def _validate_resource_data(self):
        ''' Verify we have all the required data for this resource '''
        if not all(arg in self._resource_data
                   for arg in self.required_resource_data):

            raise ResourceException(
                'Missing data required for resource creation. Expected data: {}; Got: {}'
                .format(','.join(self.required_resource_data),
                        ','.join(self._resource_data.keys())))
    def subclass_by_type(cls, resource_type):
        mapper = {
            res_cls.resource_type: res_cls
            for res_cls in cls.__subclasses__()
        }

        try:
            return mapper[resource_type]
        except KeyError:
            raise ResourceException(
                'Unrecognized resource type: {}'.format(resource_type))
    def _validate_resource_data(self):
        """Verify we have all the required data for this resource"""
        if not all(arg in self._resource_data
                   for arg in self.required_resource_data):

            raise ResourceException(
                "Missing data required for resource creation. Expected data: {}; Got: {}"
                .format(
                    ",".join(self.required_resource_data),
                    ",".join(self._resource_data.keys()),
                ))
    def factory(client_kwargs={}, **kwargs):
        resource_type_map = {
            'apps.services.versions.instances': GcpAppEngineInstance,
            'bigquery.datasets': GcpBigqueryDataset,
            'bigtableadmin.projects.instances': GcpBigtableInstance,
            'bigtableadmin.projects.instances.iam': GcpBigtableInstanceIam,
            'cloudfunctions.projects.locations.functions': GcpCloudFunction,
            'cloudfunctions.projects.locations.functions.iam':
            GcpCloudFunctionIam,
            'compute.instances': GcpComputeInstance,
            'compute.disks': GcpComputeDisks,
            'compute.subnetworks': GcpComputeSubnetwork,
            'compute.firewalls': GcpComputeFirewall,
            'container.projects.locations.clusters': GcpGkeCluster,
            'container.projects.locations.clusters.nodePools':
            GcpGkeClusterNodepool,
            'cloudresourcemanager.projects': GcpProject,
            'cloudresourcemanager.projects.iam': GcpProjectIam,
            'dataproc.clusters': GcpDataprocCluster,
            'pubsub.projects.subscriptions': GcpPubsubSubscription,
            'pubsub.projects.subscriptions.iam': GcpPubsubSubscriptionIam,
            'pubsub.projects.topics': GcpPubsubTopic,
            'pubsub.projects.topics.iam': GcpPubsubTopicIam,
            'serviceusage.services': GcpProjectService,
            'sqladmin.instances': GcpSqlInstance,
            'storage.buckets': GcpStorageBucket,
            'storage.buckets.iam': GcpStorageBucketIamPolicy
        }

        resource_type = kwargs.get('resource_type')
        if not resource_type:
            raise ResourceException('Resource type not specified')

        if resource_type not in resource_type_map:
            raise ResourceException(
                'Unknown resource type: {}'.format(resource_type))

        cls = resource_type_map.get(resource_type)
        return cls(client_kwargs=client_kwargs, **kwargs)
    def from_cai_data(resource_name,
                      asset_type,
                      content_type='resource',
                      project_id=None,
                      client_kwargs={}):

        # CAI classifies things by content_type (ex: resource or iam)
        # and asset_type (ex: storage bucket or container cluster)
        cai_map = {
            'resource': {

                # App Engine instances show up as compute instances in CAI exports. We've chosen to
                # define our own asset_type and do some munging outside of rpelib
                'appengine.googleapis.com/Instance': GcpAppEngineInstance,
                'bigquery.googleapis.com/Dataset': GcpBigqueryDataset,
                'bigtableadmin.googleapis.com/Instance': GcpBigtableInstance,

                # Cloudfunctions are not currently supported by CAI. We reached out to the CAI team
                # to find out what the asset_type would likely be
                'cloudfunctions.googleapis.com/CloudFunction':
                GcpCloudFunction,
                'compute.googleapis.com/Instance': GcpComputeInstance,
                'compute.googleapis.com/Disk': GcpComputeDisks,
                'compute.googleapis.com/Subnetwork': GcpComputeSubnetwork,
                'compute.googleapis.com/Firewall': GcpComputeFirewall,
                'dataproc.googleapis.com/Cluster': GcpDataprocCluster,
                'container.googleapis.com/Cluster': GcpGkeCluster,
                'container.googleapis.com/NodePool': GcpGkeClusterNodepool,
                'pubsub.googleapis.com/Subscription': GcpPubsubSubscription,
                'pubsub.googleapis.com/Topic': GcpPubsubTopic,
                'storage.googleapis.com/Bucket': GcpStorageBucket,
                'sqladmin.googleapis.com/Instance': GcpSqlInstance,
                'cloudresourcemanager.googleapis.com/Project': GcpProject,
                'serviceusage.googleapis.com/Service': GcpProjectService,
            },
            'iam': {
                "bigtableadmin.googleapis.com/Instance":
                GcpBigtableInstanceIam,
                "cloudfunctions.googleapis.com/CloudFunction":
                GcpCloudFunctionIam,
                "pubsub.googleapis.com/Subscription": GcpPubsubSubscriptionIam,
                "pubsub.googleapis.com/Topic": GcpPubsubTopicIam,
                "storage.googleapis.com/Bucket": GcpStorageBucketIamPolicy,
                "cloudresourcemanager.googleapis.com/Project": GcpProjectIam,
            }
        }

        if content_type not in cai_map:
            raise ResourceException(
                'Unrecognized content type: {}'.format(content_type))

        asset_type_map = cai_map.get(content_type)

        if asset_type not in asset_type_map:
            raise ResourceException(
                'Unrecognized asset type: {}'.format(asset_type))

        cls = asset_type_map.get(asset_type)

        resource_data = GoogleAPIResource._extract_cai_name_data(resource_name)

        # if the project_id was passed, and its wasnt found in the resource name, add it
        if project_id and 'project_id' not in resource_data:
            resource_data['project_id'] = project_id

        return cls(client_kwargs=client_kwargs, **resource_data)