pulumi / pulumi-google-native

Apache License 2.0
70 stars 18 forks source link

AnalyticsHub missing Subscribe method #544

Open devopsangel opened 2 years ago

devopsangel commented 2 years ago

What happened?

Per spec method is exist but current version does not seem support it. https://github.com/pulumi/pulumi-google-native/blob/master/discovery/analyticshub_v1beta1.json#L701

Steps to reproduce

from pulumi_google_native.analyticshub.v1beta1 import (
    DataExchange,
    DataExchangeArgs,
    DataExchangeIamPolicy,
    DataExchangeIamPolicyArgs,
    BindingArgs,
    Listing,
    ListingArgs,
    ListingCategoriesItem,
    DataProviderArgs,
)

Expected Behavior

Method subscribe exposed.

"id": "analyticshub.projects.locations.dataExchanges.listings.subscribe",

Actual Behavior

Method does not exist

Versions used

pip3 show pulumi_google_native
Name: pulumi-google-native
Version: 0.20.0
Summary: A native Pulumi package for creating and managing Google Cloud resources.
Home-page: https://pulumi.com
Author:
Author-email:
License: Apache-2.0

Additional context

n/a

Contributing

Vote on this issue by adding a 👍 reaction. To contribute a fix for this issue, leave a comment (and link to your pull request, if you've opened one already).

lblackstone commented 2 years ago

@viveklak This looks like another resource type that might need special handling to map to a CRUD model. I didn't see an equivalent resource in the TF provider.

viveklak commented 2 years ago

@devopsangel thanks for opening the issue. Currently the google-native provider only models resources that fit a certain shape - e.g. resources that have a put/get/delete etc. endpoint. We also currently only model a get function to retrieve an existing resources. Typically modeling mutative operations as functions is a bit problematic since that doesn't fit in well with state management patterns for an IaC tool like Pulumi. However, we have the means to seed a google SDK client with the same credentials as the Pulumi provider through functions in https://www.pulumi.com/registry/packages/google-native/api-docs/authorization/. It would be a better idea to bootstrap a google sdk client to handle this? I do think we can perhaps model listing subscriptions as an explicit resource but this would require some custom implementation here.

devopsangel commented 2 years ago

thank you so much @viveklak for a quick response. If I go with custom implementation is there sort of PulumiBase that I can extend and add that only functionality, or by bootstraping you meant make straight POST call to that endpoint, or something below?

e.g.

from pulumi import ComponentResource, ResourceOptions, log

....
....
....
class AhListing(ComponentResource):
    def __init__(
        self,
        resource_name: str,
        project: str,
        args: ...,
        opts: Optional[ResourceOptions] = None,
    ):
...
...
...
viveklak commented 2 years ago

Ah interesting point. You could perhaps explore implementing a pulumi dynamic resource provider (since it looks like you are using python). An example is here: https://github.com/pulumi/examples/tree/master/aws-py-dynamicresource In this case you would have to model a subscription resource and implement the corresponding get/create/delete etc.

devopsangel commented 2 years ago

Thank you, I am going to check. @viveklak is this something are you going to support in the future? Otherwise it feels half baked.

viveklak commented 2 years ago

I will switch this to a feature request and prioritize it accordingly. The way to implement this would be to essentially encode the semantics I mentioned above in the dynamic provider directly in the google-native provider. I can't commit to a timeline for that at the moment though.

devopsangel commented 2 years ago

Unfortunately, that AH Subscribe so raw .... :( I am including code snippet if somebody else try that too.

# -*- coding: utf-8 -*-

import binascii
import os
from pulumi import Input, Output
from pulumi.dynamic import Resource, ResourceProvider, CreateResult, UpdateResult, DiffResult
from typing import Any, Dict, Optional

from google.cloud.bigquery_data_exchange_v1beta1 import (
    AnalyticsHubServiceClient,
    DestinationDataset,
    SubscribeListingRequest,
    SubscribeListingResponse
)

ah_client = AnalyticsHubServiceClient()

class AnalyticsHubSubscribeArgs(object):
    name: Input[str]
    project_id: Input[str]
    dataset_id: Input[str]
    location: Input[str]
    friendly_name: Optional[Input[str]]
    description: Optional[Input[str]]
    labels: Optional[Input[Dict[str, Any]]]

    def __init__(self,
                 name,
                 project_id,
                 dataset_id,
                 location,
                 friendly_name=None,
                 description=None,
                 labels=None):
        self.name = name
        self.project_id = project_id
        self.dataset_id = dataset_id
        self.location = location
        self.friendly_name = friendly_name
        self.description = description
        self.labels = labels

class AnalyticsHubSubscribeProvider(ResourceProvider):
    def create(self, args):
        """
        Params:
        name (str):
            Required. Resource name of the listing to subscribe to. e.g.
            ``projects/myproject/locations/US/dataExchanges/123/listings/456``.
        destination_dataset (google.cloud.bigquery_data_exchange_v1beta1.types.DestinationDataset):
            BigQuery destination dataset to create for
            the subscriber.
        """

        # destination_dataset = DestinationDataset()
        # destination_dataset.dataset_reference.dataset_id = args["dataset_id"]
        # destination_dataset.dataset_reference.project_id = args["project_id"]
        # destination_dataset.friendly_name = args["friendly_name"]
        # destination_dataset.description = args["description"]
        # destination_dataset.location = args["location"]
        # destination_dataset.labels = args["labels"]

        request = SubscribeListingRequest(
            name=args["name"],
            # destination_dataset=destination_dataset
            destination_dataset={
                "dataset_reference": {
                    "dataset_id": args["dataset_id"],
                    "project_id": args["project_id"]
                },
                "friendly_name": args["friendly_name"],
                "description": args["description"],
                "location": args["location"],
                "labels": args["labels"]
            }
        )

        # Make the request
        response = ah_client.subscribe_listing(request=request)

        # If successful, the response body is empty.
        # print(response)

        # return CreateResult("ah-" + binascii.b2a_hex(os.urandom(8)).decode("utf-8"), {**args, **response})
        return CreateResult("ah-" + binascii.b2a_hex(os.urandom(8)).decode("utf-8"), {**args})

    def diff(self, id, old_inputs, new_inputs):
        replaces = []
        if old_inputs["friendly_name"] != new_inputs["friendly_name"]:
            replaces.append("friendly_name")

        if old_inputs["labels"] != new_inputs["labels"]:
            replaces.append("labels")

        if old_inputs["dataset_id"] != new_inputs["dataset_id"]:
            replaces.append("dataset_id")

        if old_inputs["description"] != new_inputs["description"]:
            replaces.append("description")

        return DiffResult(
            # If the old and new inputs don't match, the resource needs to be updated/replaced
            changes=old_inputs != new_inputs,
            # If the replaces[] list is empty, nothing important was changed, and we do not have to
            # replace the resource
            replaces=replaces,
            stables=None,
            delete_before_replace=False)

    def update(self, id, old_inputs, new_inputs):
        return UpdateResult(outs={**new_inputs})

class AnalyticsHubSubscribe(Resource):
    name: Output[str]
    project_id: Output[str]
    dataset_id: Output[str]
    location: Output[str]
    friendly_name: Output[str]
    description: Output[str]
    labels: Output[Dict[str, Any]]

    def __init__(self, name: str, args: AnalyticsHubSubscribeArgs, opts=None):
        super().__init__(AnalyticsHubSubscribeProvider(), name, vars(args), opts)
devopsangel commented 1 year ago

Any updates on this?