# -*- coding: utf-8 -*- # # Copyright 2022 Google Inc. 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. """Client for interaction with DataTaxonomy API CRUD DATAPLEX.""" from __future__ import absolute_import from __future__ import division from __future__ import unicode_literals import json import os from apitools.base.py import encoding from googlecloudsdk.api_lib.dataplex import util as dataplex_api from googlecloudsdk.calliope import exceptions from googlecloudsdk.command_lib.iam import iam_util from googlecloudsdk.core import yaml from googlecloudsdk.core.util import files import six def GenerateResourceAccessSpec(args): """Generate Resource Access Spec From Arguments.""" module = dataplex_api.GetMessageModule() resource_access_spec = module.GoogleCloudDataplexV1ResourceAccessSpec( owners=args.resource_owners, readers=args.resource_readers, writers=args.resource_writers) return resource_access_spec def GenerateDataAccessSpec(args): """Generate Data Access Spec From Arguments.""" module = dataplex_api.GetMessageModule() data_access_spec = module.GoogleCloudDataplexV1DataAccessSpec( readers=args.data_readers) return data_access_spec def GenerateDataTaxonomyForCreateRequest(args): """Create Data Taxonomy Requests.""" module = dataplex_api.GetMessageModule() request = module.GoogleCloudDataplexV1DataTaxonomy( description=args.description, displayName=args.display_name, labels=dataplex_api.CreateLabels(module.GoogleCloudDataplexV1DataTaxonomy, args)) return request def GenerateDataTaxonomyForUpdateRequest(args): """Update Data Taxonomy Requests.""" module = dataplex_api.GetMessageModule() return module.GoogleCloudDataplexV1DataTaxonomy( description=args.description, displayName=args.display_name, etag=args.etag, labels=dataplex_api.CreateLabels(module.GoogleCloudDataplexV1DataTaxonomy, args)) def GenerateUpdateMask(args): """Create Update Mask for DataTaxonomy.""" update_mask = [] if args.IsSpecified('description'): update_mask.append('description') if args.IsSpecified('display_name'): update_mask.append('displayName') if args.IsSpecified('labels'): update_mask.append('labels') return update_mask def GenerateAttributeUpdateMask(args): """Create Update Mask for DataTaxonomy.""" update_mask = [] if args.IsSpecified('description'): update_mask.append('description') if args.IsSpecified('display_name'): update_mask.append('displayName') if args.IsSpecified('labels'): update_mask.append('labels') if args.IsSpecified('parent'): update_mask.append('parentId') if args.IsSpecified('resource_readers'): update_mask.append('resourceAccessSpec.readers') if args.IsSpecified('resource_writers'): update_mask.append('resourceAccessSpec.writers') if args.IsSpecified('resource_owners'): update_mask.append('resourceAccessSpec.owners') if args.IsSpecified('data_readers'): update_mask.append('dataAccessSpec.readers') return update_mask def GenerateAttributeBindingUpdateMask(args): """Create Update Mask for DataAttributeBinding.""" update_mask = [] if args.IsSpecified('description'): update_mask.append('description') if args.IsSpecified('display_name'): update_mask.append('displayName') if args.IsSpecified('labels'): update_mask.append('labels') if args.IsSpecified('resource_attributes'): update_mask.append('attributes') if args.IsSpecified('paths'): update_mask.append('paths') if args.IsSpecified('path_file_name'): update_mask.append('paths') if args.IsSpecified('etag'): update_mask.append('etag') return update_mask def GenerateDataAttributeForCreateRequest(data_attribute_ref, args): """Create Data Attribute Requests.""" module = dataplex_api.GetMessageModule() request = module.GoogleCloudDataplexV1DataAttribute( description=args.description, displayName=args.display_name, # parentId is parent attribute which is associated # with the defined attribute. parentId=ResolveParentId(data_attribute_ref, args), resourceAccessSpec=GenerateResourceAccessSpec(args), dataAccessSpec=GenerateDataAccessSpec(args), labels=dataplex_api.CreateLabels( module.GoogleCloudDataplexV1DataAttribute, args)) return request def ResolveParentId(data_attribute_ref, args): if (args.IsSpecified('parent') and args.parent.find('/') == -1): return data_attribute_ref.RelativeName( ).rsplit('/', 1)[0] + '/' + args.parent else: return args.parent def GenerateDataAttributeForUpdateRequest(data_attribute_ref, args): """Generate attributes for Update Data Attribute Requests.""" module = dataplex_api.GetMessageModule() request = module.GoogleCloudDataplexV1DataAttribute( description=args.description, displayName=args.display_name, parentId=ResolveParentId(data_attribute_ref, args), resourceAccessSpec=GenerateResourceAccessSpec(args), dataAccessSpec=GenerateDataAccessSpec(args), etag=args.etag, labels=dataplex_api.CreateLabels( module.GoogleCloudDataplexV1DataAttribute, args)) return request def GenerateAttributeBindingPath(args): """Generate Data Attribute Binding Path.""" if args.IsSpecified('path_file_name'): return GenerateAttributeBindingPathFromFile( args.path_file_name, args.path_file_format) else: return GenerateAttributeBindingPathFromParam(args) def GenerateAttributeBindingPathFromParam(args): """Create Path from specified path parameter.""" module = dataplex_api.GetMessageModule() attribute_binding_path = [] if args.paths is not None: for path in args.paths: attribute_binding_path.append( module.GoogleCloudDataplexV1DataAttributeBindingPath( name=path.get('name'), attributes=path.get('attributes') ) ) return attribute_binding_path def GenerateAttributeBindingPathFromFile(path_file_name, path_file_format): """Create Path from specified file.""" if not os.path.exists(path_file_name): raise exceptions.BadFileException('No such file [{0}]'.format( path_file_name)) if os.path.isdir(path_file_name): raise exceptions.BadFileException('[{0}] is a directory'.format( path_file_name)) try: with files.FileReader(path_file_name) as import_file: return ConvertPathFileToProto(import_file, path_file_format) except Exception as exp: exp_msg = getattr(exp, 'message', six.text_type(exp)) msg = ('Unable to read Path config from specified file ' '[{0}] because [{1}]'.format(path_file_name, exp_msg)) raise exceptions.BadFileException(msg) def ConvertPathFileToProto(path_file_path, path_file_format): """Construct a DataAttributeBindingPath from a JSON/YAML formatted file. Args: path_file_path: Path to the JSON or YAML file. path_file_format: Format for the file provided. If file format will not be provided by default it will be json. Returns: a protorpc.Message of type GoogleCloudDataplexV1DataAttributeBindingPath filled in from the JSON or YAML path file. Raises: BadFileException if the JSON or YAML file is malformed. """ if path_file_format == 'yaml': parsed_path = yaml.load(path_file_path) else: try: parsed_path = json.load(path_file_path) except ValueError as e: raise exceptions.BadFileException('Error parsing JSON: {0}'.format( six.text_type(e))) path_message = dataplex_api.GetMessageModule( ).GoogleCloudDataplexV1DataAttributeBindingPath attribute_binding_path = [] for path in parsed_path['paths']: attribute_binding_path.append(encoding.PyValueToMessage(path_message, path)) return attribute_binding_path def GenerateDataAttributeBindingForCreateRequest(args): """Create Data Attribute Binding Requests.""" module = dataplex_api.GetMessageModule() request = module.GoogleCloudDataplexV1DataAttributeBinding( description=args.description, displayName=args.display_name, resource=args.resource, attributes=args.resource_attributes, paths=GenerateAttributeBindingPath(args), labels=dataplex_api.CreateLabels( module.GoogleCloudDataplexV1DataAttributeBinding, args)) return request def GenerateDataAttributeBindingForUpdateRequest(args): """Update Data Attribute Binding Requests.""" module = dataplex_api.GetMessageModule() request = module.GoogleCloudDataplexV1DataAttributeBinding( description=args.description, displayName=args.display_name, etag=args.etag, attributes=args.resource_attributes, paths=GenerateAttributeBindingPath(args), labels=dataplex_api.CreateLabels( module.GoogleCloudDataplexV1DataAttributeBinding, args)) return request def WaitForOperation(operation): """Waits for the given google.longrunning.Operation to complete.""" return dataplex_api.WaitForOperation( operation, dataplex_api.GetClientInstance().projects_locations_dataTaxonomies) def DataTaxonomySetIamPolicy(taxonomy_ref, policy): """Set Iam Policy request.""" set_iam_policy_req = dataplex_api.GetMessageModule( ).DataplexProjectsLocationsDataTaxonomiesSetIamPolicyRequest( resource=taxonomy_ref.RelativeName(), googleIamV1SetIamPolicyRequest=dataplex_api.GetMessageModule() .GoogleIamV1SetIamPolicyRequest(policy=policy)) return dataplex_api.GetClientInstance( ).projects_locations_dataTaxonomies.SetIamPolicy(set_iam_policy_req) def DataTaxonomyGetIamPolicy(taxonomy_ref): """Get Iam Policy request.""" get_iam_policy_req = dataplex_api.GetMessageModule( ).DataplexProjectsLocationsDataTaxonomiesGetIamPolicyRequest( resource=taxonomy_ref.RelativeName()) return dataplex_api.GetClientInstance( ).projects_locations_dataTaxonomies.GetIamPolicy(get_iam_policy_req) def DataTaxonomyAddIamPolicyBinding(taxonomy_ref, member, role): """Add IAM policy binding request.""" policy = DataTaxonomyGetIamPolicy(taxonomy_ref) iam_util.AddBindingToIamPolicy( dataplex_api.GetMessageModule().GoogleIamV1Binding, policy, member, role) return DataTaxonomySetIamPolicy(taxonomy_ref, policy) def DataTaxonomyRemoveIamPolicyBinding(taxonomy_ref, member, role): """Remove IAM policy binding request.""" policy = DataTaxonomyGetIamPolicy(taxonomy_ref) iam_util.RemoveBindingFromIamPolicy(policy, member, role) return DataTaxonomySetIamPolicy(taxonomy_ref, policy) def DataTaxonomySetIamPolicyFromFile(taxonomy_ref, policy_file): """Set IAM policy binding request from file.""" policy = iam_util.ParsePolicyFile( policy_file, dataplex_api.GetMessageModule().GoogleIamV1Policy) return DataTaxonomySetIamPolicy(taxonomy_ref, policy) def DataAttributeSetIamPolicy(data_attribute_ref, policy): """Set Iam Policy request.""" set_iam_policy_req = dataplex_api.GetMessageModule( ).DataplexProjectsLocationsDataTaxonomiesAttributesSetIamPolicyRequest( resource=data_attribute_ref.RelativeName(), googleIamV1SetIamPolicyRequest=dataplex_api.GetMessageModule() .GoogleIamV1SetIamPolicyRequest(policy=policy)) return dataplex_api.GetClientInstance( ).projects_locations_dataTaxonomies_attributes.SetIamPolicy( set_iam_policy_req) def DataAttributeGetIamPolicy(data_attribute_ref): """Get Iam Policy request.""" get_iam_policy_req = dataplex_api.GetMessageModule( ).DataplexProjectsLocationsDataTaxonomiesAttributesGetIamPolicyRequest( resource=data_attribute_ref.RelativeName()) return dataplex_api.GetClientInstance( ).projects_locations_dataTaxonomies_attributes.GetIamPolicy( get_iam_policy_req) def DataAttributeAddIamPolicyBinding(data_attribute_ref, member, role): """Add IAM policy binding request.""" policy = DataAttributeGetIamPolicy(data_attribute_ref) iam_util.AddBindingToIamPolicy( dataplex_api.GetMessageModule().GoogleIamV1Binding, policy, member, role) return DataAttributeSetIamPolicy(data_attribute_ref, policy) def DataAttributeRemoveIamPolicyBinding(data_attribute_ref, member, role): """Remove IAM policy binding request.""" policy = DataAttributeGetIamPolicy(data_attribute_ref) iam_util.RemoveBindingFromIamPolicy(policy, member, role) return DataAttributeSetIamPolicy(data_attribute_ref, policy) def DataAttributeSetIamPolicyFromFile(data_attribute_ref, policy_file): """Set IAM policy binding request from file.""" policy = iam_util.ParsePolicyFile( policy_file, dataplex_api.GetMessageModule().GoogleIamV1Policy) return DataAttributeSetIamPolicy(data_attribute_ref, policy) def DataAttributeBindingSetIamPolicy(attribute_binding_ref, policy): """Set Iam Policy request.""" set_iam_policy_req = dataplex_api.GetMessageModule( ).DataplexProjectsLocationsDataAttributeBindingsSetIamPolicyRequest( resource=attribute_binding_ref.RelativeName(), googleIamV1SetIamPolicyRequest=dataplex_api.GetMessageModule() .GoogleIamV1SetIamPolicyRequest(policy=policy)) return dataplex_api.GetClientInstance( ).projects_locations_dataAttributeBindings.SetIamPolicy(set_iam_policy_req) def DataAttributeBindingGetIamPolicy(attribute_binding_ref): """Get Iam Policy request.""" get_iam_policy_req = dataplex_api.GetMessageModule( ).DataplexProjectsLocationsDataAttributeBindingsGetIamPolicyRequest( resource=attribute_binding_ref.RelativeName()) return dataplex_api.GetClientInstance( ).projects_locations_dataAttributeBindings.GetIamPolicy(get_iam_policy_req) def DataAttributeBindingAddIamPolicyBinding( attribute_binding_ref, member, role): """Add IAM policy binding request.""" policy = DataAttributeGetIamPolicy(attribute_binding_ref) iam_util.AddBindingToIamPolicy( dataplex_api.GetMessageModule().GoogleIamV1Binding, policy, member, role) return DataAttributeSetIamPolicy(attribute_binding_ref, policy) def DataAttributeBindingRemoveIamPolicyBinding( attribute_binding_ref, member, role): """Remove IAM policy binding request.""" policy = DataAttributeGetIamPolicy(attribute_binding_ref) iam_util.RemoveBindingFromIamPolicy(policy, member, role) return DataAttributeSetIamPolicy(attribute_binding_ref, policy) def DataAttributeBindingSetIamPolicyFromFile( attribute_binding_ref, policy_file): """Set IAM policy binding request from file.""" policy = iam_util.ParsePolicyFile( policy_file, dataplex_api.GetMessageModule().GoogleIamV1Policy) return DataAttributeSetIamPolicy(attribute_binding_ref, policy)