1# -*- coding: utf-8 -*- #
2# Copyright 2017 Google LLC. All Rights Reserved.
3#
4# Licensed under the Apache License, Version 2.0 (the "License");
5# you may not use this file except in compliance with the License.
6# You may obtain a copy of the License at
7#
8#    http://www.apache.org/licenses/LICENSE-2.0
9#
10# Unless required by applicable law or agreed to in writing, software
11# distributed under the License is distributed on an "AS IS" BASIS,
12# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13# See the License for the specific language governing permissions and
14# limitations under the License.
15"""Flags and helpers for the compute interconnects commands."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import unicode_literals
20
21import collections
22
23from googlecloudsdk.calliope import arg_parsers
24from googlecloudsdk.calliope import base
25from googlecloudsdk.command_lib.compute import completers as compute_completers
26from googlecloudsdk.command_lib.compute import flags as compute_flags
27
28_BANDWIDTH_CHOICES = collections.OrderedDict([
29    ('50m', '50 Mbit/s'),
30    ('100m', '100 Mbit/s'),
31    ('200m', '200 Mbit/s'),
32    ('300m', '300 Mbit/s'),
33    ('400m', '400 Mbit/s'),
34    ('500m', '500 Mbit/s'),
35    ('1g', '1 Gbit/s'),
36    ('2g', '2 Gbit/s'),
37    ('5g', '5 Gbit/s'),
38    ('10g', '10 Gbit/s'),
39    ('20g', '20 Gbit/s'),
40    ('50g', '50 Gbit/s'),
41])
42
43_EDGE_AVAILABILITY_DOMAIN_CHOICES = {
44    'availability-domain-1': 'Edge Availability Domain 1',
45    'availability-domain-2': 'Edge Availability Domain 2',
46    'any': 'Any Availability Domain',
47}
48
49
50class InterconnectAttachmentsCompleter(compute_completers.ListCommandCompleter):
51
52  def __init__(self, **kwargs):
53    super(InterconnectAttachmentsCompleter, self).__init__(
54        collection='compute.interconnectAttachments',
55        list_command='alpha compute interconnects attachments list --uri',
56        **kwargs)
57
58
59def InterconnectAttachmentArgument(required=True, plural=False):
60  return compute_flags.ResourceArgument(
61      resource_name='interconnect attachment',
62      completer=InterconnectAttachmentsCompleter,
63      plural=plural,
64      required=required,
65      regional_collection='compute.interconnectAttachments',
66      region_explanation=compute_flags.REGION_PROPERTY_EXPLANATION)
67
68
69def InterconnectAttachmentArgumentForRouter(required=False,
70                                            plural=False,
71                                            operation_type='added'):
72  resource_name = 'interconnectAttachment{0}'.format('s' if plural else '')
73  return compute_flags.ResourceArgument(
74      resource_name=resource_name,
75      name='--interconnect-attachment',
76      completer=InterconnectAttachmentsCompleter,
77      plural=plural,
78      required=required,
79      regional_collection='compute.interconnectAttachments',
80      short_help='The interconnect attachment of the interface being {0}.'
81      .format(operation_type),
82      region_explanation='If not specified it will be set to the region of '
83      'the router.')
84
85
86def AddAdminEnabled(parser, default_behavior=True, update=False):
87  """Adds adminEnabled flag to the argparse.ArgumentParser."""
88  group = parser.add_group(mutex=True, required=False, help='')
89  if update:
90    # Update command
91    help_text = """\
92      Administrative status of the interconnect attachment.
93      When this is enabled, the attachment is operational and will carry
94      traffic. Use --no-enable-admin to disable it.
95      """
96  elif default_behavior:
97    # Create command for dedicated attachments, backend default behavior is to
98    # enable if not specified.
99    help_text = """\
100      Administrative status of the interconnect attachment. If not provided
101      on creation, defaults to enabled.
102      When this is enabled, the attachment is operational and will carry
103      traffic. Use --no-enable-admin to disable it.
104      """
105  else:
106    # Create command for partner attachments, backend default behavior is to
107    # disabled if not specified.
108    help_text = """\
109      Administrative status of the interconnect attachment. If not provided
110      on creation, defaults to disabled.
111      When this is enabled, the attachment is operational and will carry
112      traffic. Use --no-enable-admin to disable it.
113      """
114
115  group.add_argument(
116      '--admin-enabled',
117      hidden=True,
118      default=None,
119      action='store_true',
120      help='(DEPRECATED) Use --enable-admin instead.')
121
122  group.add_argument(
123      '--enable-admin', action='store_true', default=None, help=help_text)
124
125
126def AddBandwidth(parser, required):
127  """Adds bandwidth flag to the argparse.ArgumentParser."""
128  help_text = """\
129      Provisioned capacity of the attachment.
130      """
131  choices = _BANDWIDTH_CHOICES
132
133  base.ChoiceArgument(
134      '--bandwidth',
135      # TODO(b/80311900): use arg_parsers.BinarySize()
136      choices=choices,
137      required=required,
138      help_str=help_text).AddToParser(parser)
139
140
141def AddVlan(parser):
142  """Adds vlan flag to the argparse.ArgumentParser."""
143  parser.add_argument(
144      '--vlan',
145      type=int,
146      help="""\
147      Desired VLAN for this attachment, in the range 2-4094. If not supplied,
148      Google will automatically select a VLAN.
149      """)
150
151
152def AddPartnerAsn(parser):
153  """Adds partner asn flag to the argparse.ArgumentParser."""
154  parser.add_argument(
155      '--partner-asn',
156      type=int,
157      help="""\
158      BGP ASN of the partner. This should only be supplied by layer 3
159      providers that have configured BGP on behalf of the customer.
160      """)
161
162
163def AddPartnerMetadata(parser, required=True):
164  """Adds partner metadata flags to the argparse.ArgumentParser."""
165  group = parser.add_group(
166      mutex=False, required=required, help='Partner metadata.')
167  group.add_argument(
168      '--partner-name',
169      required=required,
170      help="""\
171      Plain text name of the Partner providing this attachment. This value
172      may be validated to match approved Partner values.
173      """)
174  group.add_argument(
175      '--partner-interconnect-name',
176      required=required,
177      help="""\
178      Plain text name of the Interconnect this attachment is connected to,
179      as displayed in the Partner's portal. For instance "Chicago 1".
180      """)
181  group.add_argument(
182      '--partner-portal-url',
183      required=required,
184      help="""\
185      URL of the Partner's portal for this Attachment. The Partner may wish
186      to customize this to be a deep-link to the specific resource on the
187      Partner portal. This value may be validated to match approved Partner
188      values.
189      """)
190
191
192def AddPairingKey(parser):
193  """Adds pairing key flag to the argparse.ArgumentParser."""
194  parser.add_argument(
195      '--pairing-key',
196      required=True,
197      help="""\
198      Value of the pairing-key from the target partner attachment provided by
199      the customer.
200      """)
201
202
203def AddEdgeAvailabilityDomain(parser):
204  """Adds edge-availability-domain flag to the argparse.ArgumentParser."""
205  parser.add_argument(
206      '--edge-availability-domain',
207      choices=_EDGE_AVAILABILITY_DOMAIN_CHOICES,
208      required=True,
209      metavar='AVAILABILITY_DOMAIN',
210      help="""\
211      Desired edge availability domain for this attachment:
212      `availability-domain-1`, `availability-domain-2`, `any`.
213
214      In each metro where the Partner can connect to Google, there are two sets
215      of redundant hardware. These sets are described as edge availability
216      domain 1 and 2. Within a metro, Google will only schedule maintenance in
217      one availability domain at a time. This guarantee does not apply to
218      availability domains outside the metro; Google may perform maintenance in
219      (say) New York availability domain 1 at the same time as Chicago
220      availability domain 1.
221      """)
222
223
224def AddDescription(parser):
225  """Adds description flag to the argparse.ArgumentParser."""
226  parser.add_argument(
227      '--description',
228      help='Human-readable plain-text description of attachment.')
229
230
231def AddCandidateSubnets(parser):
232  """Adds candidate subnets flag to the argparse.ArgumetnParser."""
233  parser.add_argument(
234      '--candidate-subnets',
235      type=arg_parsers.ArgList(max_length=16),
236      metavar='SUBNET',
237      help="""\
238      Up to 16 candidate prefixes that can be used to restrict the allocation of
239      `cloudRouterIpAddress` and `customerRouterIpAddress` for this
240      attachment. All prefixes must be within link-local address space. Google
241      will attempt to select an unused /29 from the supplied candidate
242      subnet(s), or all of link-local space if no subnets supplied. Google will
243      not re-use a /29 already in-use by your project, even if it's contained in
244      one of the candidate subnets. The request will fail if all /29s within the
245      candidate subnets are in use at Google's edge.""",
246      default=[])
247
248
249def AddDryRun(parser):
250  """Adds dry-run flag to the argparse.ArgumentParser."""
251  parser.add_argument(
252      '--dry-run',
253      default=None,
254      action='store_true',
255      help='If supplied, validates the attachment without creating it.')
256
257
258def AddMtu(parser):
259  """Adds mtu flag to the argparse.ArgumentParser."""
260  parser.add_argument(
261      '--mtu',
262      type=int,
263      help="""\
264      Maximum transmission unit (MTU) is the size of the largest IP packet
265      passing through this interconnect attachment. Only 1440 and 1500 are
266      allowed values. If not specified, the value will default to 1440.
267      """)
268
269
270def GetAdminEnabledFlag(args):
271  """Determines value of admin_enabled/enable_admin flag."""
272  return args.enable_admin if args.enable_admin is not None else args.admin_enabled
273