1# -*- coding: utf-8 -*- #
2# Copyright 2019 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
16"""Client for interaction with Gateway CRUD on API Gateway API."""
17
18from __future__ import absolute_import
19from __future__ import division
20from __future__ import unicode_literals
21
22import types
23
24from apitools.base.py import list_pager
25
26from googlecloudsdk.api_lib.util import apis
27from googlecloudsdk.command_lib.iam import iam_util
28
29
30def GetClientInstance(version='v1', no_http=False):
31  return apis.GetClientInstance('apigateway', version, no_http=no_http)
32
33
34def GetMessagesModule(version='v1'):
35  return apis.GetMessagesModule('apigateway', version)
36
37
38class BaseClient(object):
39  """Base for building API Clients."""
40
41  def __init__(self, client=None, message_base=None, service_name=None):
42    self.client = client or GetClientInstance()
43    self.messages = self.client.MESSAGES_MODULE
44    self.service = getattr(self.client, service_name, None)
45
46    # Define standard request types if they exist for the base message
47    self.get_request = getattr(self.messages, message_base + 'GetRequest', None)
48    self.create_request = getattr(self.messages,
49                                  message_base + 'CreateRequest',
50                                  None)
51    self.list_request = getattr(self.messages,
52                                message_base + 'ListRequest',
53                                None)
54    self.patch_request = getattr(self.messages,
55                                 message_base + 'PatchRequest',
56                                 None)
57    self.delete_request = getattr(self.messages,
58                                  message_base + 'DeleteRequest',
59                                  None)
60
61    # Define IAM request types if they exist for the base message
62    self.get_iam_policy_request = getattr(self.messages,
63                                          message_base + 'GetIamPolicyRequest',
64                                          None)
65    self.set_iam_policy_request = getattr(self.messages,
66                                          message_base + 'SetIamPolicyRequest',
67                                          None)
68
69  def DefineGet(self):
70    """Defines basic get function on an assigned class."""
71    def Get(self, object_ref):
72      """Gets an object.
73
74      Args:
75        self: The self of the class this is set on.
76        object_ref: Resource, resource reference for object to get.
77
78      Returns:
79        The object requested.
80      """
81      req = self.get_request(name=object_ref.RelativeName())
82
83      return self.service.Get(req)
84
85    # Bind the function to the method and set the attribute
86    setattr(self, 'Get', types.MethodType(Get, self))
87
88  def DefineDelete(self):
89    """Defines basic delete function on an assigned class."""
90    def Delete(self, object_ref):
91      """Deletes a given object given an object name.
92
93      Args:
94        self: The self of the class this is set on.
95        object_ref: Resource, resource reference for object to delete.
96
97      Returns:
98        Long running operation.
99      """
100      req = self.delete_request(name=object_ref.RelativeName())
101
102      return self.service.Delete(req)
103
104    # Bind the function to the method and set the attribute
105    setattr(self, 'Delete', types.MethodType(Delete, self))
106
107  def DefineList(self, field_name, is_operations=False):
108    """Defines the List functionality on the calling class.
109
110    Args:
111      field_name: The name of the field on the list response to list
112      is_operations: Operations have a slightly altered message structure, set
113                     to true in operations client
114    """
115    def List(self, parent_name, filters=None, limit=None, page_size=None,
116             sort_by=None):
117      """Lists the objects under a given parent.
118
119      Args:
120        self: the self object function will be bound to.
121        parent_name: Resource name of the parent to list under.
122        filters: Filters to be applied to results (optional).
123        limit: Limit to the number of results per page (optional).
124        page_size: the number of results per page (optional).
125        sort_by: Instructions about how to sort the results (optional).
126
127      Returns:
128        List Pager.
129      """
130      if is_operations:
131        req = self.list_request(filter=filters, name=parent_name)
132
133      else:
134        req = self.list_request(filter=filters, parent=parent_name,
135                                orderBy=sort_by)
136
137      return list_pager.YieldFromList(
138          self.service,
139          req,
140          limit=limit,
141          batch_size_attribute='pageSize',
142          batch_size=page_size,
143          field=field_name)
144
145    # Bind the function to the method and set the attribute
146    setattr(self, 'List', types.MethodType(List, self))
147
148  def DefineUpdate(self, update_field_name):
149    """Defines the Update functionality on the calling class.
150
151    Args:
152      update_field_name: the field on the patch_request to assign updated object
153                         to
154    """
155    def Update(self, updating_object, update_mask=None):
156      """Updates an object.
157
158      Args:
159        self: The self of the class this is set on.
160        updating_object: Object which is being updated.
161        update_mask: A string saying which fields have been updated.
162
163      Returns:
164        Long running operation.
165      """
166      req = self.patch_request(name=updating_object.name,
167                               updateMask=update_mask)
168      setattr(req, update_field_name, updating_object)
169
170      return self.service.Patch(req)
171
172    # Bind the function to the method and set the attribute
173    setattr(self, 'Update', types.MethodType(Update, self))
174
175  def DefineIamPolicyFunctions(self):
176    """Defines all of the IAM functionality on the calling class."""
177    def GetIamPolicy(self, object_ref):
178      """Gets an IAM Policy on an object.
179
180      Args:
181        self: The self of the class this is set on.
182        object_ref: Resource, reference for object IAM policy belongs to.
183
184      Returns:
185        The IAM policy.
186      """
187      req = self.get_iam_policy_request(resource=object_ref.RelativeName())
188
189      return self.service.GetIamPolicy(req)
190
191    def SetIamPolicy(self, object_ref, policy, update_mask=None):
192      """Sets an IAM Policy on an object.
193
194      Args:
195        self: The self of the class this is set on.
196        object_ref: Resource, reference for object IAM policy belongs to.
197        policy: the policy to be set.
198        update_mask: fields being update on the IAM policy.
199
200      Returns:
201        The IAM policy.
202      """
203      policy_request = self.messages.ApigatewaySetIamPolicyRequest(
204          policy=policy,
205          updateMask=update_mask)
206      req = self.set_iam_policy_request(
207          apigatewaySetIamPolicyRequest=policy_request,
208          resource=object_ref.RelativeName())
209      return self.service.SetIamPolicy(req)
210
211    def AddIamPolicyBinding(self, object_ref, member, role):
212      """Adds an IAM role to a member on an object.
213
214      Args:
215        self: The self of the class this is set on.
216        object_ref: Resource, reference for object IAM policy belongs to.
217        member: the member the binding is being added to.
218        role: the role which to bind to the member.
219
220      Returns:
221        The IAM policy.
222      """
223      policy = self.GetIamPolicy(object_ref)
224      iam_util.AddBindingToIamPolicy(self.messages.ApigatewayBinding, policy,
225                                     member, role)
226      return self.SetIamPolicy(object_ref, policy, 'bindings,etag')
227
228    def RemoveIamPolicyBinding(self, object_ref, member, role):
229      """Adds an IAM role for a member on an object.
230
231      Args:
232        self: The self of the class this is set on
233        object_ref: Resource, reference for object IAM policy belongs to
234        member: the member the binding is removed for
235        role: the role which is being removed from the member
236
237      Returns:
238        The IAM policy
239      """
240      policy = self.GetIamPolicy(object_ref)
241      iam_util.RemoveBindingFromIamPolicy(policy, member, role)
242      return self.SetIamPolicy(object_ref, policy, 'bindings,etag')
243
244    # Bind the function to the method and set the attribute
245    setattr(self, 'GetIamPolicy', types.MethodType(GetIamPolicy, self))
246    setattr(self, 'SetIamPolicy', types.MethodType(SetIamPolicy, self))
247    setattr(self, 'AddIamPolicyBinding', types.MethodType(AddIamPolicyBinding,
248                                                          self))
249    setattr(self, 'RemoveIamPolicyBinding', types.MethodType(
250        RemoveIamPolicyBinding, self))
251