1054 lines
30 KiB
Python
1054 lines
30 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.
|
|
"""Annotates the resource types with extra information."""
|
|
|
|
from __future__ import absolute_import
|
|
from __future__ import division
|
|
from __future__ import unicode_literals
|
|
|
|
import collections
|
|
|
|
from apitools.base.protorpclite import messages
|
|
|
|
from googlecloudsdk.api_lib.compute import instance_utils
|
|
from googlecloudsdk.api_lib.compute import path_simplifier
|
|
from googlecloudsdk.api_lib.compute import property_selector
|
|
import six
|
|
import six.moves.http_client
|
|
|
|
|
|
def _FirewallRulesToCell(firewall):
|
|
"""Returns a compact string describing the firewall rules."""
|
|
rules = []
|
|
for allowed in firewall.get('allowed', []):
|
|
protocol = allowed.get('IPProtocol')
|
|
if not protocol:
|
|
continue
|
|
|
|
port_ranges = allowed.get('ports')
|
|
if port_ranges:
|
|
for port_range in port_ranges:
|
|
rules.append('{0}:{1}'.format(protocol, port_range))
|
|
else:
|
|
rules.append(protocol)
|
|
|
|
return ','.join(rules)
|
|
|
|
|
|
def _TargetPoolHealthChecksToCell(target_pool):
|
|
"""Comma-joins the names of health checks of the given target pool."""
|
|
return ','.join(path_simplifier.Name(check) for check in
|
|
target_pool.get('healthChecks', []))
|
|
|
|
|
|
def _FirewallSourceRangesToCell(firewall):
|
|
"""Comma-joins the source ranges of the given firewall rule."""
|
|
return ','.join(firewall.get('sourceRanges', []))
|
|
|
|
|
|
def _FirewallSourceTagsToCell(firewall):
|
|
"""Comma-joins the source tags of the given firewall rule."""
|
|
return ','.join(firewall.get('sourceTags', []))
|
|
|
|
|
|
def _FirewallTargetTagsToCell(firewall):
|
|
"""Comma-joins the target tags of the given firewall rule."""
|
|
return ','.join(firewall.get('targetTags', []))
|
|
|
|
|
|
def _ForwardingRuleTarget(forwarding_rule):
|
|
"""Gets the API-level target or backend-service of the given rule."""
|
|
backend_service = forwarding_rule.get('backendService', None)
|
|
if backend_service is not None:
|
|
return backend_service
|
|
else:
|
|
return forwarding_rule.get('target', None)
|
|
|
|
|
|
def _StatusToCell(zone_or_region):
|
|
"""Returns status of a machine with deprecation information if applicable."""
|
|
deprecated = zone_or_region.get('deprecated', '')
|
|
if deprecated:
|
|
return '{0} ({1})'.format(zone_or_region.get('status'),
|
|
deprecated.get('state'))
|
|
else:
|
|
return zone_or_region.get('status')
|
|
|
|
|
|
def _DeprecatedDateTimeToCell(zone_or_region):
|
|
"""Returns the turndown timestamp of a deprecated machine or ''."""
|
|
deprecated = zone_or_region.get('deprecated', '')
|
|
if deprecated:
|
|
return deprecated.get('deleted')
|
|
else:
|
|
return ''
|
|
|
|
|
|
def _QuotaToCell(metric, is_integer=True):
|
|
"""Returns a function that can format the given quota as usage/limit."""
|
|
|
|
def QuotaToCell(region):
|
|
"""Formats the metric from the parent function."""
|
|
for quota in region.get('quotas', []):
|
|
if quota.get('metric') != metric:
|
|
continue
|
|
|
|
if is_integer:
|
|
return '{0:6}/{1}'.format(
|
|
int(quota.get('usage')),
|
|
int(quota.get('limit')))
|
|
else:
|
|
return '{0:7.2f}/{1:.2f}'.format(
|
|
quota.get('usage'),
|
|
quota.get('limit'))
|
|
|
|
return ''
|
|
|
|
return QuotaToCell
|
|
|
|
|
|
def _LocationName(instance_group):
|
|
"""Returns a location name, could be region name or zone name."""
|
|
if 'zone' in instance_group:
|
|
return path_simplifier.Name(instance_group['zone'])
|
|
elif 'region' in instance_group:
|
|
return path_simplifier.Name(instance_group['region'])
|
|
else:
|
|
return None
|
|
|
|
|
|
def _LocationScopeType(instance_group):
|
|
"""Returns a location scope type, could be region or zone."""
|
|
if 'zone' in instance_group:
|
|
return 'zone'
|
|
elif 'region' in instance_group:
|
|
return 'region'
|
|
else:
|
|
return None
|
|
|
|
|
|
def _MachineTypeMemoryToCell(machine_type):
|
|
"""Returns the memory of the given machine type in GB."""
|
|
memory = machine_type.get('memoryMb')
|
|
if memory:
|
|
return '{0:5.2f}'.format(float(memory) / 2**10)
|
|
else:
|
|
return ''
|
|
|
|
|
|
def _FormatCustomMachineTypeName(mt):
|
|
"""Checks for custom machine type and modifies output.
|
|
|
|
Args:
|
|
mt: machine type to be formatted
|
|
|
|
Returns:
|
|
If mt was a custom type, then it will be formatted into the desired custom
|
|
machine type output. Otherwise, it is returned unchanged.
|
|
|
|
Helper function for _MachineTypeNameToCell
|
|
"""
|
|
custom_family, custom_cpu, custom_ram = \
|
|
instance_utils.GetCpuRamVmFamilyFromCustomName(mt)
|
|
if custom_cpu and custom_ram and custom_family:
|
|
# Restricting output to 2 decimal places
|
|
custom_ram_gb = '{0:.2f}'.format(custom_ram / (2**10))
|
|
mt = 'custom ({0}, {1} vCPU, {2} GiB)'.format(custom_family, custom_cpu,
|
|
custom_ram_gb)
|
|
return mt
|
|
|
|
|
|
def _MachineTypeNameToCell(machine_type):
|
|
"""Returns the formatted name of the given machine type.
|
|
|
|
Most machine types will be untouched, with the exception of the custom machine
|
|
type. This modifies the 'custom-N-M' custom machine types with
|
|
'custom (N vCPU, M GiB)'.
|
|
|
|
For example, given the following custom machine_type:
|
|
|
|
custom-2-3500
|
|
|
|
This function will return:
|
|
|
|
custom (2 vCPU, 3.41 GiB)
|
|
|
|
in the MACHINE_TYPE field when listing out the current instances.
|
|
|
|
Args:
|
|
machine_type: The machine type of the given instance
|
|
|
|
Returns:
|
|
A formatted version of the given custom machine type (as shown in example
|
|
in docstring above).
|
|
"""
|
|
mt = machine_type.get('properties', machine_type).get('machineType')
|
|
if mt:
|
|
return _FormatCustomMachineTypeName(mt)
|
|
return mt
|
|
|
|
|
|
def FormatDescribeMachineTypeName(resources, com_path):
|
|
"""Formats a custom machine type when 'instances describe' is called.
|
|
|
|
Args:
|
|
resources: dict of resources available for the instance in question
|
|
com_path: command path of the calling command
|
|
|
|
Returns:
|
|
If input is a custom type, returns the formatted custom machine type.
|
|
Otherwise, returns None.
|
|
"""
|
|
if ('instances' in com_path) and ('describe' in com_path):
|
|
if not resources:
|
|
return None
|
|
if 'machineType' not in resources:
|
|
return None
|
|
mt_splitlist = resources['machineType'].split('/')
|
|
mt = mt_splitlist[-1]
|
|
if 'custom' not in mt:
|
|
return None
|
|
formatted_mt = _FormatCustomMachineTypeName(mt)
|
|
mt_splitlist[-1] = formatted_mt
|
|
return '/'.join(mt_splitlist)
|
|
else:
|
|
return None
|
|
|
|
|
|
def _OperationHttpStatusToCell(operation):
|
|
"""Returns the HTTP response code of the given operation."""
|
|
if operation.get('status') == 'DONE':
|
|
return operation.get('httpErrorStatusCode') or six.moves.http_client.OK
|
|
else:
|
|
return ''
|
|
|
|
|
|
def _ProjectToCell(resource):
|
|
"""Returns the project name of the given resource."""
|
|
self_link = resource.get('selfLink')
|
|
if self_link:
|
|
return path_simplifier.ProjectSuffix(self_link).split('/')[0]
|
|
else:
|
|
return ''
|
|
|
|
|
|
def _MembersToCell(group):
|
|
members = group.get('members')
|
|
if members:
|
|
return len(members)
|
|
# Must be '0' instead of 0 to pass comparison 0 or ''.
|
|
return '0'
|
|
|
|
|
|
def _BackendsToCell(backend_service):
|
|
"""Comma-joins the names of the backend services."""
|
|
return ','.join(backend.get('group')
|
|
for backend in backend_service.get('backends', []))
|
|
|
|
|
|
def _RoutesNextHopToCell(route):
|
|
"""Returns the next hop value in a compact form."""
|
|
if route.get('nextHopInstance'):
|
|
return path_simplifier.ScopedSuffix(route.get('nextHopInstance'))
|
|
elif route.get('nextHopGateway'):
|
|
return path_simplifier.ScopedSuffix(route.get('nextHopGateway'))
|
|
elif route.get('nextHopIp'):
|
|
return route.get('nextHopIp')
|
|
elif route.get('nextHopVpnTunnel'):
|
|
return path_simplifier.ScopedSuffix(route.get('nextHopVpnTunnel'))
|
|
elif route.get('nextHopPeering'):
|
|
return route.get('nextHopPeering')
|
|
else:
|
|
return ''
|
|
|
|
|
|
def _TargetProxySslCertificatesToCell(target_proxy):
|
|
"""Joins the names of ssl certificates of the given HTTPS or SSL proxy."""
|
|
return ','.join(path_simplifier.Name(cert) for cert in
|
|
target_proxy.get('sslCertificates', []))
|
|
|
|
|
|
def _ProtobufDefinitionToFields(message_class):
|
|
"""Flattens the fields in a protocol buffer definition.
|
|
|
|
For example, given the following definition:
|
|
|
|
message Point {
|
|
required int32 x = 1;
|
|
required int32 y = 2;
|
|
optional string label = 3;
|
|
}
|
|
|
|
message Polyline {
|
|
repeated Point point = 1;
|
|
optional string label = 2;
|
|
}
|
|
|
|
a call to this function with the Polyline class would produce:
|
|
|
|
['label',
|
|
'point[].label',
|
|
'point[].x',
|
|
'point[].y']
|
|
|
|
Args:
|
|
message_class: A class that inherits from protorpc.self.messages.Message
|
|
and defines a protocol buffer.
|
|
|
|
Yields:
|
|
The flattened fields, in non-decreasing order.
|
|
"""
|
|
for field in sorted(message_class.all_fields(), key=lambda field: field.name):
|
|
if isinstance(field, messages.MessageField):
|
|
for remainder in _ProtobufDefinitionToFields(field.type):
|
|
if field.repeated:
|
|
yield field.name + '[].' + remainder
|
|
else:
|
|
yield field.name + '.' + remainder
|
|
else:
|
|
if field.repeated:
|
|
yield field.name + '[]'
|
|
else:
|
|
yield field.name
|
|
|
|
|
|
_InternalSpec = collections.namedtuple(
|
|
'Spec',
|
|
['message_class_name', 'table_cols', 'transformations', 'editables'])
|
|
|
|
_SPECS_V1 = {
|
|
'addresses': _InternalSpec(
|
|
message_class_name='Address',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('REGION', 'region'),
|
|
('ADDRESS', 'address'),
|
|
('STATUS', 'status'),
|
|
],
|
|
transformations=[
|
|
('region', path_simplifier.Name),
|
|
('users[]', path_simplifier.ScopedSuffix),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'autoscalers': _InternalSpec(
|
|
message_class_name='Autoscaler',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('TARGET', 'target'),
|
|
('POLICY', 'autoscalingPolicy'),
|
|
],
|
|
transformations=[
|
|
('zone', path_simplifier.Name),
|
|
('target', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'backendBuckets': _InternalSpec(
|
|
message_class_name='BackendBucket',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('GCS_BUCKET_NAME', 'bucketName'),
|
|
('ENABLE_CDN', 'enableCdn')
|
|
],
|
|
transformations=[
|
|
('enableCdn', lambda x: str(x).lower()),
|
|
],
|
|
editables=[
|
|
'bucketName'
|
|
'description',
|
|
'enableCdn',
|
|
]),
|
|
|
|
'backendServices': _InternalSpec(
|
|
message_class_name='BackendService',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('BACKENDS', _BackendsToCell),
|
|
('PROTOCOL', 'protocol'),
|
|
],
|
|
transformations=[
|
|
('backends[].group', path_simplifier.ScopedSuffix),
|
|
],
|
|
editables=[
|
|
'backends',
|
|
'description',
|
|
'enableCDN',
|
|
'healthChecks',
|
|
'iap.enabled',
|
|
'iap.oauth2ClientId',
|
|
'iap.oauth2ClientSecret',
|
|
'port',
|
|
'portName',
|
|
'protocol',
|
|
'timeoutSec',
|
|
],
|
|
),
|
|
|
|
'backendServiceGroupHealth': _InternalSpec(
|
|
message_class_name='BackendServiceGroupHealth',
|
|
table_cols=[
|
|
],
|
|
transformations=[
|
|
('healthStatus[].instance', path_simplifier.ScopedSuffix),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'disks': _InternalSpec(
|
|
message_class_name='Disk',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('ZONE', 'zone'),
|
|
('SIZE_GB', 'sizeGb'),
|
|
('TYPE', 'type'),
|
|
('STATUS', 'status'),
|
|
],
|
|
transformations=[
|
|
('sourceSnapshot', path_simplifier.Name),
|
|
('type', path_simplifier.Name),
|
|
('zone', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'diskTypes': _InternalSpec(
|
|
message_class_name='DiskType',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('ZONE', 'zone'),
|
|
('VALID_DISK_SIZES', 'validDiskSize'),
|
|
],
|
|
transformations=[
|
|
('zone', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'firewalls': _InternalSpec(
|
|
message_class_name='Firewall',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('NETWORK', 'network'),
|
|
('SRC_RANGES', _FirewallSourceRangesToCell),
|
|
('RULES', _FirewallRulesToCell),
|
|
('SRC_TAGS', _FirewallSourceTagsToCell),
|
|
('TARGET_TAGS', _FirewallTargetTagsToCell),
|
|
],
|
|
transformations=[
|
|
('network', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'forwardingRules': _InternalSpec(
|
|
message_class_name='ForwardingRule',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('REGION', 'region'),
|
|
('IP_ADDRESS', 'IPAddress'),
|
|
('IP_PROTOCOL', 'IPProtocol'),
|
|
('TARGET', _ForwardingRuleTarget),
|
|
],
|
|
transformations=[
|
|
('region', path_simplifier.Name),
|
|
('target', path_simplifier.ScopedSuffix),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'groups': _InternalSpec(
|
|
message_class_name='Group',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('NUM_MEMBERS', _MembersToCell),
|
|
('DESCRIPTION', 'description'),
|
|
],
|
|
transformations=[],
|
|
editables=[],
|
|
),
|
|
|
|
'healthChecks': _InternalSpec(
|
|
message_class_name='HealthCheck',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('PROTOCOL', 'type'),
|
|
],
|
|
transformations=[],
|
|
editables=None,
|
|
),
|
|
|
|
'httpHealthChecks': _InternalSpec(
|
|
message_class_name='HttpHealthCheck',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('HOST', 'host'),
|
|
('PORT', 'port'),
|
|
('REQUEST_PATH', 'requestPath'),
|
|
],
|
|
transformations=[
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'httpsHealthChecks': _InternalSpec(
|
|
message_class_name='HttpsHealthCheck',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('HOST', 'host'),
|
|
('PORT', 'port'),
|
|
('REQUEST_PATH', 'requestPath'),
|
|
],
|
|
transformations=[
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'iap': _InternalSpec(
|
|
message_class_name='BackendServiceIAP',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('ENABLED', 'enabled'),
|
|
('OAUTH2_CLIENT_ID', 'oauth2ClientId'),
|
|
('OAUTH2_CLIENT_SECRET', 'oauth2ClientSecret'),
|
|
('OAUTH2_CLIENT_SECRET_SHA256', 'oauth2ClientSecretSha256'),
|
|
],
|
|
transformations=[],
|
|
editables=None,
|
|
),
|
|
|
|
'images': _InternalSpec(
|
|
message_class_name='Image',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('PROJECT', _ProjectToCell),
|
|
('FAMILY', 'family'),
|
|
('DEPRECATED', 'deprecated.state'),
|
|
('STATUS', 'status'),
|
|
],
|
|
transformations=[],
|
|
editables=None,
|
|
),
|
|
|
|
'instanceGroups': _InternalSpec(
|
|
message_class_name='InstanceGroup',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('ZONE', 'zone'),
|
|
('NETWORK', 'network'),
|
|
('MANAGED', 'isManaged'),
|
|
('INSTANCES', 'size'),
|
|
],
|
|
transformations=[
|
|
('zone', path_simplifier.Name),
|
|
('size', str),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'instanceGroupManagers': _InternalSpec(
|
|
message_class_name='InstanceGroupManager',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('ZONE', 'zone'),
|
|
('BASE_INSTANCE_NAME', 'baseInstanceName'),
|
|
('SIZE', 'size'),
|
|
('TARGET_SIZE', 'targetSize'),
|
|
('INSTANCE_TEMPLATE', 'instanceTemplate'),
|
|
('AUTOSCALED', 'autoscaled'),
|
|
],
|
|
transformations=[
|
|
('zone', path_simplifier.Name),
|
|
('instanceGroup', path_simplifier.Name),
|
|
('instanceTemplate', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'instances': _InternalSpec(
|
|
message_class_name='Instance',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('ZONE', 'zone'),
|
|
('MACHINE_TYPE', _MachineTypeNameToCell),
|
|
('PREEMPTIBLE', 'scheduling.preemptible'),
|
|
('INTERNAL_IP', 'networkInterfaces[].networkIP.notnull().list()'),
|
|
('EXTERNAL_IP',
|
|
'networkInterfaces[].accessConfigs[0].natIP.notnull().list()'),
|
|
('STATUS', 'status'),
|
|
],
|
|
transformations=[
|
|
('disks[].source', path_simplifier.Name),
|
|
('machineType', path_simplifier.Name),
|
|
('networkInterfaces[].network', path_simplifier.Name),
|
|
('zone', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'instanceTemplates': _InternalSpec(
|
|
message_class_name='InstanceTemplate',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('MACHINE_TYPE', _MachineTypeNameToCell),
|
|
('PREEMPTIBLE', 'properties.scheduling.preemptible'),
|
|
('CREATION_TIMESTAMP', 'creationTimestamp'),
|
|
],
|
|
transformations=[],
|
|
editables=None,
|
|
),
|
|
|
|
'machineTypes': _InternalSpec(
|
|
message_class_name='MachineType',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('ZONE', 'zone'),
|
|
('CPUS', 'guestCpus'),
|
|
('MEMORY_GB', _MachineTypeMemoryToCell),
|
|
('DEPRECATED', 'deprecated.state'),
|
|
],
|
|
transformations=[
|
|
('zone', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'networks': _InternalSpec(
|
|
message_class_name='Network',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('MODE', 'x_gcloud_mode'),
|
|
('IPV4_RANGE', 'IPv4Range'),
|
|
('GATEWAY_IPV4', 'gatewayIPv4'),
|
|
],
|
|
transformations=[],
|
|
editables=None,
|
|
),
|
|
|
|
'projects': _InternalSpec(
|
|
message_class_name='Project',
|
|
table_cols=[], # We do not support listing projects since
|
|
# there is only one project (and there is no
|
|
# API support).
|
|
transformations=[
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'operations': _InternalSpec(
|
|
message_class_name='Operation',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('TYPE', 'operationType'),
|
|
('TARGET', 'targetLink'),
|
|
('HTTP_STATUS', _OperationHttpStatusToCell),
|
|
('STATUS', 'status'),
|
|
('TIMESTAMP', 'insertTime'),
|
|
],
|
|
transformations=[
|
|
('targetLink', path_simplifier.ScopedSuffix),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'invalidations': _InternalSpec(
|
|
message_class_name='Operation',
|
|
table_cols=[
|
|
('DESCRIPTION', 'description'),
|
|
('HTTP_STATUS', _OperationHttpStatusToCell),
|
|
('STATUS', 'status'),
|
|
('TIMESTAMP', 'insertTime'),
|
|
],
|
|
transformations=[
|
|
('targetLink', path_simplifier.ScopedSuffix),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'regionBackendServices': _InternalSpec(
|
|
message_class_name='BackendService',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('BACKENDS', _BackendsToCell),
|
|
('PROTOCOL', 'protocol'),
|
|
],
|
|
transformations=[
|
|
('backends[].group', path_simplifier.ScopedSuffix),
|
|
],
|
|
editables=[
|
|
'backends',
|
|
'description',
|
|
'enableCDN',
|
|
'healthChecks',
|
|
'port',
|
|
'portName',
|
|
'protocol',
|
|
'timeoutSec',
|
|
],
|
|
),
|
|
|
|
'regions': _InternalSpec(
|
|
message_class_name='Region',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('CPUS', _QuotaToCell('CPUS', is_integer=False)),
|
|
('DISKS_GB', _QuotaToCell('DISKS_TOTAL_GB', is_integer=True)),
|
|
('ADDRESSES', _QuotaToCell('IN_USE_ADDRESSES', is_integer=True)),
|
|
('RESERVED_ADDRESSES',
|
|
_QuotaToCell('STATIC_ADDRESSES', is_integer=True)),
|
|
('STATUS', _StatusToCell),
|
|
('TURNDOWN_DATE', _DeprecatedDateTimeToCell),
|
|
],
|
|
transformations=[
|
|
('zones[]', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'routes': _InternalSpec(
|
|
message_class_name='Route',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('NETWORK', 'network'),
|
|
('DEST_RANGE', 'destRange'),
|
|
('NEXT_HOP', _RoutesNextHopToCell),
|
|
('PRIORITY', 'priority'),
|
|
],
|
|
transformations=[
|
|
('network', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'snapshots': _InternalSpec(
|
|
message_class_name='Snapshot',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('DISK_SIZE_GB', 'diskSizeGb'),
|
|
('SRC_DISK', 'sourceDisk'),
|
|
('STATUS', 'status'),
|
|
],
|
|
transformations=[
|
|
('sourceDisk', path_simplifier.ScopedSuffix),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'sslCertificates': _InternalSpec(
|
|
message_class_name='Network',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('CREATION_TIMESTAMP', 'creationTimestamp'),
|
|
],
|
|
transformations=[],
|
|
editables=None,
|
|
),
|
|
|
|
'subnetworks': _InternalSpec(
|
|
message_class_name='Subnetwork',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('REGION', 'region'),
|
|
('NETWORK', 'network'),
|
|
('RANGE', 'ipCidrRange')
|
|
],
|
|
transformations=[
|
|
('network', path_simplifier.Name),
|
|
('region', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'targetHttpProxies': _InternalSpec(
|
|
message_class_name='TargetHttpProxy',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('URL_MAP', 'urlMap'),
|
|
],
|
|
transformations=[
|
|
('urlMap', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'targetHttpsProxies': _InternalSpec(
|
|
message_class_name='TargetHttpsProxy',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('SSL_CERTIFICATES', _TargetProxySslCertificatesToCell),
|
|
('URL_MAP', 'urlMap'),
|
|
],
|
|
transformations=[
|
|
('sslCertificates[]', path_simplifier.Name),
|
|
('urlMap', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'targetSslProxies': _InternalSpec(
|
|
message_class_name='TargetSslProxy',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('PROXY_HEADER', 'proxyHeader'),
|
|
('SERVICE', 'service'),
|
|
('SSL_CERTIFICATES', _TargetProxySslCertificatesToCell)
|
|
],
|
|
transformations=[
|
|
('sslCertificates[]', path_simplifier.Name),
|
|
('service', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'targetInstances': _InternalSpec(
|
|
message_class_name='TargetInstance',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('ZONE', 'zone'),
|
|
('INSTANCE', 'instance'),
|
|
('NAT_POLICY', 'natPolicy'),
|
|
],
|
|
transformations=[
|
|
('instance', path_simplifier.Name),
|
|
('zone', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'targetPoolInstanceHealth': _InternalSpec(
|
|
message_class_name='TargetPoolInstanceHealth',
|
|
table_cols=[
|
|
],
|
|
transformations=[
|
|
('healthStatus[].instance', path_simplifier.ScopedSuffix),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'targetPools': _InternalSpec(
|
|
message_class_name='TargetPool',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('REGION', 'region'),
|
|
('SESSION_AFFINITY', 'sessionAffinity'),
|
|
('BACKUP', 'backupPool'),
|
|
('HEALTH_CHECKS', _TargetPoolHealthChecksToCell),
|
|
],
|
|
transformations=[
|
|
('backupPool', path_simplifier.Name),
|
|
('healthChecks[]', path_simplifier.Name),
|
|
('instances[]', path_simplifier.ScopedSuffix),
|
|
('region', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'targetVpnGateways': _InternalSpec(
|
|
message_class_name='TargetVpnGateway',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('NETWORK', 'network'),
|
|
('REGION', 'region')
|
|
],
|
|
transformations=[
|
|
('network', path_simplifier.Name),
|
|
('region', path_simplifier.Name)],
|
|
editables=None
|
|
),
|
|
|
|
'users': _InternalSpec(
|
|
message_class_name='User',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('OWNER', 'owner'),
|
|
('DESCRIPTION', 'description'),
|
|
],
|
|
transformations=[],
|
|
editables=[],
|
|
),
|
|
|
|
'zones': _InternalSpec(
|
|
message_class_name='Zone',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('REGION', 'region'),
|
|
('STATUS', _StatusToCell),
|
|
('TURNDOWN_DATE', _DeprecatedDateTimeToCell),
|
|
],
|
|
transformations=[
|
|
('region', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
|
|
'vpnTunnels': _InternalSpec(
|
|
message_class_name='VpnTunnel',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('REGION', 'region'),
|
|
('GATEWAY', 'targetVpnGateway'),
|
|
('PEER_ADDRESS', 'peerIp')
|
|
],
|
|
transformations=[
|
|
('region', path_simplifier.Name),
|
|
('targetVpnGateway', path_simplifier.Name)],
|
|
editables=None
|
|
),
|
|
|
|
'routers': _InternalSpec(
|
|
message_class_name='Router',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('REGION', 'region'),
|
|
('NETWORK', 'network'),
|
|
],
|
|
transformations=[
|
|
('network', path_simplifier.Name),
|
|
('region', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
),
|
|
}
|
|
|
|
|
|
_SPECS_BETA = _SPECS_V1.copy()
|
|
_SPECS_BETA['backendServices'] = _InternalSpec(
|
|
message_class_name='BackendService',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('BACKENDS', _BackendsToCell),
|
|
('PROTOCOL', 'protocol'),
|
|
],
|
|
transformations=[
|
|
('backends[].group', path_simplifier.ScopedSuffix),
|
|
],
|
|
editables=[
|
|
'backends',
|
|
'description',
|
|
'enableCDN',
|
|
'sessionAffinity',
|
|
'affinityCookieTTL',
|
|
'healthChecks',
|
|
'iap.enabled',
|
|
'iap.oauth2ClientId',
|
|
'iap.oauth2ClientSecret',
|
|
'port',
|
|
'portName',
|
|
'protocol',
|
|
'timeoutSec',
|
|
],)
|
|
_SPECS_BETA['commitments'] = _InternalSpec(
|
|
message_class_name='Commitment',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('ENDS', 'endTimestamp'),
|
|
('REGION', 'region'),
|
|
('STATUS', 'status'),
|
|
],
|
|
transformations=[],
|
|
editables=[])
|
|
|
|
|
|
_SPECS_ALPHA = _SPECS_BETA.copy()
|
|
|
|
_SPECS_ALPHA['instanceGroups'] = _InternalSpec(
|
|
message_class_name='InstanceGroup',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('LOCATION', _LocationName),
|
|
('SCOPE', _LocationScopeType),
|
|
('NETWORK', 'network'),
|
|
('MANAGED', 'isManaged'),
|
|
('INSTANCES', 'size'),
|
|
],
|
|
transformations=[
|
|
('size', str),
|
|
],
|
|
editables=None,
|
|
)
|
|
_SPECS_ALPHA['instanceGroupManagers'] = _InternalSpec(
|
|
message_class_name='InstanceGroupManager',
|
|
table_cols=[
|
|
('NAME', 'name'),
|
|
('LOCATION', _LocationName),
|
|
('SCOPE', _LocationScopeType),
|
|
('BASE_INSTANCE_NAME', 'baseInstanceName'),
|
|
('SIZE', 'size'),
|
|
('TARGET_SIZE', 'targetSize'),
|
|
('INSTANCE_TEMPLATE', 'instanceTemplate'),
|
|
('AUTOSCALED', 'autoscaled'),
|
|
],
|
|
transformations=[
|
|
('instanceGroup', path_simplifier.Name),
|
|
('instanceTemplate', path_simplifier.Name),
|
|
],
|
|
editables=None,
|
|
)
|
|
|
|
|
|
def _GetSpecsForVersion(api_version):
|
|
"""Get Specs for the given API version.
|
|
|
|
This currently always returns _SPECS_V1, but is left here for the future,
|
|
as a pattern for providing different specs for different versions.
|
|
|
|
Args:
|
|
api_version: A string identifying the API version, e.g. 'v1'.
|
|
|
|
Returns:
|
|
A map associating each message class name with an _InternalSpec object.
|
|
"""
|
|
if api_version == 'v1' or api_version == 'v2beta1':
|
|
return _SPECS_V1
|
|
if 'alpha' in api_version:
|
|
return _SPECS_ALPHA
|
|
return _SPECS_BETA
|
|
|
|
|
|
Spec = collections.namedtuple(
|
|
'Spec',
|
|
['message_class', 'fields', 'table_cols', 'transformations', 'editables'])
|
|
|
|
|
|
def GetSpec(resource_type, message_classes, api_version):
|
|
"""Returns a Spec for the given resource type."""
|
|
spec = _GetSpecsForVersion(api_version)
|
|
|
|
if resource_type not in spec:
|
|
raise KeyError('"%s" not found in Specs for version "%s"' %
|
|
(resource_type, api_version))
|
|
|
|
spec = spec[resource_type]
|
|
|
|
table_cols = []
|
|
for name, action in spec.table_cols:
|
|
if isinstance(action, six.string_types):
|
|
table_cols.append((name, property_selector.PropertyGetter(action)))
|
|
elif callable(action):
|
|
table_cols.append((name, action))
|
|
else:
|
|
raise ValueError('expected function or property in table_cols list: {0}'
|
|
.format(spec))
|
|
|
|
message_class = getattr(message_classes, spec.message_class_name)
|
|
fields = list(_ProtobufDefinitionToFields(message_class))
|
|
return Spec(message_class=message_class,
|
|
fields=fields,
|
|
table_cols=table_cols,
|
|
transformations=spec.transformations,
|
|
editables=spec.editables)
|