1# -*- coding: utf-8 -*- #
2# Copyright 2019 Google Inc. 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 for gcloud active-directory commands."""
16
17from __future__ import absolute_import
18from __future__ import division
19from __future__ import unicode_literals
20
21from googlecloudsdk.api_lib.active_directory import exceptions
22from googlecloudsdk.calliope import arg_parsers
23from googlecloudsdk.calliope import base
24from googlecloudsdk.calliope.concepts import concepts
25from googlecloudsdk.command_lib.util.args import labels_util
26from googlecloudsdk.command_lib.util.concepts import concept_parsers
27
28VALID_REGIONS = [
29    'asia-east1', 'asia-northeast1', 'asia-south1', 'asia-southeast1',
30    'australia-southeast1', 'europe-north1', 'europe-west1', 'europe-west2',
31    'europe-west3', 'europe-west4', 'northamerica-northeast1',
32    'southamerica-east1', 'us-central1', 'us-east1', 'us-east4', 'us-west1',
33    'us-west2'
34]
35
36
37def GetOperationResourceSpec():
38  """Adds an operation resource spec."""
39  return concepts.ResourceSpec(
40      'managedidentities.projects.locations.global.operations',
41      resource_name='operation',
42      disable_auto_completers=False,
43      projectsId=concepts.DEFAULT_PROJECT_ATTRIBUTE_CONFIG,
44      operationsId=OperationAttributeConfig(),
45  )
46
47
48def OperationAttributeConfig():
49  """Adds an operation attribute config."""
50  return concepts.ResourceParameterAttributeConfig(
51      name='operation',
52      help_text='Name of the Managed Microsoft AD operation.',
53  )
54
55
56def AddOperationResourceArg(parser, verb, positional=True):
57  """Adds an operation resource argument.
58
59  NOTE: May be used only if it's the only resource arg in the command.
60
61  Args:
62    parser: the argparse parser for the command.
63    verb: str, the verb to describe the resource, such as 'to update'.
64    positional: bool, if True, means that the instance ID is a positional rather
65      than a flag.
66  """
67  name = 'NAME' if positional else '--operation'
68  concept_parsers.ConceptParser.ForResource(
69      name,
70      GetOperationResourceSpec(),
71      'The operation name {}.'.format(verb),
72      required=True).AddToParser(parser)
73
74
75# Flags for update domain.
76def AddRegionFlag(unused_domain_ref, args, patch_request):
77  """Adds region to domain."""
78  if args.IsSpecified('add_region'):
79    locs = patch_request.domain.locations + [args.add_region]
80    locs = sorted(set(locs))
81    patch_request.domain.locations = locs
82    AddFieldToUpdateMask('locations', patch_request)
83  return patch_request
84
85
86def RemoveRegionFlag(unused_domain_ref, args, patch_request):
87  """Removes region from domain."""
88  if args.IsSpecified('remove_region'):
89    locs = [
90        loc for loc in patch_request.domain.locations
91        if loc != args.remove_region
92    ]
93    locs = sorted(set(locs))
94    if not locs:
95      raise exceptions.ActiveDirectoryError('Cannot remove all regions')
96    patch_request.domain.locations = locs
97    AddFieldToUpdateMask('locations', patch_request)
98  return patch_request
99
100
101def AddAuthorizedNetworksFlag(unused_domain_ref, args, patch_request):
102  """Adds authorized networks to domain."""
103  if args.IsSpecified('add_authorized_networks'):
104    ans = patch_request.domain.authorizedNetworks + args.add_authorized_networks
105    ans = sorted(set(ans))
106    patch_request.domain.authorizedNetworks = ans
107    AddFieldToUpdateMask('authorized_networks', patch_request)
108  return patch_request
109
110
111def RemoveAuthorizedNetworksFlag(unused_domain_ref, args, patch_request):
112  """Removes authorized networks from domain."""
113  if args.IsSpecified('remove_authorized_networks'):
114    ans = [
115        an for an in patch_request.domain.authorizedNetworks
116        if an not in args.remove_authorized_networks
117    ]
118    ans = sorted(set(ans))
119    patch_request.domain.authorizedNetworks = ans
120    AddFieldToUpdateMask('authorized_networks', patch_request)
121  return patch_request
122
123
124def UpdateAuditLogsEnabled(unused_domain_ref, args, patch_request):
125  """Updates audit logs config for the domain."""
126  if args.IsSpecified('enable_audit_logs'):
127    patch_request.domain.auditLogsEnabled = args.enable_audit_logs
128    AddFieldToUpdateMask('audit_logs_enabled', patch_request)
129  return patch_request
130
131
132def AddFieldToUpdateMask(field, patch_request):
133  """Adds name of field to update mask."""
134  update_mask = patch_request.updateMask
135  if update_mask:
136    if update_mask.count(field) == 0:
137      patch_request.updateMask = update_mask + ',' + field
138  else:
139    patch_request.updateMask = field
140  return patch_request
141
142
143def AdditionalDomainUpdateArguments():
144  """Adds all update domain arguments."""
145  return DomainUpdateLabelsFlags() + [RegionUpdateFlags(), AuthNetUpdateFlags()]
146
147
148def RegionUpdateFlags():
149  """Defines flags for updating regions."""
150  region_group = base.ArgumentGroup(mutex=True)
151  region_group.AddArgument(DomainAddRegionFlag())
152  region_group.AddArgument(DomainRemoveRegionFlag())
153  return region_group
154
155
156def AuthNetUpdateFlags():
157  """Defines flags for updating authorized networks."""
158  auth_net_group = base.ArgumentGroup(mutex=True)
159  auth_net_group.AddArgument(DomainAddAuthorizedNetworksFlag())
160  auth_net_group.AddArgument(DomainRemoveAuthorizedNetworksFlag())
161  return auth_net_group
162
163
164def DomainUpdateLabelsFlags():
165  """Defines flags for updating labels."""
166  remove_group = base.ArgumentGroup(mutex=True)
167  remove_group.AddArgument(labels_util.GetClearLabelsFlag())
168  remove_group.AddArgument(labels_util.GetRemoveLabelsFlag(''))
169  return [labels_util.GetUpdateLabelsFlag(''), remove_group]
170
171
172def RegionsType(value):
173  """Defines valid GCP regions."""
174  return arg_parsers.ArgList(choices=VALID_REGIONS)(value)
175
176
177def DomainAddRegionFlag():
178  """Defines a flag for adding a region."""
179  return base.Argument(
180      '--add-region',
181      help="""\
182      An additional region to provision this domain in.
183      If domain is already provisioned in region, nothing will be done in that
184      region. Supported regions are: {}.
185      """.format(', '.join(VALID_REGIONS)))
186
187
188def DomainRemoveRegionFlag():
189  """Defines a flag for removing a region."""
190  return base.Argument(
191      '--remove-region',
192      help="""\
193      A region to de-provision this domain from.
194      If domain is already not provisioned in a region, nothing will be done in
195      that region. Domains must be left provisioned in at least one region.
196      Supported regions are: {}.
197      """.format(', '.join(VALID_REGIONS)))
198
199
200def DomainAddAuthorizedNetworksFlag():
201  """Defines a flag for adding an authorized network."""
202  return base.Argument(
203      '--add-authorized-networks',
204      metavar='AUTH_NET1, AUTH_NET2, ...',
205      type=arg_parsers.ArgList(),
206      action=arg_parsers.UpdateAction,
207      help="""\
208       A list of URLs of additional networks to peer this domain to in the form
209       projects/{project}/global/networks/{network}.
210       Networks must belong to the project.
211      """)
212
213
214def DomainRemoveAuthorizedNetworksFlag():
215  """Defines a flag for removing an authorized network."""
216  return base.Argument(
217      '--remove-authorized-networks',
218      metavar='AUTH_NET1, AUTH_NET2, ...',
219      type=arg_parsers.ArgList(),
220      action=arg_parsers.UpdateAction,
221      help="""\
222       A list of URLs of additional networks to unpeer this domain from in the
223       form projects/{project}/global/networks/{network}.
224       Networks must belong to the project.
225      """)
226