File: //snap/google-cloud-cli/current/lib/googlecloudsdk/api_lib/compute/subnets_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 subnets subcommands."""
from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals
from googlecloudsdk.calliope import exceptions as calliope_exceptions
from googlecloudsdk.command_lib.compute.networks.subnets import flags
import six
def _CreateSecondaryRange(client, name, ip_cidr_range, reserved_internal_range):
"""Creates a subnetwork secondary range."""
if reserved_internal_range and ip_cidr_range:
return client.messages.SubnetworkSecondaryRange(
rangeName=name,
reservedInternalRange=reserved_internal_range,
ipCidrRange=ip_cidr_range)
elif reserved_internal_range:
return client.messages.SubnetworkSecondaryRange(
rangeName=name, reservedInternalRange=reserved_internal_range)
else:
return client.messages.SubnetworkSecondaryRange(
rangeName=name, ipCidrRange=ip_cidr_range)
def CreateSecondaryRanges(client, secondary_range,
secondary_range_with_reserved_internal_range):
"""Creates all secondary ranges of a subnet."""
secondary_ranges = []
range_name_to_cidr = {}
range_name_to_reserved_internal_range = {}
range_names = set()
if secondary_range:
for secondary_range in secondary_range:
for range_name, ip_cidr_range in six.iteritems(secondary_range):
range_name_to_cidr[range_name] = ip_cidr_range
range_names.add(range_name)
if secondary_range_with_reserved_internal_range:
for secondary_range in secondary_range_with_reserved_internal_range:
for range_name, internal_range in six.iteritems(secondary_range):
range_name_to_reserved_internal_range[range_name] = internal_range
range_names.add(range_name)
for range_name in sorted(range_names):
secondary_ranges.append(
_CreateSecondaryRange(
client, range_name, range_name_to_cidr.get(range_name),
range_name_to_reserved_internal_range.get(range_name)))
return secondary_ranges
def MakeSubnetworkUpdateRequest(
client,
subnet_ref,
enable_private_ip_google_access=None,
allow_cidr_routes_overlap=None,
add_secondary_ranges=None,
add_secondary_ranges_with_reserved_internal_range=None,
remove_secondary_ranges=None,
enable_flow_logs=None,
aggregation_interval=None,
flow_sampling=None,
metadata=None,
filter_expr=None,
metadata_fields=None,
set_new_purpose=None,
set_role_active=None,
drain_timeout_seconds=None,
private_ipv6_google_access_type=None,
stack_type=None,
ipv6_access_type=None,
external_ipv6_prefix=None,
internal_ipv6_prefix=None,
ip_collection=None,
):
"""Make the appropriate update request for the args.
Args:
client: GCE API client
subnet_ref: Reference to a subnetwork
enable_private_ip_google_access: Enable/disable access to Google Cloud APIs
from this subnet for instances without a public ip address.
allow_cidr_routes_overlap: Allow/Disallow this subnetwork's ranges to
conflict with existing static routes.
add_secondary_ranges: List of secondary IP ranges to add to the subnetwork
for use in IP aliasing.
add_secondary_ranges_with_reserved_internal_range: List of secondary IP
ranges that are associated with InternalRange resources.
remove_secondary_ranges: List of secondary ranges to remove from the
subnetwork.
enable_flow_logs: Enable/disable flow logging for this subnet.
aggregation_interval: The internal at which to aggregate flow logs.
flow_sampling: The sampling rate for flow logging in this subnet.
metadata: Whether metadata fields should be added reported flow logs.
filter_expr: custom CEL expression for filtering flow logs
metadata_fields: custom metadata fields to be added to flow logs
set_new_purpose: Update the purpose of the subnet.
set_role_active: Updates the role of a BACKUP subnet to ACTIVE.
drain_timeout_seconds: The maximum amount of time to drain connections from
the active subnet to the backup subnet with set_role_active=True.
private_ipv6_google_access_type: The private IPv6 google access type for the
VMs in this subnet.
stack_type: The stack type for this subnet.
ipv6_access_type: The IPv6 access type for this subnet.
external_ipv6_prefix: The IPv6 external prefix to be assigned to this
subnet.
internal_ipv6_prefix: The IPv6 internal prefix to be assigned to this
subnet. When ULA is enabled, the prefix will be ignored.
ip_collection: The IP collection that provisions BYOIP v6 addresses for this
subnet.
Returns:
response, result of sending the update request for the subnetwork
"""
convert_to_enum = lambda x: x.replace('-', '_').upper()
if enable_private_ip_google_access is not None:
google_access = (
client.messages.SubnetworksSetPrivateIpGoogleAccessRequest())
google_access.privateIpGoogleAccess = enable_private_ip_google_access
google_access_request = (
client.messages.ComputeSubnetworksSetPrivateIpGoogleAccessRequest(
project=subnet_ref.project,
region=subnet_ref.region,
subnetwork=subnet_ref.Name(),
subnetworksSetPrivateIpGoogleAccessRequest=google_access))
return client.MakeRequests([
(client.apitools_client.subnetworks, 'SetPrivateIpGoogleAccess',
google_access_request)
])
elif (add_secondary_ranges is not None or
add_secondary_ranges_with_reserved_internal_range is not None):
subnetwork = client.messages.Subnetwork()
original_subnetwork = client.MakeRequests([
(client.apitools_client.subnetworks, 'Get',
client.messages.ComputeSubnetworksGetRequest(**subnet_ref.AsDict()))
])[0]
subnetwork.secondaryIpRanges = original_subnetwork.secondaryIpRanges
subnetwork.fingerprint = original_subnetwork.fingerprint
subnetwork.secondaryIpRanges.extend(
CreateSecondaryRanges(
client, add_secondary_ranges,
add_secondary_ranges_with_reserved_internal_range))
return client.MakeRequests(
[CreateSubnetworkPatchRequest(client, subnet_ref, subnetwork)])
elif remove_secondary_ranges is not None:
subnetwork = client.messages.Subnetwork()
original_subnetwork = client.MakeRequests([
(client.apitools_client.subnetworks, 'Get',
client.messages.ComputeSubnetworksGetRequest(**subnet_ref.AsDict()))
])[0]
subnetwork.secondaryIpRanges = original_subnetwork.secondaryIpRanges
subnetwork.fingerprint = original_subnetwork.fingerprint
for name in remove_secondary_ranges[0]:
if name not in [r.rangeName for r in subnetwork.secondaryIpRanges]:
raise calliope_exceptions.UnknownArgumentException(
'remove-secondary-ranges', 'Subnetwork does not have a range {}, '
'present ranges are {}.'.format(
name, [r.rangeName for r in subnetwork.secondaryIpRanges]))
subnetwork.secondaryIpRanges = [
r for r in original_subnetwork.secondaryIpRanges
if r.rangeName not in remove_secondary_ranges[0]
]
cleared_fields = []
if not subnetwork.secondaryIpRanges:
cleared_fields.append('secondaryIpRanges')
with client.apitools_client.IncludeFields(cleared_fields):
return client.MakeRequests(
[CreateSubnetworkPatchRequest(client, subnet_ref, subnetwork)])
elif (enable_flow_logs is not None or aggregation_interval is not None or
flow_sampling is not None or metadata is not None or
filter_expr is not None or metadata_fields is not None):
subnetwork = client.messages.Subnetwork()
original_subnetwork = client.MakeRequests([
(client.apitools_client.subnetworks, 'Get',
client.messages.ComputeSubnetworksGetRequest(**subnet_ref.AsDict()))
])[0]
subnetwork.fingerprint = original_subnetwork.fingerprint
log_config = client.messages.SubnetworkLogConfig(enable=enable_flow_logs)
if aggregation_interval is not None:
log_config.aggregationInterval = flags.GetLoggingAggregationIntervalArg(
client.messages).GetEnumForChoice(aggregation_interval)
if flow_sampling is not None:
log_config.flowSampling = flow_sampling
if metadata is not None:
log_config.metadata = flags.GetLoggingMetadataArg(
client.messages).GetEnumForChoice(metadata)
if filter_expr is not None:
log_config.filterExpr = filter_expr
if metadata_fields is not None:
log_config.metadataFields = metadata_fields
subnetwork.logConfig = log_config
return client.MakeRequests(
[CreateSubnetworkPatchRequest(client, subnet_ref, subnetwork)])
elif private_ipv6_google_access_type is not None:
subnetwork = client.messages.Subnetwork()
original_subnetwork = client.MakeRequests([
(client.apitools_client.subnetworks, 'Get',
client.messages.ComputeSubnetworksGetRequest(**subnet_ref.AsDict()))
])[0]
subnetwork.fingerprint = original_subnetwork.fingerprint
subnetwork.privateIpv6GoogleAccess = (
client.messages.Subnetwork.PrivateIpv6GoogleAccessValueValuesEnum(
ConvertPrivateIpv6GoogleAccess(
convert_to_enum(private_ipv6_google_access_type))))
return client.MakeRequests(
[CreateSubnetworkPatchRequest(client, subnet_ref, subnetwork)])
elif allow_cidr_routes_overlap is not None:
subnetwork = client.messages.Subnetwork()
original_subnetwork = client.MakeRequests([(
client.apitools_client.subnetworks,
'Get',
client.messages.ComputeSubnetworksGetRequest(**subnet_ref.AsDict()),
)])[0]
subnetwork.fingerprint = original_subnetwork.fingerprint
subnetwork.allowSubnetCidrRoutesOverlap = allow_cidr_routes_overlap
return client.MakeRequests(
[CreateSubnetworkPatchRequest(client, subnet_ref, subnetwork)]
)
elif set_new_purpose is not None:
subnetwork = client.messages.Subnetwork()
original_subnetwork = client.MakeRequests([
(client.apitools_client.subnetworks, 'Get',
client.messages.ComputeSubnetworksGetRequest(**subnet_ref.AsDict()))
])[0]
subnetwork.fingerprint = original_subnetwork.fingerprint
subnetwork.purpose = client.messages.Subnetwork.PurposeValueValuesEnum(
set_new_purpose)
return client.MakeRequests(
[CreateSubnetworkPatchRequest(client, subnet_ref, subnetwork)])
elif set_role_active is not None:
subnetwork = client.messages.Subnetwork()
original_subnetwork = client.MakeRequests([
(client.apitools_client.subnetworks, 'Get',
client.messages.ComputeSubnetworksGetRequest(**subnet_ref.AsDict()))
])[0]
subnetwork.fingerprint = original_subnetwork.fingerprint
subnetwork.role = client.messages.Subnetwork.RoleValueValuesEnum.ACTIVE
patch_request = client.messages.ComputeSubnetworksPatchRequest(
project=subnet_ref.project,
subnetwork=subnet_ref.subnetwork,
region=subnet_ref.region,
subnetworkResource=subnetwork,
drainTimeoutSeconds=drain_timeout_seconds,
)
return client.MakeRequests(
[(client.apitools_client.subnetworks, 'Patch', patch_request)]
)
elif (
stack_type is not None
or ip_collection is not None
or ipv6_access_type is not None
or external_ipv6_prefix is not None
or internal_ipv6_prefix is not None
):
subnetwork = client.messages.Subnetwork()
original_subnetwork = client.MakeRequests([(
client.apitools_client.subnetworks,
'Get',
client.messages.ComputeSubnetworksGetRequest(**subnet_ref.AsDict()),
)])[0]
subnetwork.fingerprint = original_subnetwork.fingerprint
if stack_type is not None:
subnetwork.stackType = (
client.messages.Subnetwork.StackTypeValueValuesEnum(stack_type)
)
if ipv6_access_type is not None:
subnetwork.ipv6AccessType = (
client.messages.Subnetwork.Ipv6AccessTypeValueValuesEnum(
ipv6_access_type
)
)
if external_ipv6_prefix is not None:
subnetwork.externalIpv6Prefix = external_ipv6_prefix
if internal_ipv6_prefix is not None:
subnetwork.internalIpv6Prefix = internal_ipv6_prefix
if ip_collection is not None:
subnetwork.ipCollection = ip_collection
return client.MakeRequests(
[CreateSubnetworkPatchRequest(client, subnet_ref, subnetwork)]
)
return client.MakeRequests([])
def CreateSubnetworkPatchRequest(client, subnet_ref, subnetwork_resource):
patch_request = client.messages.ComputeSubnetworksPatchRequest(
project=subnet_ref.project,
subnetwork=subnet_ref.subnetwork,
region=subnet_ref.region,
subnetworkResource=subnetwork_resource)
return (client.apitools_client.subnetworks, 'Patch', patch_request)
def ConvertPrivateIpv6GoogleAccess(choice):
"""Return PrivateIpv6GoogleAccess enum defined in mixer.
Args:
choice: Enum value of PrivateIpv6GoogleAccess defined in gcloud.
"""
choices_to_enum = {
'DISABLE': 'DISABLE_GOOGLE_ACCESS',
'ENABLE_BIDIRECTIONAL_ACCESS': 'ENABLE_BIDIRECTIONAL_ACCESS_TO_GOOGLE',
'ENABLE_OUTBOUND_VM_ACCESS': 'ENABLE_OUTBOUND_VM_ACCESS_TO_GOOGLE',
}
return choices_to_enum.get(choice)