diff --git a/librarian.yaml b/librarian.yaml index c1a78b3f5094..2ff93a45f04d 100644 --- a/librarian.yaml +++ b/librarian.yaml @@ -16,8 +16,8 @@ version: v0.16.0 repo: googleapis/google-cloud-python sources: googleapis: - commit: c73334a47800ba03cc65e46ade96c07f01db3446 - sha256: 07be59c8bc1dfc420e352db0528641baa23943e7dd1659acac41ca55969fb259 + commit: ff15be54722218705740b9fc6223d264c4cdb6dd + sha256: 13dc3b1a01767be8d486980d3ddcb7fe6f6b89c3da8d41c358d5c2536c86de3c default: output: packages tag_format: '{name}-v{version}' diff --git a/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/async_client.py b/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/async_client.py index b794a173d89a..c91d8c72771a 100644 --- a/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/async_client.py +++ b/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/async_client.py @@ -438,11 +438,13 @@ def sample_row_keys( timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> Awaitable[AsyncIterable[bigtable.SampleRowKeysResponse]]: - r"""Returns a sample of row keys in the table. The - returned row keys will delimit contiguous sections of - the table of approximately equal size, which can be used - to break up the data for distributed tasks like - mapreduces. + r"""Returns a sample of row keys in the table. The returned row keys + will delimit contiguous sections of the table of approximately + equal size, which can be used to break up the data for + distributed tasks like mapreduces. + + If a ``row_range`` is provided in the request, the returned + samples will be restricted to the specified range. Args: request (Optional[Union[google.cloud.bigtable_v2.types.SampleRowKeysRequest, dict]]): diff --git a/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/client.py b/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/client.py index 2e98f59ff944..92dbae5d1c5d 100644 --- a/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/client.py +++ b/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/client.py @@ -928,11 +928,13 @@ def sample_row_keys( timeout: Union[float, object] = gapic_v1.method.DEFAULT, metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> Iterable[bigtable.SampleRowKeysResponse]: - r"""Returns a sample of row keys in the table. The - returned row keys will delimit contiguous sections of - the table of approximately equal size, which can be used - to break up the data for distributed tasks like - mapreduces. + r"""Returns a sample of row keys in the table. The returned row keys + will delimit contiguous sections of the table of approximately + equal size, which can be used to break up the data for + distributed tasks like mapreduces. + + If a ``row_range`` is provided in the request, the returned + samples will be restricted to the specified range. Args: request (Union[google.cloud.bigtable_v2.types.SampleRowKeysRequest, dict]): diff --git a/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/transports/grpc.py b/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/transports/grpc.py index 9d0bae86fd72..b4efced84827 100644 --- a/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/transports/grpc.py +++ b/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/transports/grpc.py @@ -363,11 +363,13 @@ def sample_row_keys( ) -> Callable[[bigtable.SampleRowKeysRequest], bigtable.SampleRowKeysResponse]: r"""Return a callable for the sample row keys method over gRPC. - Returns a sample of row keys in the table. The - returned row keys will delimit contiguous sections of - the table of approximately equal size, which can be used - to break up the data for distributed tasks like - mapreduces. + Returns a sample of row keys in the table. The returned row keys + will delimit contiguous sections of the table of approximately + equal size, which can be used to break up the data for + distributed tasks like mapreduces. + + If a ``row_range`` is provided in the request, the returned + samples will be restricted to the specified range. Returns: Callable[[~.SampleRowKeysRequest], diff --git a/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/transports/grpc_asyncio.py b/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/transports/grpc_asyncio.py index dfa4b4c24a91..83bd59e725cc 100644 --- a/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/transports/grpc_asyncio.py +++ b/packages/google-cloud-bigtable/google/cloud/bigtable_v2/services/bigtable/transports/grpc_asyncio.py @@ -373,11 +373,13 @@ def sample_row_keys( ]: r"""Return a callable for the sample row keys method over gRPC. - Returns a sample of row keys in the table. The - returned row keys will delimit contiguous sections of - the table of approximately equal size, which can be used - to break up the data for distributed tasks like - mapreduces. + Returns a sample of row keys in the table. The returned row keys + will delimit contiguous sections of the table of approximately + equal size, which can be used to break up the data for + distributed tasks like mapreduces. + + If a ``row_range`` is provided in the request, the returned + samples will be restricted to the specified range. Returns: Callable[[~.SampleRowKeysRequest], diff --git a/packages/google-cloud-bigtable/google/cloud/bigtable_v2/types/bigtable.py b/packages/google-cloud-bigtable/google/cloud/bigtable_v2/types/bigtable.py index bf63f4d1e12e..24e3ae5ea280 100644 --- a/packages/google-cloud-bigtable/google/cloud/bigtable_v2/types/bigtable.py +++ b/packages/google-cloud-bigtable/google/cloud/bigtable_v2/types/bigtable.py @@ -358,6 +358,11 @@ class SampleRowKeysRequest(proto.Message): This value specifies routing for replication. If not specified, the "default" application profile will be used. + row_range (google.cloud.bigtable_v2.types.RowRange): + Optional. The row range to sample. If not + specified, samples from all rows. + The output will always return the end key in the + range as the last sample returned. """ table_name: str = proto.Field( @@ -376,6 +381,11 @@ class SampleRowKeysRequest(proto.Message): proto.STRING, number=2, ) + row_range: data.RowRange = proto.Field( + proto.MESSAGE, + number=6, + message=data.RowRange, + ) class SampleRowKeysResponse(proto.Message): @@ -383,23 +393,24 @@ class SampleRowKeysResponse(proto.Message): Attributes: row_key (bytes): - Sorted streamed sequence of sample row keys - in the table. The table might have contents - before the first row key in the list and after - the last one, but a key containing the empty - string indicates "end of table" and will be the - last response given, if present. - Note that row keys in this list may not have - ever been written to or read from, and users - should therefore not make any assumptions about - the row key structure that are specific to their - use case. + Sorted streamed sequence of sample row keys in the table, + restricted to the row_range if specified in the request. The + table might have contents before the first row key in the + list and after the last one, but a key containing the empty + string indicates "end of table" and will be the last + response given, if present and within the row-range + specified in the request. Note that row keys in this list + may not have ever been written to or read from, and users + should therefore not make any assumptions about the row key + structure that are specific to their use case. offset_bytes (int): Approximate total storage space used by all rows in the - table which precede ``row_key``. Buffering the contents of - all rows between two subsequent samples would require space - roughly equal to the difference in their ``offset_bytes`` - fields. + table which precede ``row_key`` (and if a row-range is + specified in the request, which follow what would have been + the previous sample before the row-range start). Buffering + the contents of all rows between two subsequent samples + would require space roughly equal to the difference in their + ``offset_bytes`` fields. """ row_key: bytes = proto.Field( diff --git a/packages/google-cloud-dlp/google/cloud/dlp/__init__.py b/packages/google-cloud-dlp/google/cloud/dlp/__init__.py index f4e3d6a1ec2e..17c72787aa6d 100644 --- a/packages/google-cloud-dlp/google/cloud/dlp/__init__.py +++ b/packages/google-cloud-dlp/google/cloud/dlp/__init__.py @@ -35,6 +35,8 @@ AnalyzeDataSourceRiskDetails, AwsAccount, AwsAccountRegex, + BatchContentItem, + BatchContentLocation, BigQueryDiscoveryTarget, BigQueryRegex, BigQueryRegexes, @@ -280,6 +282,7 @@ StoredInfoTypeState, StoredInfoTypeStats, StoredInfoTypeVersion, + StringValueBatch, Table, TableDataProfile, TableLocation, @@ -363,6 +366,8 @@ "AnalyzeDataSourceRiskDetails", "AwsAccount", "AwsAccountRegex", + "BatchContentItem", + "BatchContentLocation", "BigQueryDiscoveryTarget", "BigQueryRegex", "BigQueryRegexes", @@ -591,6 +596,7 @@ "StoredInfoTypeConfig", "StoredInfoTypeStats", "StoredInfoTypeVersion", + "StringValueBatch", "Table", "TableDataProfile", "TableLocation", diff --git a/packages/google-cloud-dlp/google/cloud/dlp_v2/__init__.py b/packages/google-cloud-dlp/google/cloud/dlp_v2/__init__.py index 4bc8431e09e9..350174be60ef 100644 --- a/packages/google-cloud-dlp/google/cloud/dlp_v2/__init__.py +++ b/packages/google-cloud-dlp/google/cloud/dlp_v2/__init__.py @@ -39,6 +39,8 @@ AnalyzeDataSourceRiskDetails, AwsAccount, AwsAccountRegex, + BatchContentItem, + BatchContentLocation, BigQueryDiscoveryTarget, BigQueryRegex, BigQueryRegexes, @@ -284,6 +286,7 @@ StoredInfoTypeState, StoredInfoTypeStats, StoredInfoTypeVersion, + StringValueBatch, Table, TableDataProfile, TableLocation, @@ -449,6 +452,8 @@ def _get_version(dependency_name): "AnalyzeDataSourceRiskDetails", "AwsAccount", "AwsAccountRegex", + "BatchContentItem", + "BatchContentLocation", "BigQueryDiscoveryTarget", "BigQueryField", "BigQueryKey", @@ -719,6 +724,7 @@ def _get_version(dependency_name): "StoredInfoTypeStats", "StoredInfoTypeVersion", "StoredType", + "StringValueBatch", "Table", "TableDataProfile", "TableLocation", diff --git a/packages/google-cloud-dlp/google/cloud/dlp_v2/types/__init__.py b/packages/google-cloud-dlp/google/cloud/dlp_v2/types/__init__.py index 0b416e4fa3a0..bc666e4f520f 100644 --- a/packages/google-cloud-dlp/google/cloud/dlp_v2/types/__init__.py +++ b/packages/google-cloud-dlp/google/cloud/dlp_v2/types/__init__.py @@ -28,6 +28,8 @@ AnalyzeDataSourceRiskDetails, AwsAccount, AwsAccountRegex, + BatchContentItem, + BatchContentLocation, BigQueryDiscoveryTarget, BigQueryRegex, BigQueryRegexes, @@ -273,6 +275,7 @@ StoredInfoTypeState, StoredInfoTypeStats, StoredInfoTypeVersion, + StringValueBatch, Table, TableDataProfile, TableLocation, @@ -354,6 +357,8 @@ "AnalyzeDataSourceRiskDetails", "AwsAccount", "AwsAccountRegex", + "BatchContentItem", + "BatchContentLocation", "BigQueryDiscoveryTarget", "BigQueryRegex", "BigQueryRegexes", @@ -582,6 +587,7 @@ "StoredInfoTypeConfig", "StoredInfoTypeStats", "StoredInfoTypeVersion", + "StringValueBatch", "Table", "TableDataProfile", "TableLocation", diff --git a/packages/google-cloud-dlp/google/cloud/dlp_v2/types/dlp.py b/packages/google-cloud-dlp/google/cloud/dlp_v2/types/dlp.py index 567cd1d2d95d..922359158fdc 100644 --- a/packages/google-cloud-dlp/google/cloud/dlp_v2/types/dlp.py +++ b/packages/google-cloud-dlp/google/cloud/dlp_v2/types/dlp.py @@ -68,6 +68,8 @@ "ContentMetadata", "Conversation", "ConversationMessage", + "BatchContentItem", + "StringValueBatch", "Table", "KeyValueMetadataProperty", "InspectResult", @@ -75,6 +77,7 @@ "Location", "ContentLocation", "ConversationLocation", + "BatchContentLocation", "MetadataLocation", "StorageMetadataLabel", "KeyValueMetadataLabel", @@ -1644,6 +1647,10 @@ class ContentItem(proto.Message): messages are contiguous and ordered in chronological order. + This field is a member of `oneof`_ ``data_item``. + batch_content_item (google.cloud.dlp_v2.types.BatchContentItem): + Represents a batch of items to inspect. + This field is a member of `oneof`_ ``data_item``. content_metadata (google.cloud.dlp_v2.types.ContentMetadata): User provided metadata for the content. @@ -1672,6 +1679,12 @@ class ContentItem(proto.Message): oneof="data_item", message="Conversation", ) + batch_content_item: "BatchContentItem" = proto.Field( + proto.MESSAGE, + number=8, + oneof="data_item", + message="BatchContentItem", + ) content_metadata: "ContentMetadata" = proto.Field( proto.MESSAGE, number=6, @@ -1725,7 +1738,7 @@ class ConversationMessage(proto.Message): message_type (google.cloud.dlp_v2.types.ConversationMessage.MessageType): The type of message. participant_id (str): - Optional. The identifier of the participant, for example, + Optional. The identifier of the participant, for example 'test-user' or 'gemini'. The participant ID can contain lowercase letters, numbers, and hyphens; that is, it must match the regular expression: @@ -1767,6 +1780,42 @@ class MessageType(proto.Enum): ) +class BatchContentItem(proto.Message): + r"""Represents a batch of content to inspect or redact. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + string_value_batch (google.cloud.dlp_v2.types.StringValueBatch): + Optional. Represents a batch of string values + to inspect or redact. + + This field is a member of `oneof`_ ``batch``. + """ + + string_value_batch: "StringValueBatch" = proto.Field( + proto.MESSAGE, + number=1, + oneof="batch", + message="StringValueBatch", + ) + + +class StringValueBatch(proto.Message): + r"""Represents a batch of string values to inspect or redact. + + Attributes: + values (MutableSequence[str]): + Optional. Represents string data to inspect + or redact. + """ + + values: MutableSequence[str] = proto.RepeatedField( + proto.STRING, + number=1, + ) + + class Table(proto.Message): r"""Structured content to inspect. Up to 50,000 ``Value``\ s per request allowed. See @@ -2069,6 +2118,10 @@ class ContentLocation(proto.Message): conversation_location (google.cloud.dlp_v2.types.ConversationLocation): Location within a conversation. + This field is a member of `oneof`_ ``location``. + batch_content_location (google.cloud.dlp_v2.types.BatchContentLocation): + Location within a batch of content. + This field is a member of `oneof`_ ``location``. container_timestamp (google.protobuf.timestamp_pb2.Timestamp): Finding container modification timestamp, if applicable. For @@ -2115,6 +2168,12 @@ class ContentLocation(proto.Message): oneof="location", message="ConversationLocation", ) + batch_content_location: "BatchContentLocation" = proto.Field( + proto.MESSAGE, + number=11, + oneof="location", + message="BatchContentLocation", + ) container_timestamp: timestamp_pb2.Timestamp = proto.Field( proto.MESSAGE, number=6, @@ -2168,6 +2227,21 @@ class AllMessages(proto.Message): ) +class BatchContentLocation(proto.Message): + r"""Location within a batch of content. + + Attributes: + item_index (int): + Matches an index of a batch item in the batch + provided in the request. + """ + + item_index: int = proto.Field( + proto.INT32, + number=1, + ) + + class MetadataLocation(proto.Message): r"""Metadata Location diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/__init__.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/__init__.py index 07edbdbb3cd0..db78fe9542c2 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/__init__.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/__init__.py @@ -34,7 +34,12 @@ from .types.agent_context import AgentContextReference from .types.context import ( AnalysisOptions, + BigQueryRoutine, + BigQueryRoutineReference, ChartOptions, + Citation, + CitationAnchor, + CitationSource, Context, ConversationOptions, DatasourceOptions, @@ -42,6 +47,10 @@ GlossaryTerm, LookerGoldenQuery, LookerQuery, + MatchedQuery, + QueryParameter, + QueryParameterValues, + UserFunctions, ) from .types.conversation import ( Conversation, @@ -89,6 +98,7 @@ GenerationOptions, ListMessagesRequest, ListMessagesResponse, + LookerSettings, Message, ParameterizedSecureViewParameters, QueryDataContext, @@ -105,10 +115,12 @@ from .types.datasource import ( AlloyDbDatabaseReference, AlloyDbReference, + BigQueryPropertyGraphReference, BigQueryTableReference, BigQueryTableReferences, CloudSqlDatabaseReference, CloudSqlReference, + DatabaseTableReference, DataFilter, DataFilterType, Datasource, @@ -218,6 +230,9 @@ def _get_version(dependency_name): "AnalysisOptions", "AnalysisQuery", "BigQueryJob", + "BigQueryPropertyGraphReference", + "BigQueryRoutine", + "BigQueryRoutineReference", "BigQueryTableReference", "BigQueryTableReferences", "Blob", @@ -226,6 +241,9 @@ def _get_version(dependency_name): "ChartQuery", "ChartResult", "ChatRequest", + "Citation", + "CitationAnchor", + "CitationSource", "ClarificationMessage", "ClarificationQuestion", "ClientManagedResourceContext", @@ -248,6 +266,7 @@ def _get_version(dependency_name): "DataMessage", "DataQuery", "DataResult", + "DatabaseTableReference", "Datasource", "DatasourceOptions", "DatasourceReferences", @@ -274,6 +293,8 @@ def _get_version(dependency_name): "LookerExploreReferences", "LookerGoldenQuery", "LookerQuery", + "LookerSettings", + "MatchedQuery", "Message", "OAuthCredentials", "OperationMetadata", @@ -282,6 +303,8 @@ def _get_version(dependency_name): "QueryDataContext", "QueryDataRequest", "QueryDataResponse", + "QueryParameter", + "QueryParameterValues", "Schema", "SchemaMessage", "SchemaQuery", @@ -294,5 +317,6 @@ def _get_version(dependency_name): "SystemMessage", "TextMessage", "UpdateDataAgentRequest", + "UserFunctions", "UserMessage", ) diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_agent_service/async_client.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_agent_service/async_client.py index 4ef2b8d9e90b..75202c204bc9 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_agent_service/async_client.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_agent_service/async_client.py @@ -88,6 +88,8 @@ class DataAgentServiceAsyncClient: _DEFAULT_ENDPOINT_TEMPLATE = DataAgentServiceClient._DEFAULT_ENDPOINT_TEMPLATE _DEFAULT_UNIVERSE = DataAgentServiceClient._DEFAULT_UNIVERSE + crypto_key_path = staticmethod(DataAgentServiceClient.crypto_key_path) + parse_crypto_key_path = staticmethod(DataAgentServiceClient.parse_crypto_key_path) data_agent_path = staticmethod(DataAgentServiceClient.data_agent_path) parse_data_agent_path = staticmethod(DataAgentServiceClient.parse_data_agent_path) common_billing_account_path = staticmethod( diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_agent_service/client.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_agent_service/client.py index 5bbd4d73008b..2e3cffac16f0 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_agent_service/client.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_agent_service/client.py @@ -241,6 +241,30 @@ def transport(self) -> DataAgentServiceTransport: """ return self._transport + @staticmethod + def crypto_key_path( + project: str, + location: str, + key_ring: str, + crypto_key: str, + ) -> str: + """Returns a fully-qualified crypto_key string.""" + return "projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}".format( + project=project, + location=location, + key_ring=key_ring, + crypto_key=crypto_key, + ) + + @staticmethod + def parse_crypto_key_path(path: str) -> Dict[str, str]: + """Parses a crypto_key path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/keyRings/(?P.+?)/cryptoKeys/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + @staticmethod def data_agent_path( project: str, diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/async_client.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/async_client.py index ff0a0a5a4fac..81b99ecb0717 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/async_client.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/async_client.py @@ -92,6 +92,8 @@ class DataChatServiceAsyncClient: parse_conversation_path = staticmethod( DataChatServiceClient.parse_conversation_path ) + crypto_key_path = staticmethod(DataChatServiceClient.crypto_key_path) + parse_crypto_key_path = staticmethod(DataChatServiceClient.parse_crypto_key_path) data_agent_path = staticmethod(DataChatServiceClient.data_agent_path) parse_data_agent_path = staticmethod(DataChatServiceClient.parse_data_agent_path) common_billing_account_path = staticmethod( @@ -323,8 +325,7 @@ def chat( metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> Awaitable[AsyncIterable[data_chat_service.Message]]: r"""Answers a data question by generating a stream of - [Message][google.cloud.geminidataanalytics.v1alpha.Message] - objects. + [Message][google.cloud.geminidataanalytics.v1.Message] objects. .. code-block:: python diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/client.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/client.py index a6a36cd555c8..a17532f97afc 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/client.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/client.py @@ -262,6 +262,30 @@ def parse_conversation_path(path: str) -> Dict[str, str]: ) return m.groupdict() if m else {} + @staticmethod + def crypto_key_path( + project: str, + location: str, + key_ring: str, + crypto_key: str, + ) -> str: + """Returns a fully-qualified crypto_key string.""" + return "projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}".format( + project=project, + location=location, + key_ring=key_ring, + crypto_key=crypto_key, + ) + + @staticmethod + def parse_crypto_key_path(path: str) -> Dict[str, str]: + """Parses a crypto_key path into its component segments.""" + m = re.match( + r"^projects/(?P.+?)/locations/(?P.+?)/keyRings/(?P.+?)/cryptoKeys/(?P.+?)$", + path, + ) + return m.groupdict() if m else {} + @staticmethod def data_agent_path( project: str, @@ -774,8 +798,7 @@ def chat( metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), ) -> Iterable[data_chat_service.Message]: r"""Answers a data question by generating a stream of - [Message][google.cloud.geminidataanalytics.v1alpha.Message] - objects. + [Message][google.cloud.geminidataanalytics.v1.Message] objects. .. code-block:: python diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc.py index 769cf5e1311b..3508fedf3e2a 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc.py @@ -343,8 +343,7 @@ def chat( r"""Return a callable for the chat method over gRPC. Answers a data question by generating a stream of - [Message][google.cloud.geminidataanalytics.v1alpha.Message] - objects. + [Message][google.cloud.geminidataanalytics.v1.Message] objects. Returns: Callable[[~.ChatRequest], diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc_asyncio.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc_asyncio.py index f7447ede900c..7df68e8da03c 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc_asyncio.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/services/data_chat_service/transports/grpc_asyncio.py @@ -353,8 +353,7 @@ def chat( r"""Return a callable for the chat method over gRPC. Answers a data question by generating a stream of - [Message][google.cloud.geminidataanalytics.v1alpha.Message] - objects. + [Message][google.cloud.geminidataanalytics.v1.Message] objects. Returns: Callable[[~.ChatRequest], diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/__init__.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/__init__.py index 85838315154f..7eefd0f64522 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/__init__.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/__init__.py @@ -18,7 +18,12 @@ ) from .context import ( AnalysisOptions, + BigQueryRoutine, + BigQueryRoutineReference, ChartOptions, + Citation, + CitationAnchor, + CitationSource, Context, ConversationOptions, DatasourceOptions, @@ -26,6 +31,10 @@ GlossaryTerm, LookerGoldenQuery, LookerQuery, + MatchedQuery, + QueryParameter, + QueryParameterValues, + UserFunctions, ) from .conversation import ( Conversation, @@ -80,6 +89,7 @@ GenerationOptions, ListMessagesRequest, ListMessagesResponse, + LookerSettings, Message, ParameterizedSecureViewParameters, QueryDataContext, @@ -96,10 +106,12 @@ from .datasource import ( AlloyDbDatabaseReference, AlloyDbReference, + BigQueryPropertyGraphReference, BigQueryTableReference, BigQueryTableReferences, CloudSqlDatabaseReference, CloudSqlReference, + DatabaseTableReference, DataFilter, DataFilterType, Datasource, @@ -118,7 +130,12 @@ __all__ = ( "AgentContextReference", "AnalysisOptions", + "BigQueryRoutine", + "BigQueryRoutineReference", "ChartOptions", + "Citation", + "CitationAnchor", + "CitationSource", "Context", "ConversationOptions", "DatasourceOptions", @@ -126,6 +143,10 @@ "GlossaryTerm", "LookerGoldenQuery", "LookerQuery", + "MatchedQuery", + "QueryParameter", + "QueryParameterValues", + "UserFunctions", "Conversation", "CreateConversationRequest", "DeleteConversationRequest", @@ -168,6 +189,7 @@ "GenerationOptions", "ListMessagesRequest", "ListMessagesResponse", + "LookerSettings", "Message", "ParameterizedSecureViewParameters", "QueryDataContext", @@ -182,10 +204,12 @@ "UserMessage", "AlloyDbDatabaseReference", "AlloyDbReference", + "BigQueryPropertyGraphReference", "BigQueryTableReference", "BigQueryTableReferences", "CloudSqlDatabaseReference", "CloudSqlReference", + "DatabaseTableReference", "DataFilter", "Datasource", "DatasourceReferences", diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/context.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/context.py index 034610559c00..383117bb720e 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/context.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/context.py @@ -26,7 +26,13 @@ package="google.cloud.geminidataanalytics.v1beta", manifest={ "Context", + "UserFunctions", + "BigQueryRoutine", + "BigQueryRoutineReference", "ExampleQuery", + "QueryParameter", + "MatchedQuery", + "QueryParameterValues", "LookerGoldenQuery", "LookerQuery", "GlossaryTerm", @@ -34,6 +40,9 @@ "DatasourceOptions", "ChartOptions", "AnalysisOptions", + "Citation", + "CitationSource", + "CitationAnchor", }, ) @@ -62,18 +71,25 @@ class Context(proto.Message): providing examples of relevant and commonly used SQL queries and their corresponding natural language queries optionally present. Currently - only used for BigQuery data sources. + only used for BigQuery data sources and + databases (alloydb, cloudsql, spanner) data + sources. looker_golden_queries (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.LookerGoldenQuery]): Optional. A list of golden queries, providing examples of relevant and commonly used Looker queries and their corresponding natural language - queries optionally present. + queries optionally present. Only supported for + Looker data sources. glossary_terms (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.GlossaryTerm]): Optional. Term definitions (currently, only - user authored) + user authored) Not supported for databases + (alloydb, cloudsql, spanner) data sources. schema_relationships (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.Context.SchemaRelationship]): Optional. Relationships between table schema, including referencing and referenced columns. + user_functions (google.cloud.geminidataanalytics_v1beta.types.UserFunctions): + Optional. A collection of user functions to + be included in context. """ class SchemaRelationship(proto.Message): @@ -95,12 +111,12 @@ class SchemaRelationship(proto.Message): must correspond to a field at the same index in the ``left_schema_paths`` list. sources (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.Context.SchemaRelationship.Source]): - Sources which generated the schema relation - edge. + Optional. Sources which generated the schema + relation edge. confidence_score (float): - A confidence score for the suggested - relationship. Manually added edges have the - highest confidence score. + Optional. A confidence score for the + suggested relationship. Manually added edges + have the highest confidence score. """ class Source(proto.Enum): @@ -203,6 +219,75 @@ class SchemaPaths(proto.Message): number=9, message=SchemaRelationship, ) + user_functions: "UserFunctions" = proto.Field( + proto.MESSAGE, + number=10, + message="UserFunctions", + ) + + +class UserFunctions(proto.Message): + r"""A collection of user functions to be included in context. + + Attributes: + bq_routines (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.BigQueryRoutine]): + A list of BigQuery routines to include in the + context. + """ + + bq_routines: MutableSequence["BigQueryRoutine"] = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="BigQueryRoutine", + ) + + +class BigQueryRoutine(proto.Message): + r"""A reference to a BigQuery routine. + + Attributes: + routine_reference (google.cloud.geminidataanalytics_v1beta.types.BigQueryRoutineReference): + The reference to the BigQuery routine. + description (str): + User override or addition to description, to + tell the agent when to use the UDF. + """ + + routine_reference: "BigQueryRoutineReference" = proto.Field( + proto.MESSAGE, + number=1, + message="BigQueryRoutineReference", + ) + description: str = proto.Field( + proto.STRING, + number=2, + ) + + +class BigQueryRoutineReference(proto.Message): + r"""A reference to a BigQuery routine. + + Attributes: + project_id (str): + The project ID of the routine. + dataset_id (str): + The dataset ID of the routine. + routine_id (str): + The routine ID of the routine. + """ + + project_id: str = proto.Field( + proto.STRING, + number=1, + ) + dataset_id: str = proto.Field( + proto.STRING, + number=2, + ) + routine_id: str = proto.Field( + proto.STRING, + number=3, + ) class ExampleQuery(proto.Message): @@ -225,6 +310,10 @@ class ExampleQuery(proto.Message): Optional. A natural language question that a user might ask. For example: "How many orders were placed last month?". + parameters (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.QueryParameter]): + Optional. The list of query parameters. Example: The + parameterized SQL query "SELECT \* FROM my_table WHERE id = + @id" can be matched with any value of id. """ sql_query: str = proto.Field( @@ -236,6 +325,96 @@ class ExampleQuery(proto.Message): proto.STRING, number=1, ) + parameters: MutableSequence["QueryParameter"] = proto.RepeatedField( + proto.MESSAGE, + number=3, + message="QueryParameter", + ) + + +class QueryParameter(proto.Message): + r"""A query parameter message represents a parameter that can be + used to parameterize a SQL query. + + Attributes: + name (str): + Required. The name of the parameter reference + in the SQL query. + description (str): + Optional. The description of the parameter + that can be used by LLM to extract the parameter + value from the user question. + data_type (str): + Required. The data type of the parameter, e.g. "STRING", + "INT64", "DATE", etc. For valid values, see the `BigQuery + documentation `__. + This will be used to populate + google.cloud.bigquery.v2.QueryParameterType.type. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + description: str = proto.Field( + proto.STRING, + number=2, + ) + data_type: str = proto.Field( + proto.STRING, + number=3, + ) + + +class MatchedQuery(proto.Message): + r"""A matched query message represents the agent having matched + one of the example queries supplied in context as being + applicable to the current question. It will also contain + additional info during the matching process. + + Attributes: + example_query (google.cloud.geminidataanalytics_v1beta.types.ExampleQuery): + The query that was matched based on an + example query. + query_parameter_values (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.QueryParameterValues]): + The extracted values for the query + parameters. + """ + + example_query: "ExampleQuery" = proto.Field( + proto.MESSAGE, + number=1, + message="ExampleQuery", + ) + query_parameter_values: MutableSequence["QueryParameterValues"] = ( + proto.RepeatedField( + proto.MESSAGE, + number=2, + message="QueryParameterValues", + ) + ) + + +class QueryParameterValues(proto.Message): + r"""A query parameter values message represents the values for + the query parameters that were extracted from the user question + by LLM, based on the example query. + + Attributes: + name (str): + Required. The name of the parameter. + value (str): + Required. The value of the parameter. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + value: str = proto.Field( + proto.STRING, + number=2, + ) class LookerGoldenQuery(proto.Message): @@ -290,17 +469,36 @@ class LookerQuery(proto.Message): Optional. Limit in the query. This field is a member of `oneof`_ ``_limit``. + query_id (str): + Optional. The primary identifier for the query resource in + Looker, used for API operations. Maps to ``id`` (or + ``slug``) in the Looker API ``Query`` resource. + + This field is a member of `oneof`_ ``_query_id``. + client_id (str): + Optional. The short alphanumeric identifier for the query, + used for share links and Explore URLs (e.g., in the ``qid`` + parameter). Maps to ``client_id`` in the Looker API + ``Query`` resource. + + This field is a member of `oneof`_ ``_client_id``. """ class Filter(proto.Message): r"""A Looker query filter. + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + Attributes: field (str): Required. The field to filter on. value (str): - Required. The value for the field to filter - on. + Optional. The value for the field to filter + on. Optional so we can preserve the default + value as an empty string, important to get a + valid and working Looker Explore url. + + This field is a member of `oneof`_ ``_value``. """ field: str = proto.Field( @@ -310,6 +508,7 @@ class Filter(proto.Message): value: str = proto.Field( proto.STRING, number=2, + optional=True, ) model: str = proto.Field( @@ -338,6 +537,16 @@ class Filter(proto.Message): number=6, optional=True, ) + query_id: str = proto.Field( + proto.STRING, + number=10, + optional=True, + ) + client_id: str = proto.Field( + proto.STRING, + number=11, + optional=True, + ) class GlossaryTerm(proto.Message): @@ -377,6 +586,8 @@ class GlossaryTerm(proto.Message): class ConversationOptions(proto.Message): r"""Options for the conversation. + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + Attributes: chart (google.cloud.geminidataanalytics_v1beta.types.ChartOptions): Optional. Options for chart generation. @@ -384,8 +595,30 @@ class ConversationOptions(proto.Message): Optional. Options for analysis. datasource (google.cloud.geminidataanalytics_v1beta.types.DatasourceOptions): Optional. Options for datasources. + model (google.cloud.geminidataanalytics_v1beta.types.ConversationOptions.Model): + Optional. The model to use for the agent + loop. + + This field is a member of `oneof`_ ``_model``. """ + class Model(proto.Enum): + r"""Allowed models for the agent/conversation. + + Values: + MODEL_UNSPECIFIED (0): + No model specified. The model may be set on + the chat request, or the default model will be + used. + LATEST_GA_MODEL (1): + Use the most up-to-date non-preview model. + This may constrain certain request level + settings. + """ + + MODEL_UNSPECIFIED = 0 + LATEST_GA_MODEL = 1 + chart: "ChartOptions" = proto.Field( proto.MESSAGE, number=1, @@ -401,6 +634,12 @@ class ConversationOptions(proto.Message): number=3, message="DatasourceOptions", ) + model: Model = proto.Field( + proto.ENUM, + number=6, + optional=True, + enum=Model, + ) class DatasourceOptions(proto.Message): @@ -509,4 +748,152 @@ class Python(proto.Message): ) +class Citation(proto.Message): + r"""Source attributions for content. + + Attributes: + sources (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.CitationSource]): + Output only. List of the sources being cited. + anchors (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.CitationAnchor]): + Output only. List of the anchors of the + citations. + """ + + sources: MutableSequence["CitationSource"] = proto.RepeatedField( + proto.MESSAGE, + number=1, + message="CitationSource", + ) + anchors: MutableSequence["CitationAnchor"] = proto.RepeatedField( + proto.MESSAGE, + number=2, + message="CitationAnchor", + ) + + +class CitationSource(proto.Message): + r"""The source of the citation. + + This message has `oneof`_ fields (mutually exclusive fields). + For each oneof, at most one member field can be set at the same time. + Setting any member of the oneof automatically clears all other + members. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + uri (str): + Output only. The uri used as the source, such + as a web grounding URL. + + This field is a member of `oneof`_ ``source_type``. + example_query (google.cloud.geminidataanalytics_v1beta.types.ExampleQuery): + Output only. The example query used as the + source. + + This field is a member of `oneof`_ ``source_type``. + glossary_term (google.cloud.geminidataanalytics_v1beta.types.GlossaryTerm): + Output only. The glossary term used as the + source. + + This field is a member of `oneof`_ ``source_type``. + id (str): + Output only. Unique identifier of the source. This ID is + service-generated and is unique within the scope of a single + ``Citation`` message. + title (str): + Output only. The title of the source. + """ + + uri: str = proto.Field( + proto.STRING, + number=3, + oneof="source_type", + ) + example_query: "ExampleQuery" = proto.Field( + proto.MESSAGE, + number=4, + oneof="source_type", + message="ExampleQuery", + ) + glossary_term: "GlossaryTerm" = proto.Field( + proto.MESSAGE, + number=5, + oneof="source_type", + message="GlossaryTerm", + ) + id: str = proto.Field( + proto.STRING, + number=1, + ) + title: str = proto.Field( + proto.STRING, + number=2, + ) + + +class CitationAnchor(proto.Message): + r"""The anchor of the citation. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + text_message_anchor (google.cloud.geminidataanalytics_v1beta.types.CitationAnchor.TextMessageCitationAnchor): + Output only. Only set if the citation is for + a TextMessage. + + This field is a member of `oneof`_ ``anchor_type``. + """ + + class TextMessageCitationAnchor(proto.Message): + r"""Citation anchor within a TextMessage. + + Attributes: + part_index (int): + Output only. The 0-based index of the part + within the TextMessage.parts field. + start_offset_bytes (int): + Output only. The offset, measured in UTF-8 + bytes, within the part string where the citation + begins (inclusive). Example: For the text + "Hello, world" where "world" is cited, the start + offset bytes (inclusive) is 7 and the end offset + bytes (exclusive) is 12. + end_offset_bytes (int): + Output only. The offset, measured in UTF-8 + bytes, within the part string where the citation + ends (exclusive). Example: For the text "Hello, + world" where "world" is cited, the start offset + bytes (inclusive) is 7 and the end offset bytes + (exclusive) is 12. + source_ids (MutableSequence[str]): + Output only. The ids of the sources that are + cited. + """ + + part_index: int = proto.Field( + proto.INT32, + number=1, + ) + start_offset_bytes: int = proto.Field( + proto.INT32, + number=2, + ) + end_offset_bytes: int = proto.Field( + proto.INT32, + number=3, + ) + source_ids: MutableSequence[str] = proto.RepeatedField( + proto.STRING, + number=4, + ) + + text_message_anchor: TextMessageCitationAnchor = proto.Field( + proto.MESSAGE, + number=1, + oneof="anchor_type", + message=TextMessageCitationAnchor, + ) + + __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/conversation.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/conversation.py index 48091924c735..787f9a93d6a3 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/conversation.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/conversation.py @@ -36,6 +36,8 @@ class Conversation(proto.Message): r"""Message for a conversation. + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + Attributes: name (str): Optional. Identifier. The unique resource name of a @@ -67,6 +69,20 @@ class Conversation(proto.Message): that can be set by the client to tag a conversation (e.g. to filter conversations for specific surfaces/products). + kms_key (str): + Optional. Customer managed encryption key (CMEK) to use for + encrypting the Conversation resources. Encryption will + happen at Titan layer, we will pass the KMS key to Titan. + + Format: + projects/{project_id}/locations/{location}/keyRings/{key_ring_name}/cryptoKeys/{key_name}. + + This field is a member of `oneof`_ ``_kms_key``. + memory_paused (bool): + Optional. Whether memory is paused for this + conversation. + + This field is a member of `oneof`_ ``_memory_paused``. """ name: str = proto.Field( @@ -92,6 +108,16 @@ class Conversation(proto.Message): proto.STRING, number=9, ) + kms_key: str = proto.Field( + proto.STRING, + number=10, + optional=True, + ) + memory_paused: bool = proto.Field( + proto.BOOL, + number=11, + optional=True, + ) class CreateConversationRequest(proto.Message): @@ -160,11 +186,10 @@ class ListConversationsRequest(proto.Message): Required. Parent value for ListConversationsRequest. Format: ``projects/{project}/locations/{location}`` page_size (int): - Optional. Requested page size. Server may - return fewer items than requested. The max page - size is 100. All larger page sizes will be - coerced to 100. If unspecified, server will pick - 50 as an approperiate default. + Optional. Requested page size. Server may return fewer items + than requested. The max page size is ``100``. All larger + page sizes will be coerced to ``100``. If unspecified, + server will pick ``50`` as an appropriate default. page_token (str): Optional. A token identifying a page of results the server should return. diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_agent.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_agent.py index 83db62ac5617..e250674853cf 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_agent.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_agent.py @@ -84,6 +84,14 @@ class DataAgent(proto.Message): Output only. Timestamp in UTC of when this data agent is considered expired. This is *always* provided on output, regardless of what was sent on input. + kms_key (str): + Optional. Customer managed encryption key (CMEK) to use for + encrypting the DataAgent resources. Cloud KMS CryptoKeys + must reside in the same location as the DataAgent. The + expected format is + ``projects/*/locations/*/keyRings/*/cryptoKeys/*``. + + This field is a member of `oneof`_ ``_kms_key``. """ data_analytics_agent: gcg_data_analytics_agent.DataAnalyticsAgent = proto.Field( @@ -129,6 +137,11 @@ class DataAgent(proto.Message): number=13, message=timestamp_pb2.Timestamp, ) + kms_key: str = proto.Field( + proto.STRING, + number=14, + optional=True, + ) __all__ = tuple(sorted(__protobuf__.manifest)) diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_chat_service.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_chat_service.py index 3a0a35d3a702..237691bdbd42 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_chat_service.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/data_chat_service.py @@ -42,6 +42,7 @@ "ConversationReference", "ClientManagedResourceContext", "Message", + "LookerSettings", "UserMessage", "SystemMessage", "TextMessage", @@ -179,17 +180,34 @@ class ParameterizedSecureViewParameters(proto.Message): generation and query execution. Attributes: - parameters (MutableMapping[str, str]): - Optional. Named parameters for Parameterized Secure Views - (PSV). The map keys are parameter names (e.g., - ``"user_id"``), and values are the corresponding parameter - values (e.g., ``"123"``). + parameters (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.ParameterizedSecureViewParameters.Parameter]): + Optional. Named parameters for Parameterized + Secure Views (PSV). """ - parameters: MutableMapping[str, str] = proto.MapField( - proto.STRING, - proto.STRING, + class Parameter(proto.Message): + r"""Represents a single parameter for Parameterized Secure Views. + + Attributes: + key (str): + Required. The parameter key (e.g., ``"user_id"``). + value (str): + Required. The parameter value (e.g., ``"123"``). + """ + + key: str = proto.Field( + proto.STRING, + number=1, + ) + value: str = proto.Field( + proto.STRING, + number=2, + ) + + parameters: MutableSequence[Parameter] = proto.RepeatedField( + proto.MESSAGE, number=1, + message=Parameter, ) @@ -356,11 +374,10 @@ class ListMessagesRequest(proto.Message): Required. The conversation to list messages under. Format: ``projects/{project}/locations/{location}/conversations/{conversation_id}`` page_size (int): - Optional. Requested page size. Server may - return fewer items than requested. The max page - size is 100. All larger page sizes will be - coerced to 100. If unspecified, server will pick - 50 as an approperiate default. + Optional. Requested page size. Server may return fewer items + than requested. The max page size is ``100``. All larger + page sizes will be coerced to ``100``. If unspecified, + server will pick ``50`` as an appropriate default. page_token (str): Optional. A token identifying a page of results the server should return. @@ -479,17 +496,35 @@ class ChatRequest(proto.Message): conversations and agents resources. This field is a member of `oneof`_ ``context_provider``. + looker_settings (google.cloud.geminidataanalytics_v1beta.types.LookerSettings): + Optional. Looker specific settings. + + This field is a member of `oneof`_ ``datasource_settings``. project (str): - Optional. The Google Cloud project to be used - for quota and billing. + Optional. Deprecated: Use ``parent`` field instead. The + Google Cloud project to be used for quota and billing. parent (str): Required. The parent value for chat request. Pattern: ``projects/{project}/locations/{location}`` messages (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.Message]): Required. Content of current conversation. + credentials (google.cloud.geminidataanalytics_v1beta.types.Credentials): + Optional. The credentials to use when calling the data + source(s) specified in the context. + + This field can be used to provide credentials for various + data sources. For example, when connecting to Looker, it + currently supports both OAuth token and API key-based + credentials, as described in `Authentication with an + SDK `__. thinking_mode (google.cloud.geminidataanalytics_v1beta.types.ChatRequest.ThinkingMode): Optional. The thinking mode to use for the agent loop. Defaults to THINKING_MODE_UNSPECIFIED if not specified. + model (google.cloud.geminidataanalytics_v1beta.types.ChatRequest.Model): + Optional. The model to use for the agent loop + when processing the request. This setting only + has an effect when context.options.model is not + set. """ class ThinkingMode(proto.Enum): @@ -509,6 +544,22 @@ class ThinkingMode(proto.Enum): FAST = 1 THINKING = 2 + class Model(proto.Enum): + r"""Model selection for the agent. + + Values: + MODEL_UNSPECIFIED (0): + No model specified. The default model will be + used. + LATEST_GA_MODEL (1): + Use the most up-to-date non-preview model. + This may constrain certain request level + settings. + """ + + MODEL_UNSPECIFIED = 0 + LATEST_GA_MODEL = 1 + inline_context: gcg_context.Context = proto.Field( proto.MESSAGE, number=101, @@ -533,6 +584,12 @@ class ThinkingMode(proto.Enum): oneof="context_provider", message="ClientManagedResourceContext", ) + looker_settings: "LookerSettings" = proto.Field( + proto.MESSAGE, + number=13, + oneof="datasource_settings", + message="LookerSettings", + ) project: str = proto.Field( proto.STRING, number=1, @@ -546,11 +603,21 @@ class ThinkingMode(proto.Enum): number=2, message="Message", ) + credentials: gcg_credentials.Credentials = proto.Field( + proto.MESSAGE, + number=7, + message=gcg_credentials.Credentials, + ) thinking_mode: ThinkingMode = proto.Field( proto.ENUM, number=9, enum=ThinkingMode, ) + model: Model = proto.Field( + proto.ENUM, + number=11, + enum=Model, + ) class DataAgentContext(proto.Message): @@ -561,8 +628,8 @@ class DataAgentContext(proto.Message): Required. The name of the data agent resource. credentials (google.cloud.geminidataanalytics_v1beta.types.Credentials): - Optional. The credentials to use when calling the Looker - data source. + Optional. Deprecated: Use credentials in ChatRequest. The + credentials to use when calling the Looker data source. Currently supports both OAuth token and API key-based credentials, as described in `Authentication with an @@ -719,6 +786,28 @@ class Message(proto.Message): ) +class LookerSettings(proto.Message): + r"""Message to hold Looker specific custom settings. + + Attributes: + enable_dev_mode (bool): + Optional. Whether to operate in Looker's + Development Mode. If true, the API session will + be switched to the "dev" workspace, allowing + interaction with LookML changes in the user's + development branch. If false or unset, the + session remains in the default state (Production + Mode). + See + https://cloud.google.com/looker/docs/dev-mode-prod-mode. + """ + + enable_dev_mode: bool = proto.Field( + proto.BOOL, + number=1, + ) + + class UserMessage(proto.Message): r"""A message from the user that is interacting with the system. @@ -741,7 +830,7 @@ class UserMessage(proto.Message): class SystemMessage(proto.Message): r"""A message from the system in response to the user. This message can also be a message from the user as historical - context for multiturn conversations with the system. + context for multi-turn conversations with the system. This message has `oneof`_ fields (mutually exclusive fields). For each oneof, at most one member field can be set at the same time. @@ -782,8 +871,9 @@ class SystemMessage(proto.Message): This field is a member of `oneof`_ ``kind``. clarification (google.cloud.geminidataanalytics_v1beta.types.ClarificationMessage): - Optional. A message containing clarification - questions. + Optional. Deprecated: Use TextMessage with + TextType.FINAL_RESPONSE instead. A message containing + clarification questions. This field is a member of `oneof`_ ``kind``. group_id (int): @@ -793,6 +883,9 @@ class SystemMessage(proto.Message): together in the UI. This field is a member of `oneof`_ ``_group_id``. + citation (google.cloud.geminidataanalytics_v1beta.types.Citation): + Output only. Citation information for the + system message. """ text: "TextMessage" = proto.Field( @@ -848,6 +941,11 @@ class SystemMessage(proto.Message): number=12, optional=True, ) + citation: gcg_context.Citation = proto.Field( + proto.MESSAGE, + number=15, + message=gcg_context.Citation, + ) class TextMessage(proto.Message): @@ -880,12 +978,17 @@ class TextType(proto.Enum): from the agent's internal thought process (``THOUGHT``) and the final answer to the user (``FINAL_RESPONSE``). These messages provide insight into the agent's actions. + FOLLOWUP_QUESTIONS (4): + The text is a list of follow-up questions + suggested. Each item in parts is a follow-up + question. """ TEXT_TYPE_UNSPECIFIED = 0 FINAL_RESPONSE = 1 THOUGHT = 2 PROGRESS = 3 + FOLLOWUP_QUESTIONS = 4 parts: MutableSequence[str] = proto.RepeatedField( proto.STRING, @@ -993,15 +1096,20 @@ class DataMessage(proto.Message): This field is a member of `oneof`_ ``kind``. generated_looker_query (google.cloud.geminidataanalytics_v1beta.types.LookerQuery): - Looker Query generated by the system to - retrieve data. Deprecated: generated looker - query is now under DataQuery.looker. + Deprecated: generated looker query is now + under DataQuery.looker. Looker Query generated + by the system to retrieve data. This field is a member of `oneof`_ ``kind``. big_query_job (google.cloud.geminidataanalytics_v1beta.types.BigQueryJob): A BigQuery job executed by the system to retrieve data. + This field is a member of `oneof`_ ``kind``. + matched_query (google.cloud.geminidataanalytics_v1beta.types.MatchedQuery): + A pre-existing query that was matched to + retrieve data. + This field is a member of `oneof`_ ``kind``. """ @@ -1034,6 +1142,12 @@ class DataMessage(proto.Message): oneof="kind", message="BigQueryJob", ) + matched_query: gcg_context.MatchedQuery = proto.Field( + proto.MESSAGE, + number=6, + oneof="kind", + message=gcg_context.MatchedQuery, + ) class DataQuery(proto.Message): @@ -1463,57 +1577,71 @@ class ErrorMessage(proto.Message): class ClarificationQuestion(proto.Message): - r"""Represents a single question to the user to help clarify - their query. + r"""Deprecated: Use TextMessage with TextType.FINAL_RESPONSE instead. + Represents a single question to the user to help clarify their + query. Attributes: question (str): - Required. The natural language question to - ask the user. + Required. Deprecated: The parent message is + deprecated. The natural language question to ask + the user. selection_mode (google.cloud.geminidataanalytics_v1beta.types.ClarificationQuestion.SelectionMode): - Required. The selection mode for this + Required. Deprecated: The parent message is + deprecated. The selection mode for this question. options (MutableSequence[str]): - Required. A list of distinct options for the + Required. Deprecated: The parent message is + deprecated. A list of distinct options for the user to choose from. The number of options is limited to a maximum of 5. clarification_question_type (google.cloud.geminidataanalytics_v1beta.types.ClarificationQuestion.ClarificationQuestionType): - Optional. The type of clarification question. + Optional. Deprecated: The parent message is + deprecated. The type of clarification question. """ class SelectionMode(proto.Enum): - r"""The selection mode for the clarification question. + r"""Deprecated: The parent message is deprecated. + The selection mode for the clarification question. Values: SELECTION_MODE_UNSPECIFIED (0): + Deprecated: The parent message is deprecated. Unspecified selection mode. SINGLE_SELECT (1): + Deprecated: The parent message is deprecated. The user can select only one option. MULTI_SELECT (2): + Deprecated: The parent message is deprecated. The user can select multiple options. """ + _pb_options = {"deprecated": True} SELECTION_MODE_UNSPECIFIED = 0 SINGLE_SELECT = 1 MULTI_SELECT = 2 class ClarificationQuestionType(proto.Enum): - r"""The type of clarification question. + r"""Deprecated: The parent message is deprecated. + The type of clarification question. This enum may be extended with new values in the future. Values: CLARIFICATION_QUESTION_TYPE_UNSPECIFIED (0): + Deprecated: The parent message is deprecated. Unspecified clarification question type. FILTER_VALUES (1): - The clarification question is for filter - values. + Deprecated: The parent message is deprecated. + The clarification question is for filter values. FIELDS (2): - The clarification question is for data - fields. This is a generic term encompassing SQL - columns, Looker fields (dimensions/measures), or - nested data structure properties. + Deprecated: The parent message is deprecated. + The clarification question is for data fields. + This is a generic term encompassing SQL columns, + Looker fields (dimensions/measures), or nested + data structure properties. """ + _pb_options = {"deprecated": True} CLARIFICATION_QUESTION_TYPE_UNSPECIFIED = 0 FILTER_VALUES = 1 FIELDS = 2 @@ -1539,13 +1667,15 @@ class ClarificationQuestionType(proto.Enum): class ClarificationMessage(proto.Message): - r"""A message of questions to help clarify the user's query. This - is returned when the system cannot confidently answer the user's + r"""Deprecated: Use TextMessage with TextType.FINAL_RESPONSE instead. A + message of questions to help clarify the user's query. This is + returned when the system cannot confidently answer the user's question. Attributes: questions (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.ClarificationQuestion]): - Required. A batch of clarification questions + Required. Deprecated: The parent message is + deprecated. A batch of clarification questions to ask the user. """ diff --git a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/datasource.py b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/datasource.py index 7f743db56df9..e92e494f6ebb 100644 --- a/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/datasource.py +++ b/packages/google-cloud-geminidataanalytics/google/cloud/geminidataanalytics_v1beta/types/datasource.py @@ -33,6 +33,7 @@ "StudioDatasourceReferences", "StudioDatasourceReference", "AlloyDbReference", + "DatabaseTableReference", "AlloyDbDatabaseReference", "SpannerReference", "SpannerDatabaseReference", @@ -40,6 +41,7 @@ "CloudSqlDatabaseReference", "LookerExploreReferences", "LookerExploreReference", + "BigQueryPropertyGraphReference", "PrivateLookerInstanceInfo", "Datasource", "Schema", @@ -146,12 +148,19 @@ class DatasourceReferences(proto.Message): class BigQueryTableReferences(proto.Message): r"""Message representing references to BigQuery tables and property - graphs. At least one of ``table_references`` or - ``property_graph_references`` must be populated. + graphs. At least one of ``table_references``, + ``property_graph_references``, or ``search_scope`` must be + populated. Attributes: table_references (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.BigQueryTableReference]): Optional. References to BigQuery tables. + property_graph_references (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.BigQueryPropertyGraphReference]): + Optional. Preview feature. References to + BigQuery property graphs. Note: Data sources + must exclusively use either tables or property + graphs, not both. When using property graphs, a + maximum of one graph reference is supported. """ table_references: MutableSequence["BigQueryTableReference"] = proto.RepeatedField( @@ -159,6 +168,13 @@ class BigQueryTableReferences(proto.Message): number=1, message="BigQueryTableReference", ) + property_graph_references: MutableSequence["BigQueryPropertyGraphReference"] = ( + proto.RepeatedField( + proto.MESSAGE, + number=2, + message="BigQueryPropertyGraphReference", + ) + ) class BigQueryTableReference(proto.Message): @@ -201,7 +217,8 @@ class StudioDatasourceReferences(proto.Message): Attributes: studio_references (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.StudioDatasourceReference]): - The references to the studio datasources. + Optional. The references to the studio + datasources. """ studio_references: MutableSequence["StudioDatasourceReference"] = ( @@ -253,6 +270,58 @@ class AlloyDbReference(proto.Message): ) +class DatabaseTableReference(proto.Message): + r"""Message representing a table including its schema. + + Attributes: + table_id (str): + Required. The name of the table as defined in the database. + + Note: The precise rules for table naming, including valid + characters, length limits, and case sensitivity, are + determined by the specific database system. + + Requirements: + + - Exact Match: The provided name must be identical to the + name stored in the database. + - Case Sensitivity: Respect the case sensitivity rules of + the specific database system and how the table was + created. For example, "Orders" and "orders" may be + distinct table names. + - Special Characters/Keywords: If the table name includes + spaces, special characters, or is a database reserved + keyword, provide the literal name as it is stored. Do not + add any database-specific identifier quoting characters + (e.g., ", \`, []). + + Examples: + + - Simple name: "orders", "UserActivity" + - Case sensitive: "MyTable" + - Name with spaces: "Order Details" + - Name with other special characters: "user/data", + "order-items" + - Name that is a keyword: "Group", "Order" + + Permissions: The caller's credentials must have the + necessary database permissions to access the table's schema + and data. + schema (google.cloud.geminidataanalytics_v1beta.types.Schema): + Optional. The schema of the table. + """ + + table_id: str = proto.Field( + proto.STRING, + number=1, + ) + schema: "Schema" = proto.Field( + proto.MESSAGE, + number=2, + message="Schema", + ) + + class AlloyDbDatabaseReference(proto.Message): r"""Message representing a reference to a single AlloyDB database. @@ -272,6 +341,11 @@ class AlloyDbDatabaseReference(proto.Message): table_ids (MutableSequence[str]): Optional. The table ids. Denotes all tables if unset. + database_table_references (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.DatabaseTableReference]): + Optional. References to tables within the + database. Each reference specifies a table and + can optionally include the table's schema to + provide context for the query. """ project_id: str = proto.Field( @@ -298,6 +372,13 @@ class AlloyDbDatabaseReference(proto.Message): proto.STRING, number=6, ) + database_table_references: MutableSequence["DatabaseTableReference"] = ( + proto.RepeatedField( + proto.MESSAGE, + number=7, + message="DatabaseTableReference", + ) + ) class SpannerReference(proto.Message): @@ -335,8 +416,6 @@ class SpannerDatabaseReference(proto.Message): project_id (str): Required. The project the instance belongs to. - region (str): - Required. The region of the instance. instance_id (str): Required. The instance id. database_id (str): @@ -344,6 +423,22 @@ class SpannerDatabaseReference(proto.Message): table_ids (MutableSequence[str]): Optional. The table ids. Denotes all tables if unset. + database_table_references (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.DatabaseTableReference]): + Optional. References to tables within the + database. Each reference specifies a table and + can optionally include the table's schema to + provide context for the query. + priority (str): + Optional. Priority for the queries to + Spanner. Should be a value supported by Cloud + Spanner e.g.: LOW, MEDIUM, HIGH. Unsupported + values will be ignored. See + https://docs.cloud.google.com/spanner/docs/reference/rest/v1/RequestOptions#Priority + for complete list. + request_tag (str): + Tag to be attached to all queries to Spanner. + Allows to identify and monitor queries sent to + Spanner by the GDA service. """ class Engine(proto.Enum): @@ -371,10 +466,6 @@ class Engine(proto.Enum): proto.STRING, number=1, ) - region: str = proto.Field( - proto.STRING, - number=2, - ) instance_id: str = proto.Field( proto.STRING, number=3, @@ -387,6 +478,21 @@ class Engine(proto.Enum): proto.STRING, number=5, ) + database_table_references: MutableSequence["DatabaseTableReference"] = ( + proto.RepeatedField( + proto.MESSAGE, + number=7, + message="DatabaseTableReference", + ) + ) + priority: str = proto.Field( + proto.STRING, + number=8, + ) + request_tag: str = proto.Field( + proto.STRING, + number=9, + ) class CloudSqlReference(proto.Message): @@ -434,6 +540,11 @@ class CloudSqlDatabaseReference(proto.Message): table_ids (MutableSequence[str]): Optional. The table ids. Denotes all tables if unset. + database_table_references (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.DatabaseTableReference]): + Optional. References to tables within the + database. Each reference specifies a table and + can optionally include the table's schema to + provide context for the query. """ class Engine(proto.Enum): @@ -477,6 +588,13 @@ class Engine(proto.Enum): proto.STRING, number=7, ) + database_table_references: MutableSequence["DatabaseTableReference"] = ( + proto.RepeatedField( + proto.MESSAGE, + number=8, + message="DatabaseTableReference", + ) + ) class LookerExploreReferences(proto.Message): @@ -486,8 +604,8 @@ class LookerExploreReferences(proto.Message): explore_references (MutableSequence[google.cloud.geminidataanalytics_v1beta.types.LookerExploreReference]): Required. References to Looker explores. credentials (google.cloud.geminidataanalytics_v1beta.types.Credentials): - Optional. The credentials to use when calling the Looker - API. + Optional. Deprecated: Use credentials in ChatRequest. The + credentials to use when calling the Looker API. Currently supports both OAuth token and API key-based credentials, as described in `Authentication with an @@ -564,6 +682,35 @@ class LookerExploreReference(proto.Message): ) +class BigQueryPropertyGraphReference(proto.Message): + r"""Message representing a reference to a single BigQuery + property graph. + + Attributes: + project_id (str): + Required. The project that the property graph + belongs to. + dataset_id (str): + Required. The dataset that the property graph + belongs to. + property_graph_id (str): + Required. The property graph id. + """ + + project_id: str = proto.Field( + proto.STRING, + number=1, + ) + dataset_id: str = proto.Field( + proto.STRING, + number=2, + ) + property_graph_id: str = proto.Field( + proto.STRING, + number=3, + ) + + class PrivateLookerInstanceInfo(proto.Message): r"""Message representing a private Looker instance info required if the Looker instance is behind a private network. @@ -620,6 +767,10 @@ class Datasource(proto.Message): cloud_sql_reference (google.cloud.geminidataanalytics_v1beta.types.CloudSqlReference): A reference to a CloudSQL database. + This field is a member of `oneof`_ ``reference``. + bigquery_property_graph_reference (google.cloud.geminidataanalytics_v1beta.types.BigQueryPropertyGraphReference): + A reference to a BigQuery property graph. + This field is a member of `oneof`_ ``reference``. schema (google.cloud.geminidataanalytics_v1beta.types.Schema): Optional. The schema of the datasource. @@ -668,6 +819,12 @@ class Datasource(proto.Message): oneof="reference", message="CloudSqlReference", ) + bigquery_property_graph_reference: "BigQueryPropertyGraphReference" = proto.Field( + proto.MESSAGE, + number=16, + oneof="reference", + message="BigQueryPropertyGraphReference", + ) schema: "Schema" = proto.Field( proto.MESSAGE, number=7, @@ -770,9 +927,7 @@ class Field(proto.Message): schema structures. category (str): Optional. Field category, not required, - currently only useful for Looker. We are using a - string to avoid depending on an external package - and keep this package self-contained. + currently only useful for Looker. value_format (str): Optional. Looker only. Value format of the field. Ref: diff --git a/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_agent_service.py b/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_agent_service.py index c7b48b76e446..112b3ba57d7a 100644 --- a/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_agent_service.py +++ b/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_agent_service.py @@ -2481,6 +2481,7 @@ def test_get_data_agent(request_type, transport: str = "grpc"): name="name_value", display_name="display_name_value", description="description_value", + kms_key="kms_key_value", ) response = client.get_data_agent(request) @@ -2495,6 +2496,7 @@ def test_get_data_agent(request_type, transport: str = "grpc"): assert response.name == "name_value" assert response.display_name == "display_name_value" assert response.description == "description_value" + assert response.kms_key == "kms_key_value" def test_get_data_agent_non_empty_request_with_auto_populated_field(): @@ -2629,6 +2631,7 @@ async def test_get_data_agent_async(request_type, transport: str = "grpc_asyncio name="name_value", display_name="display_name_value", description="description_value", + kms_key="kms_key_value", ) ) response = await client.get_data_agent(request) @@ -2644,6 +2647,7 @@ async def test_get_data_agent_async(request_type, transport: str = "grpc_asyncio assert response.name == "name_value" assert response.display_name == "display_name_value" assert response.description == "description_value" + assert response.kms_key == "kms_key_value" def test_get_data_agent_field_headers(): @@ -3217,6 +3221,7 @@ def test_create_data_agent_sync(request_type, transport: str = "grpc"): name="name_value", display_name="display_name_value", description="description_value", + kms_key="kms_key_value", ) response = client.create_data_agent_sync(request) @@ -3231,6 +3236,7 @@ def test_create_data_agent_sync(request_type, transport: str = "grpc"): assert response.name == "name_value" assert response.display_name == "display_name_value" assert response.description == "description_value" + assert response.kms_key == "kms_key_value" def test_create_data_agent_sync_non_empty_request_with_auto_populated_field(): @@ -3378,6 +3384,7 @@ async def test_create_data_agent_sync_async( name="name_value", display_name="display_name_value", description="description_value", + kms_key="kms_key_value", ) ) response = await client.create_data_agent_sync(request) @@ -3393,6 +3400,7 @@ async def test_create_data_agent_sync_async( assert response.name == "name_value" assert response.display_name == "display_name_value" assert response.description == "description_value" + assert response.kms_key == "kms_key_value" def test_create_data_agent_sync_field_headers(): @@ -4014,6 +4022,7 @@ def test_update_data_agent_sync(request_type, transport: str = "grpc"): name="name_value", display_name="display_name_value", description="description_value", + kms_key="kms_key_value", ) response = client.update_data_agent_sync(request) @@ -4028,6 +4037,7 @@ def test_update_data_agent_sync(request_type, transport: str = "grpc"): assert response.name == "name_value" assert response.display_name == "display_name_value" assert response.description == "description_value" + assert response.kms_key == "kms_key_value" def test_update_data_agent_sync_non_empty_request_with_auto_populated_field(): @@ -4169,6 +4179,7 @@ async def test_update_data_agent_sync_async( name="name_value", display_name="display_name_value", description="description_value", + kms_key="kms_key_value", ) ) response = await client.update_data_agent_sync(request) @@ -4184,6 +4195,7 @@ async def test_update_data_agent_sync_async( assert response.name == "name_value" assert response.display_name == "display_name_value" assert response.description == "description_value" + assert response.kms_key == "kms_key_value" def test_update_data_agent_sync_field_headers(): @@ -8471,6 +8483,7 @@ async def test_get_data_agent_empty_call_grpc_asyncio(): name="name_value", display_name="display_name_value", description="description_value", + kms_key="kms_key_value", ) ) await client.get_data_agent(request=None) @@ -8527,6 +8540,7 @@ async def test_create_data_agent_sync_empty_call_grpc_asyncio(): name="name_value", display_name="display_name_value", description="description_value", + kms_key="kms_key_value", ) ) await client.create_data_agent_sync(request=None) @@ -8583,6 +8597,7 @@ async def test_update_data_agent_sync_empty_call_grpc_asyncio(): name="name_value", display_name="display_name_value", description="description_value", + kms_key="kms_key_value", ) ) await client.update_data_agent_sync(request=None) @@ -9034,6 +9049,7 @@ def test_get_data_agent_rest_call_success(request_type): name="name_value", display_name="display_name_value", description="description_value", + kms_key="kms_key_value", ) # Wrap the value into a proper Response obj @@ -9053,6 +9069,7 @@ def test_get_data_agent_rest_call_success(request_type): assert response.name == "name_value" assert response.display_name == "display_name_value" assert response.description == "description_value" + assert response.kms_key == "kms_key_value" @pytest.mark.parametrize("null_interceptor", [True, False]) @@ -9202,7 +9219,14 @@ def test_create_data_agent_rest_call_success(request_type): ], }, } - ] + ], + "property_graph_references": [ + { + "project_id": "project_id_value", + "dataset_id": "dataset_id_value", + "property_graph_id": "property_graph_id_value", + } + ], }, "studio": { "studio_references": [{"datasource_id": "datasource_id_value"}] @@ -9238,6 +9262,9 @@ def test_create_data_agent_rest_call_success(request_type): "instance_id": "instance_id_value", "database_id": "database_id_value", "table_ids": ["table_ids_value1", "table_ids_value2"], + "database_table_references": [ + {"table_id": "table_id_value", "schema": {}} + ], }, "agent_context_reference": { "context_set_id": "context_set_id_value" @@ -9247,10 +9274,12 @@ def test_create_data_agent_rest_call_success(request_type): "database_reference": { "engine": 1, "project_id": "project_id_value", - "region": "region_value", "instance_id": "instance_id_value", "database_id": "database_id_value", "table_ids": ["table_ids_value1", "table_ids_value2"], + "database_table_references": {}, + "priority": "priority_value", + "request_tag": "request_tag_value", }, "agent_context_reference": {}, }, @@ -9262,6 +9291,7 @@ def test_create_data_agent_rest_call_success(request_type): "instance_id": "instance_id_value", "database_id": "database_id_value", "table_ids": ["table_ids_value1", "table_ids_value2"], + "database_table_references": {}, }, "agent_context_reference": {}, }, @@ -9270,11 +9300,19 @@ def test_create_data_agent_rest_call_success(request_type): "chart": {"image": {"no_image": {}, "svg": {}}}, "analysis": {"python": {"enabled": True}}, "datasource": {"big_query_max_billed_bytes": {"value": 541}}, + "model": 1, }, "example_queries": [ { "sql_query": "sql_query_value", "natural_language_question": "natural_language_question_value", + "parameters": [ + { + "name": "name_value", + "description": "description_value", + "data_type": "data_type_value", + } + ], } ], "looker_golden_queries": [ @@ -9292,6 +9330,8 @@ def test_create_data_agent_rest_call_success(request_type): ], "sorts": ["sorts_value1", "sorts_value2"], "limit": "limit_value", + "query_id": "query_id_value", + "client_id": "client_id_value", }, } ], @@ -9313,6 +9353,18 @@ def test_create_data_agent_rest_call_success(request_type): "confidence_score": 0.1673, } ], + "user_functions": { + "bq_routines": [ + { + "routine_reference": { + "project_id": "project_id_value", + "dataset_id": "dataset_id_value", + "routine_id": "routine_id_value", + }, + "description": "description_value", + } + ] + }, }, "published_context": {}, "last_published_context": {}, @@ -9325,6 +9377,7 @@ def test_create_data_agent_rest_call_success(request_type): "update_time": {}, "delete_time": {}, "purge_time": {}, + "kms_key": "kms_key_value", } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -9561,7 +9614,14 @@ def test_create_data_agent_sync_rest_call_success(request_type): ], }, } - ] + ], + "property_graph_references": [ + { + "project_id": "project_id_value", + "dataset_id": "dataset_id_value", + "property_graph_id": "property_graph_id_value", + } + ], }, "studio": { "studio_references": [{"datasource_id": "datasource_id_value"}] @@ -9597,6 +9657,9 @@ def test_create_data_agent_sync_rest_call_success(request_type): "instance_id": "instance_id_value", "database_id": "database_id_value", "table_ids": ["table_ids_value1", "table_ids_value2"], + "database_table_references": [ + {"table_id": "table_id_value", "schema": {}} + ], }, "agent_context_reference": { "context_set_id": "context_set_id_value" @@ -9606,10 +9669,12 @@ def test_create_data_agent_sync_rest_call_success(request_type): "database_reference": { "engine": 1, "project_id": "project_id_value", - "region": "region_value", "instance_id": "instance_id_value", "database_id": "database_id_value", "table_ids": ["table_ids_value1", "table_ids_value2"], + "database_table_references": {}, + "priority": "priority_value", + "request_tag": "request_tag_value", }, "agent_context_reference": {}, }, @@ -9621,6 +9686,7 @@ def test_create_data_agent_sync_rest_call_success(request_type): "instance_id": "instance_id_value", "database_id": "database_id_value", "table_ids": ["table_ids_value1", "table_ids_value2"], + "database_table_references": {}, }, "agent_context_reference": {}, }, @@ -9629,11 +9695,19 @@ def test_create_data_agent_sync_rest_call_success(request_type): "chart": {"image": {"no_image": {}, "svg": {}}}, "analysis": {"python": {"enabled": True}}, "datasource": {"big_query_max_billed_bytes": {"value": 541}}, + "model": 1, }, "example_queries": [ { "sql_query": "sql_query_value", "natural_language_question": "natural_language_question_value", + "parameters": [ + { + "name": "name_value", + "description": "description_value", + "data_type": "data_type_value", + } + ], } ], "looker_golden_queries": [ @@ -9651,6 +9725,8 @@ def test_create_data_agent_sync_rest_call_success(request_type): ], "sorts": ["sorts_value1", "sorts_value2"], "limit": "limit_value", + "query_id": "query_id_value", + "client_id": "client_id_value", }, } ], @@ -9672,6 +9748,18 @@ def test_create_data_agent_sync_rest_call_success(request_type): "confidence_score": 0.1673, } ], + "user_functions": { + "bq_routines": [ + { + "routine_reference": { + "project_id": "project_id_value", + "dataset_id": "dataset_id_value", + "routine_id": "routine_id_value", + }, + "description": "description_value", + } + ] + }, }, "published_context": {}, "last_published_context": {}, @@ -9684,6 +9772,7 @@ def test_create_data_agent_sync_rest_call_success(request_type): "update_time": {}, "delete_time": {}, "purge_time": {}, + "kms_key": "kms_key_value", } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -9761,6 +9850,7 @@ def get_message_fields(field): name="name_value", display_name="display_name_value", description="description_value", + kms_key="kms_key_value", ) # Wrap the value into a proper Response obj @@ -9780,6 +9870,7 @@ def get_message_fields(field): assert response.name == "name_value" assert response.display_name == "display_name_value" assert response.description == "description_value" + assert response.kms_key == "kms_key_value" @pytest.mark.parametrize("null_interceptor", [True, False]) @@ -9933,7 +10024,14 @@ def test_update_data_agent_rest_call_success(request_type): ], }, } - ] + ], + "property_graph_references": [ + { + "project_id": "project_id_value", + "dataset_id": "dataset_id_value", + "property_graph_id": "property_graph_id_value", + } + ], }, "studio": { "studio_references": [{"datasource_id": "datasource_id_value"}] @@ -9969,6 +10067,9 @@ def test_update_data_agent_rest_call_success(request_type): "instance_id": "instance_id_value", "database_id": "database_id_value", "table_ids": ["table_ids_value1", "table_ids_value2"], + "database_table_references": [ + {"table_id": "table_id_value", "schema": {}} + ], }, "agent_context_reference": { "context_set_id": "context_set_id_value" @@ -9978,10 +10079,12 @@ def test_update_data_agent_rest_call_success(request_type): "database_reference": { "engine": 1, "project_id": "project_id_value", - "region": "region_value", "instance_id": "instance_id_value", "database_id": "database_id_value", "table_ids": ["table_ids_value1", "table_ids_value2"], + "database_table_references": {}, + "priority": "priority_value", + "request_tag": "request_tag_value", }, "agent_context_reference": {}, }, @@ -9993,6 +10096,7 @@ def test_update_data_agent_rest_call_success(request_type): "instance_id": "instance_id_value", "database_id": "database_id_value", "table_ids": ["table_ids_value1", "table_ids_value2"], + "database_table_references": {}, }, "agent_context_reference": {}, }, @@ -10001,11 +10105,19 @@ def test_update_data_agent_rest_call_success(request_type): "chart": {"image": {"no_image": {}, "svg": {}}}, "analysis": {"python": {"enabled": True}}, "datasource": {"big_query_max_billed_bytes": {"value": 541}}, + "model": 1, }, "example_queries": [ { "sql_query": "sql_query_value", "natural_language_question": "natural_language_question_value", + "parameters": [ + { + "name": "name_value", + "description": "description_value", + "data_type": "data_type_value", + } + ], } ], "looker_golden_queries": [ @@ -10023,6 +10135,8 @@ def test_update_data_agent_rest_call_success(request_type): ], "sorts": ["sorts_value1", "sorts_value2"], "limit": "limit_value", + "query_id": "query_id_value", + "client_id": "client_id_value", }, } ], @@ -10044,6 +10158,18 @@ def test_update_data_agent_rest_call_success(request_type): "confidence_score": 0.1673, } ], + "user_functions": { + "bq_routines": [ + { + "routine_reference": { + "project_id": "project_id_value", + "dataset_id": "dataset_id_value", + "routine_id": "routine_id_value", + }, + "description": "description_value", + } + ] + }, }, "published_context": {}, "last_published_context": {}, @@ -10056,6 +10182,7 @@ def test_update_data_agent_rest_call_success(request_type): "update_time": {}, "delete_time": {}, "purge_time": {}, + "kms_key": "kms_key_value", } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -10296,7 +10423,14 @@ def test_update_data_agent_sync_rest_call_success(request_type): ], }, } - ] + ], + "property_graph_references": [ + { + "project_id": "project_id_value", + "dataset_id": "dataset_id_value", + "property_graph_id": "property_graph_id_value", + } + ], }, "studio": { "studio_references": [{"datasource_id": "datasource_id_value"}] @@ -10332,6 +10466,9 @@ def test_update_data_agent_sync_rest_call_success(request_type): "instance_id": "instance_id_value", "database_id": "database_id_value", "table_ids": ["table_ids_value1", "table_ids_value2"], + "database_table_references": [ + {"table_id": "table_id_value", "schema": {}} + ], }, "agent_context_reference": { "context_set_id": "context_set_id_value" @@ -10341,10 +10478,12 @@ def test_update_data_agent_sync_rest_call_success(request_type): "database_reference": { "engine": 1, "project_id": "project_id_value", - "region": "region_value", "instance_id": "instance_id_value", "database_id": "database_id_value", "table_ids": ["table_ids_value1", "table_ids_value2"], + "database_table_references": {}, + "priority": "priority_value", + "request_tag": "request_tag_value", }, "agent_context_reference": {}, }, @@ -10356,6 +10495,7 @@ def test_update_data_agent_sync_rest_call_success(request_type): "instance_id": "instance_id_value", "database_id": "database_id_value", "table_ids": ["table_ids_value1", "table_ids_value2"], + "database_table_references": {}, }, "agent_context_reference": {}, }, @@ -10364,11 +10504,19 @@ def test_update_data_agent_sync_rest_call_success(request_type): "chart": {"image": {"no_image": {}, "svg": {}}}, "analysis": {"python": {"enabled": True}}, "datasource": {"big_query_max_billed_bytes": {"value": 541}}, + "model": 1, }, "example_queries": [ { "sql_query": "sql_query_value", "natural_language_question": "natural_language_question_value", + "parameters": [ + { + "name": "name_value", + "description": "description_value", + "data_type": "data_type_value", + } + ], } ], "looker_golden_queries": [ @@ -10386,6 +10534,8 @@ def test_update_data_agent_sync_rest_call_success(request_type): ], "sorts": ["sorts_value1", "sorts_value2"], "limit": "limit_value", + "query_id": "query_id_value", + "client_id": "client_id_value", }, } ], @@ -10407,6 +10557,18 @@ def test_update_data_agent_sync_rest_call_success(request_type): "confidence_score": 0.1673, } ], + "user_functions": { + "bq_routines": [ + { + "routine_reference": { + "project_id": "project_id_value", + "dataset_id": "dataset_id_value", + "routine_id": "routine_id_value", + }, + "description": "description_value", + } + ] + }, }, "published_context": {}, "last_published_context": {}, @@ -10419,6 +10581,7 @@ def test_update_data_agent_sync_rest_call_success(request_type): "update_time": {}, "delete_time": {}, "purge_time": {}, + "kms_key": "kms_key_value", } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -10496,6 +10659,7 @@ def get_message_fields(field): name="name_value", display_name="display_name_value", description="description_value", + kms_key="kms_key_value", ) # Wrap the value into a proper Response obj @@ -10515,6 +10679,7 @@ def get_message_fields(field): assert response.name == "name_value" assert response.display_name == "display_name_value" assert response.description == "description_value" + assert response.kms_key == "kms_key_value" @pytest.mark.parametrize("null_interceptor", [True, False]) @@ -12211,10 +12376,41 @@ def test_data_agent_service_grpc_lro_async_client(): assert transport.operations_client is transport.operations_client -def test_data_agent_path(): +def test_crypto_key_path(): project = "squid" location = "clam" - data_agent = "whelk" + key_ring = "whelk" + crypto_key = "octopus" + expected = "projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}".format( + project=project, + location=location, + key_ring=key_ring, + crypto_key=crypto_key, + ) + actual = DataAgentServiceClient.crypto_key_path( + project, location, key_ring, crypto_key + ) + assert expected == actual + + +def test_parse_crypto_key_path(): + expected = { + "project": "oyster", + "location": "nudibranch", + "key_ring": "cuttlefish", + "crypto_key": "mussel", + } + path = DataAgentServiceClient.crypto_key_path(**expected) + + # Check that the path construction is reversible. + actual = DataAgentServiceClient.parse_crypto_key_path(path) + assert expected == actual + + +def test_data_agent_path(): + project = "winkle" + location = "nautilus" + data_agent = "scallop" expected = "projects/{project}/locations/{location}/dataAgents/{data_agent}".format( project=project, location=location, @@ -12226,9 +12422,9 @@ def test_data_agent_path(): def test_parse_data_agent_path(): expected = { - "project": "octopus", - "location": "oyster", - "data_agent": "nudibranch", + "project": "abalone", + "location": "squid", + "data_agent": "clam", } path = DataAgentServiceClient.data_agent_path(**expected) @@ -12238,7 +12434,7 @@ def test_parse_data_agent_path(): def test_common_billing_account_path(): - billing_account = "cuttlefish" + billing_account = "whelk" expected = "billingAccounts/{billing_account}".format( billing_account=billing_account, ) @@ -12248,7 +12444,7 @@ def test_common_billing_account_path(): def test_parse_common_billing_account_path(): expected = { - "billing_account": "mussel", + "billing_account": "octopus", } path = DataAgentServiceClient.common_billing_account_path(**expected) @@ -12258,7 +12454,7 @@ def test_parse_common_billing_account_path(): def test_common_folder_path(): - folder = "winkle" + folder = "oyster" expected = "folders/{folder}".format( folder=folder, ) @@ -12268,7 +12464,7 @@ def test_common_folder_path(): def test_parse_common_folder_path(): expected = { - "folder": "nautilus", + "folder": "nudibranch", } path = DataAgentServiceClient.common_folder_path(**expected) @@ -12278,7 +12474,7 @@ def test_parse_common_folder_path(): def test_common_organization_path(): - organization = "scallop" + organization = "cuttlefish" expected = "organizations/{organization}".format( organization=organization, ) @@ -12288,7 +12484,7 @@ def test_common_organization_path(): def test_parse_common_organization_path(): expected = { - "organization": "abalone", + "organization": "mussel", } path = DataAgentServiceClient.common_organization_path(**expected) @@ -12298,7 +12494,7 @@ def test_parse_common_organization_path(): def test_common_project_path(): - project = "squid" + project = "winkle" expected = "projects/{project}".format( project=project, ) @@ -12308,7 +12504,7 @@ def test_common_project_path(): def test_parse_common_project_path(): expected = { - "project": "clam", + "project": "nautilus", } path = DataAgentServiceClient.common_project_path(**expected) @@ -12318,8 +12514,8 @@ def test_parse_common_project_path(): def test_common_location_path(): - project = "whelk" - location = "octopus" + project = "scallop" + location = "abalone" expected = "projects/{project}/locations/{location}".format( project=project, location=location, @@ -12330,8 +12526,8 @@ def test_common_location_path(): def test_parse_common_location_path(): expected = { - "project": "oyster", - "location": "nudibranch", + "project": "squid", + "location": "clam", } path = DataAgentServiceClient.common_location_path(**expected) diff --git a/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_chat_service.py b/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_chat_service.py index 6348deebdc71..8c92be8a4f29 100644 --- a/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_chat_service.py +++ b/packages/google-cloud-geminidataanalytics/tests/unit/gapic/geminidataanalytics_v1beta/test_data_chat_service.py @@ -1626,6 +1626,8 @@ def test_create_conversation(request_type, transport: str = "grpc"): call.return_value = gcg_conversation.Conversation( name="name_value", agents=["agents_value"], + kms_key="kms_key_value", + memory_paused=True, ) response = client.create_conversation(request) @@ -1639,6 +1641,8 @@ def test_create_conversation(request_type, transport: str = "grpc"): assert isinstance(response, gcg_conversation.Conversation) assert response.name == "name_value" assert response.agents == ["agents_value"] + assert response.kms_key == "kms_key_value" + assert response.memory_paused is True def test_create_conversation_non_empty_request_with_auto_populated_field(): @@ -1782,6 +1786,8 @@ async def test_create_conversation_async(request_type, transport: str = "grpc_as gcg_conversation.Conversation( name="name_value", agents=["agents_value"], + kms_key="kms_key_value", + memory_paused=True, ) ) response = await client.create_conversation(request) @@ -1796,6 +1802,8 @@ async def test_create_conversation_async(request_type, transport: str = "grpc_as assert isinstance(response, gcg_conversation.Conversation) assert response.name == "name_value" assert response.agents == ["agents_value"] + assert response.kms_key == "kms_key_value" + assert response.memory_paused is True def test_create_conversation_field_headers(): @@ -2322,6 +2330,8 @@ def test_get_conversation(request_type, transport: str = "grpc"): call.return_value = conversation.Conversation( name="name_value", agents=["agents_value"], + kms_key="kms_key_value", + memory_paused=True, ) response = client.get_conversation(request) @@ -2335,6 +2345,8 @@ def test_get_conversation(request_type, transport: str = "grpc"): assert isinstance(response, conversation.Conversation) assert response.name == "name_value" assert response.agents == ["agents_value"] + assert response.kms_key == "kms_key_value" + assert response.memory_paused is True def test_get_conversation_non_empty_request_with_auto_populated_field(): @@ -2470,6 +2482,8 @@ async def test_get_conversation_async(request_type, transport: str = "grpc_async conversation.Conversation( name="name_value", agents=["agents_value"], + kms_key="kms_key_value", + memory_paused=True, ) ) response = await client.get_conversation(request) @@ -2484,6 +2498,8 @@ async def test_get_conversation_async(request_type, transport: str = "grpc_async assert isinstance(response, conversation.Conversation) assert response.name == "name_value" assert response.agents == ["agents_value"] + assert response.kms_key == "kms_key_value" + assert response.memory_paused is True def test_get_conversation_field_headers(): @@ -5610,6 +5626,8 @@ async def test_create_conversation_empty_call_grpc_asyncio(): gcg_conversation.Conversation( name="name_value", agents=["agents_value"], + kms_key="kms_key_value", + memory_paused=True, ) ) await client.create_conversation(request=None) @@ -5661,6 +5679,8 @@ async def test_get_conversation_empty_call_grpc_asyncio(): conversation.Conversation( name="name_value", agents=["agents_value"], + kms_key="kms_key_value", + memory_paused=True, ) ) await client.get_conversation(request=None) @@ -5936,6 +5956,8 @@ def test_create_conversation_rest_call_success(request_type): "create_time": {"seconds": 751, "nanos": 543}, "last_used_time": {}, "labels": {}, + "kms_key": "kms_key_value", + "memory_paused": True, } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -6012,6 +6034,8 @@ def get_message_fields(field): return_value = gcg_conversation.Conversation( name="name_value", agents=["agents_value"], + kms_key="kms_key_value", + memory_paused=True, ) # Wrap the value into a proper Response obj @@ -6030,6 +6054,8 @@ def get_message_fields(field): assert isinstance(response, gcg_conversation.Conversation) assert response.name == "name_value" assert response.agents == ["agents_value"] + assert response.kms_key == "kms_key_value" + assert response.memory_paused is True @pytest.mark.parametrize("null_interceptor", [True, False]) @@ -6257,6 +6283,8 @@ def test_get_conversation_rest_call_success(request_type): return_value = conversation.Conversation( name="name_value", agents=["agents_value"], + kms_key="kms_key_value", + memory_paused=True, ) # Wrap the value into a proper Response obj @@ -6275,6 +6303,8 @@ def test_get_conversation_rest_call_success(request_type): assert isinstance(response, conversation.Conversation) assert response.name == "name_value" assert response.agents == ["agents_value"] + assert response.kms_key == "kms_key_value" + assert response.memory_paused is True @pytest.mark.parametrize("null_interceptor", [True, False]) @@ -7766,10 +7796,41 @@ def test_parse_conversation_path(): assert expected == actual -def test_data_agent_path(): +def test_crypto_key_path(): project = "cuttlefish" location = "mussel" - data_agent = "winkle" + key_ring = "winkle" + crypto_key = "nautilus" + expected = "projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{crypto_key}".format( + project=project, + location=location, + key_ring=key_ring, + crypto_key=crypto_key, + ) + actual = DataChatServiceClient.crypto_key_path( + project, location, key_ring, crypto_key + ) + assert expected == actual + + +def test_parse_crypto_key_path(): + expected = { + "project": "scallop", + "location": "abalone", + "key_ring": "squid", + "crypto_key": "clam", + } + path = DataChatServiceClient.crypto_key_path(**expected) + + # Check that the path construction is reversible. + actual = DataChatServiceClient.parse_crypto_key_path(path) + assert expected == actual + + +def test_data_agent_path(): + project = "whelk" + location = "octopus" + data_agent = "oyster" expected = "projects/{project}/locations/{location}/dataAgents/{data_agent}".format( project=project, location=location, @@ -7781,9 +7842,9 @@ def test_data_agent_path(): def test_parse_data_agent_path(): expected = { - "project": "nautilus", - "location": "scallop", - "data_agent": "abalone", + "project": "nudibranch", + "location": "cuttlefish", + "data_agent": "mussel", } path = DataChatServiceClient.data_agent_path(**expected) @@ -7793,7 +7854,7 @@ def test_parse_data_agent_path(): def test_common_billing_account_path(): - billing_account = "squid" + billing_account = "winkle" expected = "billingAccounts/{billing_account}".format( billing_account=billing_account, ) @@ -7803,7 +7864,7 @@ def test_common_billing_account_path(): def test_parse_common_billing_account_path(): expected = { - "billing_account": "clam", + "billing_account": "nautilus", } path = DataChatServiceClient.common_billing_account_path(**expected) @@ -7813,7 +7874,7 @@ def test_parse_common_billing_account_path(): def test_common_folder_path(): - folder = "whelk" + folder = "scallop" expected = "folders/{folder}".format( folder=folder, ) @@ -7823,7 +7884,7 @@ def test_common_folder_path(): def test_parse_common_folder_path(): expected = { - "folder": "octopus", + "folder": "abalone", } path = DataChatServiceClient.common_folder_path(**expected) @@ -7833,7 +7894,7 @@ def test_parse_common_folder_path(): def test_common_organization_path(): - organization = "oyster" + organization = "squid" expected = "organizations/{organization}".format( organization=organization, ) @@ -7843,7 +7904,7 @@ def test_common_organization_path(): def test_parse_common_organization_path(): expected = { - "organization": "nudibranch", + "organization": "clam", } path = DataChatServiceClient.common_organization_path(**expected) @@ -7853,7 +7914,7 @@ def test_parse_common_organization_path(): def test_common_project_path(): - project = "cuttlefish" + project = "whelk" expected = "projects/{project}".format( project=project, ) @@ -7863,7 +7924,7 @@ def test_common_project_path(): def test_parse_common_project_path(): expected = { - "project": "mussel", + "project": "octopus", } path = DataChatServiceClient.common_project_path(**expected) @@ -7873,8 +7934,8 @@ def test_parse_common_project_path(): def test_common_location_path(): - project = "winkle" - location = "nautilus" + project = "oyster" + location = "nudibranch" expected = "projects/{project}/locations/{location}".format( project=project, location=location, @@ -7885,8 +7946,8 @@ def test_common_location_path(): def test_parse_common_location_path(): expected = { - "project": "scallop", - "location": "abalone", + "project": "cuttlefish", + "location": "mussel", } path = DataChatServiceClient.common_location_path(**expected) diff --git a/packages/google-cloud-storage/tests/system/test_zonal.py b/packages/google-cloud-storage/tests/system/test_zonal.py index 2d79ec8a817c..bcdaeaffb182 100644 --- a/packages/google-cloud-storage/tests/system/test_zonal.py +++ b/packages/google-cloud-storage/tests/system/test_zonal.py @@ -27,7 +27,6 @@ ObjectCustomContextPayload, ) - pytestmark = pytest.mark.skipif( os.getenv("RUN_ZONAL_SYSTEM_TESTS") != "True", reason="Zonal system tests need to be explicitly enabled. This helps scheduling tests in Kokoro and Cloud Build.", diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/async_client.py b/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/async_client.py index 490316be1e22..8fd43959ea38 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/async_client.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/async_client.py @@ -1413,7 +1413,9 @@ async def sample_create_workstation_config(): on the ``request`` instance; if ``request`` is provided, this should not be set. workstation_config (:class:`google.cloud.workstations_v1.types.WorkstationConfig`): - Required. Config to create. + Required. Workstation configuration + to create. + This corresponds to the ``workstation_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1562,7 +1564,9 @@ async def sample_update_workstation_config(): The request object. Request message for UpdateWorkstationConfig. workstation_config (:class:`google.cloud.workstations_v1.types.WorkstationConfig`): - Required. Config to update. + Required. Workstation configuration + to update. + This corresponds to the ``workstation_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -2221,7 +2225,14 @@ async def sample_create_workstation(): on the ``request`` instance; if ``request`` is provided, this should not be set. workstation (:class:`google.cloud.workstations_v1.types.Workstation`): - Required. Workstation to create. + Required. Workstation to create. If source_workstation + is specified, the user must have + ``workstations.workstations.use`` permission on the + source workstation, and the Cloud Workstations Service + Agent for the project where you are creating the new + workstation must have compute.disks.createSnapshot and + compute.snapshots.useReadOnly on the source project. + This corresponds to the ``workstation`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -2363,8 +2374,8 @@ async def sample_update_workstation(): should not be set. update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): Required. Mask specifying which - fields in the workstation configuration - should be updated. + fields in the workstation should be + updated. This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this @@ -2839,7 +2850,8 @@ async def generate_access_token( ) -> workstations.GenerateAccessTokenResponse: r"""Returns a short-lived credential that can be used to send authenticated and authorized traffic to a - workstation. + workstation. Once generated this token cannot be revoked + and is good for the lifetime of the token. .. code-block:: python diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/client.py b/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/client.py index e2453f65fce0..201a77a9c903 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/client.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/client.py @@ -1876,7 +1876,9 @@ def sample_create_workstation_config(): on the ``request`` instance; if ``request`` is provided, this should not be set. workstation_config (google.cloud.workstations_v1.types.WorkstationConfig): - Required. Config to create. + Required. Workstation configuration + to create. + This corresponds to the ``workstation_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -2024,7 +2026,9 @@ def sample_update_workstation_config(): The request object. Request message for UpdateWorkstationConfig. workstation_config (google.cloud.workstations_v1.types.WorkstationConfig): - Required. Config to update. + Required. Workstation configuration + to update. + This corresponds to the ``workstation_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -2672,7 +2676,14 @@ def sample_create_workstation(): on the ``request`` instance; if ``request`` is provided, this should not be set. workstation (google.cloud.workstations_v1.types.Workstation): - Required. Workstation to create. + Required. Workstation to create. If source_workstation + is specified, the user must have + ``workstations.workstations.use`` permission on the + source workstation, and the Cloud Workstations Service + Agent for the project where you are creating the new + workstation must have compute.disks.createSnapshot and + compute.snapshots.useReadOnly on the source project. + This corresponds to the ``workstation`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -2811,8 +2822,8 @@ def sample_update_workstation(): should not be set. update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. Mask specifying which - fields in the workstation configuration - should be updated. + fields in the workstation should be + updated. This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this @@ -3275,7 +3286,8 @@ def generate_access_token( ) -> workstations.GenerateAccessTokenResponse: r"""Returns a short-lived credential that can be used to send authenticated and authorized traffic to a - workstation. + workstation. Once generated this token cannot be revoked + and is good for the lifetime of the token. .. code-block:: python diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/transports/grpc.py b/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/transports/grpc.py index f7c763db3a7c..09c3420c1c68 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/transports/grpc.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/transports/grpc.py @@ -900,7 +900,8 @@ def generate_access_token( Returns a short-lived credential that can be used to send authenticated and authorized traffic to a - workstation. + workstation. Once generated this token cannot be revoked + and is good for the lifetime of the token. Returns: Callable[[~.GenerateAccessTokenRequest], diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/transports/grpc_asyncio.py b/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/transports/grpc_asyncio.py index 1630391a3946..12f1d4f78f69 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/transports/grpc_asyncio.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1/services/workstations/transports/grpc_asyncio.py @@ -929,7 +929,8 @@ def generate_access_token( Returns a short-lived credential that can be used to send authenticated and authorized traffic to a - workstation. + workstation. Once generated this token cannot be revoked + and is good for the lifetime of the token. Returns: Callable[[~.GenerateAccessTokenRequest], diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1/types/workstations.py b/packages/google-cloud-workstations/google/cloud/workstations_v1/types/workstations.py index b5180a3edfda..eee957989694 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1/types/workstations.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1/types/workstations.py @@ -68,7 +68,8 @@ class WorkstationCluster(proto.Message): Attributes: name (str): - Full name of this workstation cluster. + Identifier. Full name of this workstation + cluster. display_name (str): Optional. Human-readable name for this workstation cluster. @@ -120,14 +121,50 @@ class WorkstationCluster(proto.Message): private_cluster_config (google.cloud.workstations_v1.types.WorkstationCluster.PrivateClusterConfig): Optional. Configuration for private workstation cluster. + domain_config (google.cloud.workstations_v1.types.WorkstationCluster.DomainConfig): + Optional. Configuration options for a custom + domain. degraded (bool): Output only. Whether this workstation cluster is in degraded mode, in which case it may require user action to restore - full functionality. Details can be found in - [conditions][google.cloud.workstations.v1.WorkstationCluster.conditions]. + full functionality. The + [conditions][google.cloud.workstations.v1.WorkstationCluster.conditions] + field contains detailed information about the status of the + cluster. conditions (MutableSequence[google.rpc.status_pb2.Status]): Output only. Status conditions describing the workstation cluster's current state. + tags (MutableMapping[str, str]): + Optional. Input only. Immutable. Tag + keys/values directly bound to this resource. For + example: + + "123/environment": "production", + "123/costCenter": "marketing". + gateway_config (google.cloud.workstations_v1.types.WorkstationCluster.GatewayConfig): + Optional. Configuration options for Cluster + HTTP Gateway. + workstation_authorization_url (str): + Optional. Specifies the redirect URL for unauthorized + requests received by workstation VMs in this cluster. + + Redirects to this endpoint will send a base64 encoded + ``state`` query param containing the target workstation name + and original request hostname. The endpoint is responsible + for retrieving a token using ``GenerateAccessToken`` and + redirecting back to the original hostname with the token. + workstation_launch_url (str): + Optional. Specifies the launch URL for workstations in this + cluster. Requests sent to unstarted workstations will be + redirected to this URL. + + Requests redirected to the launch endpoint will be sent with + a ``workstation`` and ``project`` query parameter containing + the full workstation resource name and project ID, + respectively. The launch endpoint is responsible for + starting the workstation, polling it until it reaches + ``STATE_RUNNING``, and then issuing a redirect to the + workstation's host URL. """ class PrivateClusterConfig(proto.Message): @@ -147,7 +184,7 @@ class PrivateClusterConfig(proto.Message): mapping that address to the service attachment. service_attachment_uri (str): Output only. Service attachment URI for the workstation - cluster. The service attachemnt is created when private + cluster. The service attachment is created when private endpoint is enabled. To access workstations in the workstation cluster, configure access to the managed service using `Private Service @@ -177,6 +214,34 @@ class PrivateClusterConfig(proto.Message): number=4, ) + class DomainConfig(proto.Message): + r"""Configuration options for a custom domain. + + Attributes: + domain (str): + Immutable. Domain used by Workstations for + HTTP ingress. + """ + + domain: str = proto.Field( + proto.STRING, + number=1, + ) + + class GatewayConfig(proto.Message): + r"""Configuration options for Cluster HTTP Gateway. + + Attributes: + http2_enabled (bool): + Optional. Whether HTTP/2 is enabled for this + workstation cluster. Defaults to false. + """ + + http2_enabled: bool = proto.Field( + proto.BOOL, + number=1, + ) + name: str = proto.Field( proto.STRING, number=1, @@ -239,6 +304,11 @@ class PrivateClusterConfig(proto.Message): number=12, message=PrivateClusterConfig, ) + domain_config: DomainConfig = proto.Field( + proto.MESSAGE, + number=17, + message=DomainConfig, + ) degraded: bool = proto.Field( proto.BOOL, number=13, @@ -248,6 +318,24 @@ class PrivateClusterConfig(proto.Message): number=14, message=status_pb2.Status, ) + tags: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=20, + ) + gateway_config: GatewayConfig = proto.Field( + proto.MESSAGE, + number=21, + message=GatewayConfig, + ) + workstation_authorization_url: str = proto.Field( + proto.STRING, + number=22, + ) + workstation_launch_url: str = proto.Field( + proto.STRING, + number=23, + ) class WorkstationConfig(proto.Message): @@ -264,7 +352,8 @@ class WorkstationConfig(proto.Message): Attributes: name (str): - Full name of this workstation configuration. + Identifier. Full name of this workstation + configuration. display_name (str): Optional. Human-readable name for this workstation configuration. @@ -332,11 +421,31 @@ class WorkstationConfig(proto.Message): Workstations VMs created with this configuration have no maximum running time. This is strongly discouraged because you incur costs and will not pick up security updates. + max_usable_workstations (int): + Optional. Maximum number of workstations under this + configuration a user can have + ``workstations.workstation.use`` permission on. + + Only enforced on CreateWorkstation API calls on the user + issuing the API request. Can be overridden by: + + - granting a user + workstations.workstationConfigs.exemptMaxUsableWorkstationLimit + permission, or + - having a user with that permission create a workstation + and granting another user ``workstations.workstation.use`` + permission on that workstation. + + If not specified, defaults to ``0``, which indicates + unlimited. host (google.cloud.workstations_v1.types.WorkstationConfig.Host): Optional. Runtime host for the workstation. persistent_directories (MutableSequence[google.cloud.workstations_v1.types.WorkstationConfig.PersistentDirectory]): Optional. Directories to persist across workstation sessions. + ephemeral_directories (MutableSequence[google.cloud.workstations_v1.types.WorkstationConfig.EphemeralDirectory]): + Optional. Ephemeral directories which won't + persist across workstation sessions. container (google.cloud.workstations_v1.types.WorkstationConfig.Container): Optional. Container that runs upon startup for each workstation using this workstation @@ -383,14 +492,56 @@ class WorkstationConfig(proto.Message): Immutable after the workstation configuration is created. degraded (bool): - Output only. Whether this resource is degraded, in which - case it may require user action to restore full - functionality. See also the + Output only. Whether this workstation configuration is in + degraded mode, in which case it may require user action to + restore full functionality. The [conditions][google.cloud.workstations.v1.WorkstationConfig.conditions] - field. + field contains detailed information about the status of the + configuration. conditions (MutableSequence[google.rpc.status_pb2.Status]): Output only. Status conditions describing the - current resource state. + workstation configuration's current state. + enable_audit_agent (bool): + Optional. Whether to enable Linux ``auditd`` logging on the + workstation. When enabled, a + [service_account][google.cloud.workstations.v1.WorkstationConfig.Host.GceInstance.service_account] + must also be specified that has ``roles/logging.logWriter`` + and ``roles/monitoring.metricWriter`` on the project. + Operating system audit logging is distinct from `Cloud Audit + Logs `__ + and `Container output + logging `__. + Operating system audit logs are available in the `Cloud + Logging `__ console + by querying: + + :: + + resource.type="gce_instance" + log_name:"/logs/linux-auditd". + disable_tcp_connections (bool): + Optional. Disables support for plain TCP + connections in the workstation. By default the + service supports TCP connections through a + websocket relay. Setting this option to true + disables that relay, which prevents the usage of + services that require plain TCP connections, + such as SSH. When enabled, all communication + must occur over HTTPS or WSS. + allowed_ports (MutableSequence[google.cloud.workstations_v1.types.WorkstationConfig.PortRange]): + Optional. A list of + [PortRange][google.cloud.workstations.v1.WorkstationConfig.PortRange]s + specifying single ports or ranges of ports that are + externally accessible in the workstation. Allowed ports must + be one of 22, 80, or within range 1024-65535. If not + specified defaults to ports 22, 80, and ports 1024-65535. + grant_workstation_admin_role_on_create (bool): + Optional. Grant creator of a workstation + ``roles/workstations.policyAdmin`` role along with + ``roles/workstations.user`` role on the workstation created + by them. This allows workstation users to share access to + either their entire workstation, or individual ports. + Defaults to false. """ class Host(proto.Message): @@ -420,10 +571,13 @@ class GceInstance(proto.Message): Optional. The email address of the service account for Cloud Workstations VMs created with this configuration. When specified, be sure that the service account has - ``logginglogEntries.create`` permission on the project so it - can write logs out to Cloud Logging. If using a custom - container image, the service account must have permissions - to pull the specified image. + ``logging.logEntries.create`` and + ``monitoring.timeSeries.create`` permissions on the project + so it can write logs out to Cloud Logging. If using a custom + container image, the service account must have `Artifact + Registry + Reader `__ + permission to pull the specified image. If you as the administrator want to be able to ``ssh`` into the underlying VM, you need to set this value to a service @@ -438,8 +592,7 @@ class GceInstance(proto.Message): service_account_scopes (MutableSequence[str]): Optional. Scopes to grant to the [service_account][google.cloud.workstations.v1.WorkstationConfig.Host.GceInstance.service_account]. - Various scopes are automatically added based on feature - usage. When specified, users of workstations under this + When specified, users of workstations under this configuration must have ``iam.serviceAccounts.actAs`` on the service account. tags (MutableSequence[str]): @@ -469,9 +622,11 @@ class GceInstance(proto.Message): addresses). enable_nested_virtualization (bool): Optional. Whether to enable nested virtualization on Cloud - Workstations VMs created under this workstation + Workstations VMs created using this workstation configuration. + Defaults to false. + Nested virtualization lets you run virtual machine (VM) instances inside your workstation. Before enabling nested virtualization, consider the following important @@ -494,15 +649,6 @@ class GceInstance(proto.Message): enabled on workstation configurations that specify a [machine_type][google.cloud.workstations.v1.WorkstationConfig.Host.GceInstance.machine_type] in the N1 or N2 machine series. - - **GPUs**: nested virtualization may not be enabled on - workstation configurations with accelerators. - - **Operating System**: Because `Container-Optimized - OS `__ - does not support nested virtualization, when nested - virtualization is enabled, the underlying Compute Engine - VM instances boot from an `Ubuntu - LTS `__ - image. shielded_instance_config (google.cloud.workstations_v1.types.WorkstationConfig.Host.GceInstance.GceShieldedInstanceConfig): Optional. A set of Compute Engine Shielded instance options. @@ -513,6 +659,41 @@ class GceInstance(proto.Message): Optional. The size of the boot disk for the VM in gigabytes (GB). The minimum boot disk size is ``30`` GB. Defaults to ``50`` GB. + accelerators (MutableSequence[google.cloud.workstations_v1.types.WorkstationConfig.Host.GceInstance.Accelerator]): + Optional. A list of the type and count of + accelerator cards attached to the instance. + boost_configs (MutableSequence[google.cloud.workstations_v1.types.WorkstationConfig.Host.GceInstance.BoostConfig]): + Optional. A list of the boost configurations + that workstations created using this workstation + configuration are allowed to use. If specified, + users will have the option to choose from the + list of boost configs when starting a + workstation. + disable_ssh (bool): + Optional. Whether to disable SSH access to + the VM. + vm_tags (MutableMapping[str, str]): + Optional. Resource manager tags to be bound to this + instance. Tag keys and values have the same definition as + `resource manager + tags `__. + Keys must be in the format ``tagKeys/{tag_key_id}``, and + values are in the format ``tagValues/456``. + startup_script_uri (str): + Optional. Link to the startup script stored in Cloud + Storage. This script will be run on the host workstation VM + when the VM is created. The URI must be of the form + gs://{bucket-name}/{object-name}. If specifying a startup + script, the service account must have `Permission to access + the bucket and script file in Cloud + Storage `__. + Otherwise, the script must be publicly accessible. Note that + the service regularly updates the OS version of the host VM, + and it is the responsibility of the user to ensure the + script stays compatible with the OS version. + instance_metadata (MutableMapping[str, str]): + Optional. Custom metadata to apply to Compute + Engine instances. """ class GceShieldedInstanceConfig(proto.Message): @@ -557,6 +738,118 @@ class GceConfidentialInstanceConfig(proto.Message): number=1, ) + class Accelerator(proto.Message): + r"""An accelerator card attached to the instance. + + Attributes: + type_ (str): + Optional. Type of accelerator resource to attach to the + instance, for example, ``"nvidia-tesla-p100"``. + count (int): + Optional. Number of accelerator cards exposed + to the instance. + """ + + type_: str = proto.Field( + proto.STRING, + number=1, + ) + count: int = proto.Field( + proto.INT32, + number=2, + ) + + class BoostConfig(proto.Message): + r"""A boost configuration is a set of resources that a + workstation can use to increase its performance. If you specify + a boost configuration, upon startup, workstation users can + choose to use a VM provisioned under the boost config by passing + the boost config ID in the start request. If the workstation + user does not provide a boost config ID in the start request, + the system will choose a VM from the pool provisioned under the + default config. + + Attributes: + id (str): + Required. The ID to be used for the boost + configuration. + machine_type (str): + Optional. The type of machine that boosted VM instances will + use—for example, ``e2-standard-4``. For more information + about machine types that Cloud Workstations supports, see + the list of `available machine + types `__. + Defaults to ``e2-standard-4``. + accelerators (MutableSequence[google.cloud.workstations_v1.types.WorkstationConfig.Host.GceInstance.Accelerator]): + Optional. A list of the type and count of accelerator cards + attached to the boost instance. Defaults to ``none``. + boot_disk_size_gb (int): + Optional. The size of the boot disk for the VM in gigabytes + (GB). The minimum boot disk size is ``30`` GB. Defaults to + ``50`` GB. + enable_nested_virtualization (bool): + Optional. Whether to enable nested virtualization on boosted + Cloud Workstations VMs running using this boost + configuration. + + Defaults to false. + + Nested virtualization lets you run virtual machine (VM) + instances inside your workstation. Before enabling nested + virtualization, consider the following important + considerations. Cloud Workstations instances are subject to + the `same restrictions as Compute Engine + instances `__: + + - **Organization policy**: projects, folders, or + organizations may be restricted from creating nested VMs + if the **Disable VM nested virtualization** constraint is + enforced in the organization policy. For more information, + see the Compute Engine section, `Checking whether nested + virtualization is + allowed `__. + - **Performance**: nested VMs might experience a 10% or + greater decrease in performance for workloads that are + CPU-bound and possibly greater than a 10% decrease for + workloads that are input/output bound. + - **Machine Type**: nested virtualization can only be + enabled on boost configurations that specify a + [machine_type][google.cloud.workstations.v1.WorkstationConfig.Host.GceInstance.BoostConfig.machine_type] + in the N1 or N2 machine series. + pool_size (int): + Optional. The number of boost VMs that the system should + keep idle so that workstations can be boosted quickly. + Defaults to ``0``. + """ + + id: str = proto.Field( + proto.STRING, + number=1, + ) + machine_type: str = proto.Field( + proto.STRING, + number=2, + ) + accelerators: MutableSequence[ + "WorkstationConfig.Host.GceInstance.Accelerator" + ] = proto.RepeatedField( + proto.MESSAGE, + number=3, + message="WorkstationConfig.Host.GceInstance.Accelerator", + ) + boot_disk_size_gb: int = proto.Field( + proto.INT32, + number=4, + ) + enable_nested_virtualization: bool = proto.Field( + proto.BOOL, + number=7, + ) + pool_size: int = proto.Field( + proto.INT32, + number=5, + ) + machine_type: str = proto.Field( proto.STRING, number=1, @@ -603,6 +896,38 @@ class GceConfidentialInstanceConfig(proto.Message): proto.INT32, number=9, ) + accelerators: MutableSequence[ + "WorkstationConfig.Host.GceInstance.Accelerator" + ] = proto.RepeatedField( + proto.MESSAGE, + number=11, + message="WorkstationConfig.Host.GceInstance.Accelerator", + ) + boost_configs: MutableSequence[ + "WorkstationConfig.Host.GceInstance.BoostConfig" + ] = proto.RepeatedField( + proto.MESSAGE, + number=25, + message="WorkstationConfig.Host.GceInstance.BoostConfig", + ) + disable_ssh: bool = proto.Field( + proto.BOOL, + number=13, + ) + vm_tags: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=14, + ) + startup_script_uri: str = proto.Field( + proto.STRING, + number=26, + ) + instance_metadata: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=27, + ) gce_instance: "WorkstationConfig.Host.GceInstance" = proto.Field( proto.MESSAGE, @@ -612,7 +937,14 @@ class GceConfidentialInstanceConfig(proto.Message): ) class PersistentDirectory(proto.Message): - r"""A directory to persist across workstation sessions. + r"""A directory to persist across workstation sessions. Updates + to this field will not update existing workstations and will + only take effect on new workstations. + + This message has `oneof`_ fields (mutually exclusive fields). + For each oneof, at most one member field can be set at the same time. + Setting any member of the oneof automatically clears all other + members. .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields @@ -621,6 +953,11 @@ class PersistentDirectory(proto.Message): A PersistentDirectory backed by a Compute Engine persistent disk. + This field is a member of `oneof`_ ``directory_type``. + gce_hd (google.cloud.workstations_v1.types.WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability): + A PersistentDirectory backed by a Compute + Engine hyperdisk high availability disk. + This field is a member of `oneof`_ ``directory_type``. mount_path (str): Optional. Location of this directory in the @@ -628,8 +965,8 @@ class PersistentDirectory(proto.Message): """ class GceRegionalPersistentDisk(proto.Message): - r"""A PersistentDirectory backed by a Compute Engine regional persistent - disk. The + r"""A Persistent Directory backed by a Compute Engine regional + persistent disk. The [persistent_directories][google.cloud.workstations.v1.WorkstationConfig.persistent_directories] field is repeated, but it may contain only one entry. It creates a `persistent @@ -652,6 +989,10 @@ class GceRegionalPersistentDisk(proto.Message): the [disk_type][google.cloud.workstations.v1.WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk.disk_type] must be ``"pd-balanced"`` or ``"pd-ssd"``. + max_size_gb (int): + Optional. Maximum size in GB to which this + persistent directory can be resized. Defaults to + unlimited if not set. fs_type (str): Optional. Type of file system that the disk should be formatted with. The workstation image must support this file @@ -668,11 +1009,22 @@ class GceRegionalPersistentDisk(proto.Message): [size_gb][google.cloud.workstations.v1.WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk.size_gb] and [fs_type][google.cloud.workstations.v1.WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk.fs_type] - must be empty. + must be empty. Must be formatted as ext4 file system with no + partitions. reclaim_policy (google.cloud.workstations_v1.types.WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk.ReclaimPolicy): Optional. Whether the persistent disk should be deleted when the workstation is deleted. Valid values are ``DELETE`` and ``RETAIN``. Defaults to ``DELETE``. + archive_timeout (google.protobuf.duration_pb2.Duration): + Optional. Number of seconds to wait after initially creating + or subsequently shutting down the workstation before + converting its disk into a snapshot. This generally saves + costs at the expense of greater startup time on next + workstation start, as the service will need to create a disk + from the archival snapshot. + + A value of ``"0s"`` indicates that the disk will never be + archived. """ class ReclaimPolicy(proto.Enum): @@ -699,6 +1051,10 @@ class ReclaimPolicy(proto.Enum): proto.INT32, number=1, ) + max_size_gb: int = proto.Field( + proto.INT32, + number=7, + ) fs_type: str = proto.Field( proto.STRING, number=2, @@ -716,6 +1072,98 @@ class ReclaimPolicy(proto.Enum): number=4, enum="WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk.ReclaimPolicy", ) + archive_timeout: duration_pb2.Duration = proto.Field( + proto.MESSAGE, + number=6, + message=duration_pb2.Duration, + ) + + class GceHyperdiskBalancedHighAvailability(proto.Message): + r"""A Persistent Directory backed by a Compute Engine `Hyperdisk + Balanced High Availability + Disk `__. + This is a high-availability block storage solution that offers a + balance between performance and cost for most general-purpose + workloads. + + Attributes: + size_gb (int): + Optional. The GB capacity of a persistent home directory for + each workstation created with this configuration. Must be + empty if + [source_snapshot][google.cloud.workstations.v1.WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability.source_snapshot] + is set. + + Valid values are ``10``, ``50``, ``100``, ``200``, ``500``, + or ``1000``. Defaults to ``200``. + max_size_gb (int): + Optional. Maximum size in GB to which this + persistent directory can be resized. Defaults to + unlimited if not set. + source_snapshot (str): + Optional. Name of the snapshot to use as the source for the + disk. If set, + [size_gb][google.cloud.workstations.v1.WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability.size_gb] + must be empty. Must be formatted as ext4 file system with no + partitions. + reclaim_policy (google.cloud.workstations_v1.types.WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability.ReclaimPolicy): + Optional. Whether the persistent disk should be deleted when + the workstation is deleted. Valid values are ``DELETE`` and + ``RETAIN``. Defaults to ``DELETE``. + archive_timeout (google.protobuf.duration_pb2.Duration): + Optional. Number of seconds to wait after initially creating + or subsequently shutting down the workstation before + converting its disk into a snapshot. This generally saves + costs at the expense of greater startup time on next + workstation start, as the service will need to create a disk + from the archival snapshot. + + A value of ``"0s"`` indicates that the disk will never be + archived. + """ + + class ReclaimPolicy(proto.Enum): + r"""Value representing what should happen to the disk after the + workstation is deleted. + + Values: + RECLAIM_POLICY_UNSPECIFIED (0): + Do not use. + DELETE (1): + Delete the persistent disk when deleting the + workstation. + RETAIN (2): + Keep the persistent disk when deleting the + workstation. An administrator must manually + delete the disk. + """ + + RECLAIM_POLICY_UNSPECIFIED = 0 + DELETE = 1 + RETAIN = 2 + + size_gb: int = proto.Field( + proto.INT32, + number=1, + ) + max_size_gb: int = proto.Field( + proto.INT32, + number=5, + ) + source_snapshot: str = proto.Field( + proto.STRING, + number=2, + ) + reclaim_policy: "WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability.ReclaimPolicy" = proto.Field( + proto.ENUM, + number=3, + enum="WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability.ReclaimPolicy", + ) + archive_timeout: duration_pb2.Duration = proto.Field( + proto.MESSAGE, + number=4, + message=duration_pb2.Duration, + ) gce_pd: "WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk" = proto.Field( proto.MESSAGE, @@ -723,6 +1171,107 @@ class ReclaimPolicy(proto.Enum): oneof="directory_type", message="WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk", ) + gce_hd: "WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability" = proto.Field( + proto.MESSAGE, + number=3, + oneof="directory_type", + message="WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability", + ) + mount_path: str = proto.Field( + proto.STRING, + number=1, + ) + + class EphemeralDirectory(proto.Message): + r"""An ephemeral directory which won't persist across workstation + sessions. It is freshly created on every workstation start + operation. + + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + gce_pd (google.cloud.workstations_v1.types.WorkstationConfig.EphemeralDirectory.GcePersistentDisk): + An EphemeralDirectory backed by a Compute + Engine persistent disk. + + This field is a member of `oneof`_ ``directory_type``. + mount_path (str): + Required. Location of this directory in the + running workstation. + """ + + class GcePersistentDisk(proto.Message): + r"""An EphemeralDirectory is backed by a Compute Engine + persistent disk. + + Attributes: + disk_type (str): + Optional. Type of the disk to use. Defaults to + ``"pd-standard"``. + source_snapshot (str): + Optional. Name of the snapshot to use as the source for the + disk. Must be empty if + [source_image][google.cloud.workstations.v1.WorkstationConfig.EphemeralDirectory.GcePersistentDisk.source_image] + is set. Must be empty if + [read_only][google.cloud.workstations.v1.WorkstationConfig.EphemeralDirectory.GcePersistentDisk.read_only] + is false. Updating + [source_snapshot][google.cloud.workstations.v1.WorkstationConfig.EphemeralDirectory.GcePersistentDisk.source_snapshot] + will update content in the ephemeral directory after the + workstation is restarted. + + Only file systems supported by Container-Optimized OS (COS) + are explicitly supported. For a list of supported file + systems, see `the filesystems available in + Container-Optimized + OS `__. + + This field is mutable. + source_image (str): + Optional. Name of the disk image to use as the source for + the disk. Must be empty if + [source_snapshot][google.cloud.workstations.v1.WorkstationConfig.EphemeralDirectory.GcePersistentDisk.source_snapshot] + is set. Updating + [source_image][google.cloud.workstations.v1.WorkstationConfig.EphemeralDirectory.GcePersistentDisk.source_image] + will update content in the ephemeral directory after the + workstation is restarted. + + Only file systems supported by Container-Optimized OS (COS) + are explicitly supported. For a list of supported file + systems, please refer to the `COS + documentation `__. + + This field is mutable. + read_only (bool): + Optional. Whether the disk is read only. If true, the disk + may be shared by multiple VMs and + [source_snapshot][google.cloud.workstations.v1.WorkstationConfig.EphemeralDirectory.GcePersistentDisk.source_snapshot] + must be set. + """ + + disk_type: str = proto.Field( + proto.STRING, + number=1, + ) + source_snapshot: str = proto.Field( + proto.STRING, + number=2, + ) + source_image: str = proto.Field( + proto.STRING, + number=3, + ) + read_only: bool = proto.Field( + proto.BOOL, + number=4, + ) + + gce_pd: "WorkstationConfig.EphemeralDirectory.GcePersistentDisk" = proto.Field( + proto.MESSAGE, + number=3, + oneof="directory_type", + message="WorkstationConfig.EphemeralDirectory.GcePersistentDisk", + ) mount_path: str = proto.Field( proto.STRING, number=1, @@ -742,9 +1291,12 @@ class Container(proto.Message): images `__. If using a private image, the ``host.gceInstance.serviceAccount`` field must be specified - in the workstation configuration and must have permission to - pull the specified image. Otherwise, the image must be - publicly accessible. + in the workstation configuration. If using a custom + container image, the service account must have `Artifact + Registry + Reader `__ + permission to pull the specified image. Otherwise, the image + must be publicly accessible. command (MutableSequence[str]): Optional. If set, overrides the default ENTRYPOINT specified by the image. @@ -842,6 +1394,37 @@ class ReadinessCheck(proto.Message): number=2, ) + class PortRange(proto.Message): + r"""A PortRange defines a range of ports. Both + [first][google.cloud.workstations.v1.WorkstationConfig.PortRange.first] + and + [last][google.cloud.workstations.v1.WorkstationConfig.PortRange.last] + are inclusive. To specify a single port, both + [first][google.cloud.workstations.v1.WorkstationConfig.PortRange.first] + and + [last][google.cloud.workstations.v1.WorkstationConfig.PortRange.last] + should be the same. + + Attributes: + first (int): + Required. Starting port number for the + current range of ports. Valid ports are 22, 80, + and ports within the range 1024-65535. + last (int): + Required. Ending port number for the current + range of ports. Valid ports are 22, 80, and + ports within the range 1024-65535. + """ + + first: int = proto.Field( + proto.INT32, + number=1, + ) + last: int = proto.Field( + proto.INT32, + number=2, + ) + name: str = proto.Field( proto.STRING, number=1, @@ -897,6 +1480,10 @@ class ReadinessCheck(proto.Message): number=11, message=duration_pb2.Duration, ) + max_usable_workstations: int = proto.Field( + proto.INT32, + number=28, + ) host: Host = proto.Field( proto.MESSAGE, number=12, @@ -907,6 +1494,11 @@ class ReadinessCheck(proto.Message): number=13, message=PersistentDirectory, ) + ephemeral_directories: MutableSequence[EphemeralDirectory] = proto.RepeatedField( + proto.MESSAGE, + number=22, + message=EphemeralDirectory, + ) container: Container = proto.Field( proto.MESSAGE, number=14, @@ -935,6 +1527,23 @@ class ReadinessCheck(proto.Message): number=16, message=status_pb2.Status, ) + enable_audit_agent: bool = proto.Field( + proto.BOOL, + number=20, + ) + disable_tcp_connections: bool = proto.Field( + proto.BOOL, + number=24, + ) + allowed_ports: MutableSequence[PortRange] = proto.RepeatedField( + proto.MESSAGE, + number=25, + message=PortRange, + ) + grant_workstation_admin_role_on_create: bool = proto.Field( + proto.BOOL, + number=29, + ) class Workstation(proto.Message): @@ -943,7 +1552,7 @@ class Workstation(proto.Message): Attributes: name (str): - Full name of this workstation. + Identifier. Full name of this workstation. display_name (str): Optional. Human-readable name for this workstation. @@ -979,6 +1588,9 @@ class Workstation(proto.Message): May be sent on update and delete requests to make sure that the client has an up-to-date value before proceeding. + persistent_directories (MutableSequence[google.cloud.workstations_v1.types.Workstation.WorkstationPersistentDirectory]): + Optional. Directories to persist across + workstation sessions. state (google.cloud.workstations_v1.types.Workstation.State): Output only. Current state of the workstation. @@ -989,6 +1601,21 @@ class Workstation(proto.Message): send traffic to a different port, clients may prefix the host with the destination port in the format ``{port}-{host}``. + env (MutableMapping[str, str]): + Optional. Environment variables passed to the + workstation container's entrypoint. + kms_key (str): + Output only. The name of the Google Cloud KMS encryption key + used to encrypt this workstation. The KMS key can only be + configured in the WorkstationConfig. The expected format is + ``projects/*/locations/*/keyRings/*/cryptoKeys/*``. + source_workstation (str): + Optional. The source workstation from which + this workstation's persistent directories were + cloned on creation. + runtime_host (google.cloud.workstations_v1.types.Workstation.RuntimeHost): + Optional. Output only. Runtime host for the workstation when + in STATE_RUNNING. """ class State(proto.Enum): @@ -1017,6 +1644,78 @@ class State(proto.Enum): STATE_STOPPING = 3 STATE_STOPPED = 4 + class WorkstationPersistentDirectory(proto.Message): + r"""A directory to persist across workstation sessions. Updates + to this field will only take effect on this workstation after it + is restarted. + + Attributes: + mount_path (str): + Optional. The mount path of the persistent + directory. + size_gb (int): + Optional. Size of the persistent directory in + GB. If specified in an update request, this is + the desired size of the directory. + """ + + mount_path: str = proto.Field( + proto.STRING, + number=2, + ) + size_gb: int = proto.Field( + proto.INT32, + number=3, + ) + + class RuntimeHost(proto.Message): + r"""Runtime host for the workstation. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + gce_instance_host (google.cloud.workstations_v1.types.Workstation.RuntimeHost.GceInstanceHost): + Specifies a Compute Engine instance as the + host. + + This field is a member of `oneof`_ ``host_type``. + """ + + class GceInstanceHost(proto.Message): + r"""The Compute Engine instance host. + + Attributes: + name (str): + Optional. Output only. The name of the + Compute Engine instance. + id (str): + Optional. Output only. The ID of the Compute + Engine instance. + zone (str): + Optional. Output only. The zone of the + Compute Engine instance. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + id: str = proto.Field( + proto.STRING, + number=2, + ) + zone: str = proto.Field( + proto.STRING, + number=3, + ) + + gce_instance_host: "Workstation.RuntimeHost.GceInstanceHost" = proto.Field( + proto.MESSAGE, + number=1, + oneof="host_type", + message="Workstation.RuntimeHost.GceInstanceHost", + ) + name: str = proto.Field( proto.STRING, number=1, @@ -1067,6 +1766,13 @@ class State(proto.Enum): proto.STRING, number=9, ) + persistent_directories: MutableSequence[WorkstationPersistentDirectory] = ( + proto.RepeatedField( + proto.MESSAGE, + number=25, + message=WorkstationPersistentDirectory, + ) + ) state: State = proto.Field( proto.ENUM, number=10, @@ -1076,6 +1782,24 @@ class State(proto.Enum): proto.STRING, number=11, ) + env: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=12, + ) + kms_key: str = proto.Field( + proto.STRING, + number=15, + ) + source_workstation: str = proto.Field( + proto.STRING, + number=17, + ) + runtime_host: RuntimeHost = proto.Field( + proto.MESSAGE, + number=21, + message=RuntimeHost, + ) class GetWorkstationClusterRequest(proto.Message): @@ -1103,6 +1827,10 @@ class ListWorkstationClustersRequest(proto.Message): page_token (str): Optional. next_page_token value returned from a previous List request, if any. + filter (str): + Optional. Filter the WorkstationClusters to + be listed. Possible filters are described in + https://google.aip.dev/160. """ parent: str = proto.Field( @@ -1117,6 +1845,10 @@ class ListWorkstationClustersRequest(proto.Message): proto.STRING, number=3, ) + filter: str = proto.Field( + proto.STRING, + number=4, + ) class ListWorkstationClustersResponse(proto.Message): @@ -1165,7 +1897,7 @@ class CreateWorkstationClusterRequest(proto.Message): Required. Workstation cluster to create. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. """ @@ -1199,7 +1931,7 @@ class UpdateWorkstationClusterRequest(proto.Message): the workstation cluster should be updated. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. allow_missing (bool): Optional. If set, and the workstation cluster is not found, @@ -1236,7 +1968,7 @@ class DeleteWorkstationClusterRequest(proto.Message): delete. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not apply it. + preview the result, but do not apply it. etag (str): Optional. If set, the request will be rejected if the latest version of the @@ -1293,6 +2025,10 @@ class ListWorkstationConfigsRequest(proto.Message): page_token (str): Optional. next_page_token value returned from a previous List request, if any. + filter (str): + Optional. Filter the WorkstationConfigs to be + listed. Possible filters are described in + https://google.aip.dev/160. """ parent: str = proto.Field( @@ -1307,6 +2043,10 @@ class ListWorkstationConfigsRequest(proto.Message): proto.STRING, number=3, ) + filter: str = proto.Field( + proto.STRING, + number=4, + ) class ListWorkstationConfigsResponse(proto.Message): @@ -1412,10 +2152,11 @@ class CreateWorkstationConfigRequest(proto.Message): Required. ID to use for the workstation configuration. workstation_config (google.cloud.workstations_v1.types.WorkstationConfig): - Required. Config to create. + Required. Workstation configuration to + create. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. """ @@ -1443,13 +2184,14 @@ class UpdateWorkstationConfigRequest(proto.Message): Attributes: workstation_config (google.cloud.workstations_v1.types.WorkstationConfig): - Required. Config to update. + Required. Workstation configuration to + update. update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. Mask specifying which fields in the workstation configuration should be updated. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. allow_missing (bool): Optional. If set and the workstation configuration is not @@ -1486,7 +2228,7 @@ class DeleteWorkstationConfigRequest(proto.Message): configuration to delete. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. etag (str): Optional. If set, the request is rejected if @@ -1543,6 +2285,10 @@ class ListWorkstationsRequest(proto.Message): page_token (str): Optional. next_page_token value returned from a previous List request, if any. + filter (str): + Optional. Filter the Workstations to be + listed. Possible filters are described in + https://google.aip.dev/160. """ parent: str = proto.Field( @@ -1557,6 +2303,10 @@ class ListWorkstationsRequest(proto.Message): proto.STRING, number=3, ) + filter: str = proto.Field( + proto.STRING, + number=4, + ) class ListWorkstationsResponse(proto.Message): @@ -1661,10 +2411,16 @@ class CreateWorkstationRequest(proto.Message): workstation_id (str): Required. ID to use for the workstation. workstation (google.cloud.workstations_v1.types.Workstation): - Required. Workstation to create. + Required. Workstation to create. If source_workstation is + specified, the user must have + ``workstations.workstations.use`` permission on the source + workstation, and the Cloud Workstations Service Agent for + the project where you are creating the new workstation must + have compute.disks.createSnapshot and + compute.snapshots.useReadOnly on the source project. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. """ @@ -1695,15 +2451,15 @@ class UpdateWorkstationRequest(proto.Message): Required. Workstation to update. update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. Mask specifying which fields in the - workstation configuration should be updated. + workstation should be updated. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. allow_missing (bool): - Optional. If set and the workstation configuration is not - found, a new workstation configuration is created. In this - situation, update_mask is ignored. + Optional. If set and the workstation is not found, a new + workstation is created. In this situation, update_mask is + ignored. """ workstation: "Workstation" = proto.Field( @@ -1734,7 +2490,7 @@ class DeleteWorkstationRequest(proto.Message): Required. Name of the workstation to delete. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. etag (str): Optional. If set, the request will be @@ -1765,13 +2521,17 @@ class StartWorkstationRequest(proto.Message): Required. Name of the workstation to start. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. etag (str): Optional. If set, the request will be rejected if the latest version of the workstation on the server does not have this ETag. + boost_config (str): + Optional. If set, the workstation starts + using the boost configuration with the specified + ID. """ name: str = proto.Field( @@ -1786,6 +2546,10 @@ class StartWorkstationRequest(proto.Message): proto.STRING, number=3, ) + boost_config: str = proto.Field( + proto.STRING, + number=4, + ) class StopWorkstationRequest(proto.Message): @@ -1796,7 +2560,7 @@ class StopWorkstationRequest(proto.Message): Required. Name of the workstation to stop. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. etag (str): Optional. If set, the request will be @@ -1848,6 +2612,13 @@ class GenerateAccessTokenRequest(proto.Message): workstation (str): Required. Name of the workstation for which the access token should be generated. + port (int): + Optional. Port for which the access token should be + generated. If specified, the generated access token grants + access only to the specified port of the workstation. If + specified, values must be within the range [1 - 65535]. If + not specified, the generated access token grants access to + all ports of the workstation. """ expire_time: timestamp_pb2.Timestamp = proto.Field( @@ -1866,6 +2637,10 @@ class GenerateAccessTokenRequest(proto.Message): proto.STRING, number=1, ) + port: int = proto.Field( + proto.INT32, + number=4, + ) class GenerateAccessTokenResponse(proto.Message): diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/__init__.py b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/__init__.py index 1afa425e3c15..1a0ed5c51123 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/__init__.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/__init__.py @@ -47,6 +47,8 @@ ListWorkstationsRequest, ListWorkstationsResponse, OperationMetadata, + PushCredentialsMetadata, + PushCredentialsRequest, StartWorkstationRequest, StopWorkstationRequest, UpdateWorkstationClusterRequest, @@ -164,6 +166,8 @@ def _get_version(dependency_name): "ListWorkstationsRequest", "ListWorkstationsResponse", "OperationMetadata", + "PushCredentialsMetadata", + "PushCredentialsRequest", "StartWorkstationRequest", "StopWorkstationRequest", "UpdateWorkstationClusterRequest", diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/gapic_metadata.json b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/gapic_metadata.json index cf8a80968ec1..b5e2753ac53e 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/gapic_metadata.json +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/gapic_metadata.json @@ -85,6 +85,11 @@ "list_workstations" ] }, + "PushCredentials": { + "methods": [ + "push_credentials" + ] + }, "StartWorkstation": { "methods": [ "start_workstation" @@ -190,6 +195,11 @@ "list_workstations" ] }, + "PushCredentials": { + "methods": [ + "push_credentials" + ] + }, "StartWorkstation": { "methods": [ "start_workstation" @@ -295,6 +305,11 @@ "list_workstations" ] }, + "PushCredentials": { + "methods": [ + "push_credentials" + ] + }, "StartWorkstation": { "methods": [ "start_workstation" diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/async_client.py b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/async_client.py index 66e4284718ab..d9eae3bc2993 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/async_client.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/async_client.py @@ -1413,7 +1413,9 @@ async def sample_create_workstation_config(): on the ``request`` instance; if ``request`` is provided, this should not be set. workstation_config (:class:`google.cloud.workstations_v1beta.types.WorkstationConfig`): - Required. Config to create. + Required. Workstation configuration + to create. + This corresponds to the ``workstation_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -1562,7 +1564,9 @@ async def sample_update_workstation_config(): The request object. Request message for UpdateWorkstationConfig. workstation_config (:class:`google.cloud.workstations_v1beta.types.WorkstationConfig`): - Required. Config to update. + Required. Workstation configuration + to update. + This corresponds to the ``workstation_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -2221,7 +2225,14 @@ async def sample_create_workstation(): on the ``request`` instance; if ``request`` is provided, this should not be set. workstation (:class:`google.cloud.workstations_v1beta.types.Workstation`): - Required. Workstation to create. + Required. Workstation to create. If source_workstation + is specified, the user must have + ``workstations.workstations.use`` permission on the + source workstation, and the Cloud Workstations Service + Agent for the project where you are creating the new + workstation must have compute.disks.createSnapshot and + compute.snapshots.useReadOnly on the source project. + This corresponds to the ``workstation`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -2363,8 +2374,8 @@ async def sample_update_workstation(): should not be set. update_mask (:class:`google.protobuf.field_mask_pb2.FieldMask`): Required. Mask specifying which - fields in the workstation configuration - should be updated. + fields in the workstation should be + updated. This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this @@ -2839,7 +2850,8 @@ async def generate_access_token( ) -> workstations.GenerateAccessTokenResponse: r"""Returns a short-lived credential that can be used to send authenticated and authorized traffic to a - workstation. + workstation. Once generated this token cannot be revoked + and is good for the lifetime of the token. .. code-block:: python @@ -2944,6 +2956,137 @@ async def sample_generate_access_token(): # Done; return the response. return response + async def push_credentials( + self, + request: Optional[Union[workstations.PushCredentialsRequest, dict]] = None, + *, + workstation: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), + ) -> operation_async.AsyncOperation: + r"""Pushes credentials to a running workstation on behalf of a user. + Once complete, supported credential types + (application_default_credentials) are made available to + processes running in the user container. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import workstations_v1beta + + async def sample_push_credentials(): + # Create a client + client = workstations_v1beta.WorkstationsAsyncClient() + + # Initialize request argument(s) + request = workstations_v1beta.PushCredentialsRequest( + workstation="workstation_value", + ) + + # Make the request + operation = await client.push_credentials(request=request) + + print("Waiting for operation to complete...") + + response = await operation.result() + + # Handle the response + print(response) + + Args: + request (Optional[Union[google.cloud.workstations_v1beta.types.PushCredentialsRequest, dict]]): + The request object. Request message for PushCredentials. + workstation (:class:`str`): + Required. Name of the workstation for + which the credentials should be pushed. + + This corresponds to the ``workstation`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry_async.AsyncRetry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. + + Returns: + google.api_core.operation_async.AsyncOperation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.workstations_v1beta.types.Workstation` + A single instance of a developer workstation with its + own persistent storage. + + """ + # Create or coerce a protobuf request object. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + flattened_params = [workstation] + has_flattened_params = ( + len([param for param in flattened_params if param is not None]) > 0 + ) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, workstations.PushCredentialsRequest): + request = workstations.PushCredentialsRequest(request) + + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if workstation is not None: + request.workstation = workstation + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._client._transport._wrapped_methods[ + self._client._transport.push_credentials + ] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("workstation", request.workstation),) + ), + ) + + # Validate the universe domain. + self._client._validate_universe_domain() + + # Send the request. + response = await rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation_async.from_gapic( + response, + self._client._transport.operations_client, + workstations.Workstation, + metadata_type=workstations.PushCredentialsMetadata, + ) + + # Done; return the response. + return response + async def list_operations( self, request: Optional[Union[operations_pb2.ListOperationsRequest, dict]] = None, diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/client.py b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/client.py index d363529917b4..1fdbed3608f8 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/client.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/client.py @@ -1876,7 +1876,9 @@ def sample_create_workstation_config(): on the ``request`` instance; if ``request`` is provided, this should not be set. workstation_config (google.cloud.workstations_v1beta.types.WorkstationConfig): - Required. Config to create. + Required. Workstation configuration + to create. + This corresponds to the ``workstation_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -2024,7 +2026,9 @@ def sample_update_workstation_config(): The request object. Request message for UpdateWorkstationConfig. workstation_config (google.cloud.workstations_v1beta.types.WorkstationConfig): - Required. Config to update. + Required. Workstation configuration + to update. + This corresponds to the ``workstation_config`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -2672,7 +2676,14 @@ def sample_create_workstation(): on the ``request`` instance; if ``request`` is provided, this should not be set. workstation (google.cloud.workstations_v1beta.types.Workstation): - Required. Workstation to create. + Required. Workstation to create. If source_workstation + is specified, the user must have + ``workstations.workstations.use`` permission on the + source workstation, and the Cloud Workstations Service + Agent for the project where you are creating the new + workstation must have compute.disks.createSnapshot and + compute.snapshots.useReadOnly on the source project. + This corresponds to the ``workstation`` field on the ``request`` instance; if ``request`` is provided, this should not be set. @@ -2811,8 +2822,8 @@ def sample_update_workstation(): should not be set. update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. Mask specifying which - fields in the workstation configuration - should be updated. + fields in the workstation should be + updated. This corresponds to the ``update_mask`` field on the ``request`` instance; if ``request`` is provided, this @@ -3275,7 +3286,8 @@ def generate_access_token( ) -> workstations.GenerateAccessTokenResponse: r"""Returns a short-lived credential that can be used to send authenticated and authorized traffic to a - workstation. + workstation. Once generated this token cannot be revoked + and is good for the lifetime of the token. .. code-block:: python @@ -3377,6 +3389,134 @@ def sample_generate_access_token(): # Done; return the response. return response + def push_credentials( + self, + request: Optional[Union[workstations.PushCredentialsRequest, dict]] = None, + *, + workstation: Optional[str] = None, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Union[float, object] = gapic_v1.method.DEFAULT, + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), + ) -> operation.Operation: + r"""Pushes credentials to a running workstation on behalf of a user. + Once complete, supported credential types + (application_default_credentials) are made available to + processes running in the user container. + + .. code-block:: python + + # This snippet has been automatically generated and should be regarded as a + # code template only. + # It will require modifications to work: + # - It may require correct/in-range values for request initialization. + # - It may require specifying regional endpoints when creating the service + # client as shown in: + # https://googleapis.dev/python/google-api-core/latest/client_options.html + from google.cloud import workstations_v1beta + + def sample_push_credentials(): + # Create a client + client = workstations_v1beta.WorkstationsClient() + + # Initialize request argument(s) + request = workstations_v1beta.PushCredentialsRequest( + workstation="workstation_value", + ) + + # Make the request + operation = client.push_credentials(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + + Args: + request (Union[google.cloud.workstations_v1beta.types.PushCredentialsRequest, dict]): + The request object. Request message for PushCredentials. + workstation (str): + Required. Name of the workstation for + which the credentials should be pushed. + + This corresponds to the ``workstation`` field + on the ``request`` instance; if ``request`` is provided, this + should not be set. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. + + Returns: + google.api_core.operation.Operation: + An object representing a long-running operation. + + The result type for the operation will be + :class:`google.cloud.workstations_v1beta.types.Workstation` + A single instance of a developer workstation with its + own persistent storage. + + """ + # Create or coerce a protobuf request object. + # - Quick check: If we got a request object, we should *not* have + # gotten any keyword arguments that map to the request. + flattened_params = [workstation] + has_flattened_params = ( + len([param for param in flattened_params if param is not None]) > 0 + ) + if request is not None and has_flattened_params: + raise ValueError( + "If the `request` argument is set, then none of " + "the individual field arguments should be set." + ) + + # - Use the request object if provided (there's no risk of modifying the input as + # there are no flattened fields), or create one. + if not isinstance(request, workstations.PushCredentialsRequest): + request = workstations.PushCredentialsRequest(request) + # If we have keyword arguments corresponding to fields on the + # request, apply these. + if workstation is not None: + request.workstation = workstation + + # Wrap the RPC method; this adds retry and timeout information, + # and friendly error handling. + rpc = self._transport._wrapped_methods[self._transport.push_credentials] + + # Certain fields should be provided within the metadata header; + # add these here. + metadata = tuple(metadata) + ( + gapic_v1.routing_header.to_grpc_metadata( + (("workstation", request.workstation),) + ), + ) + + # Validate the universe domain. + self._validate_universe_domain() + + # Send the request. + response = rpc( + request, + retry=retry, + timeout=timeout, + metadata=metadata, + ) + + # Wrap the response in an operation future. + response = operation.from_gapic( + response, + self._transport.operations_client, + workstations.Workstation, + metadata_type=workstations.PushCredentialsMetadata, + ) + + # Done; return the response. + return response + def __enter__(self) -> "WorkstationsClient": return self diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/base.py b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/base.py index 07fc1cb5cccb..65bf9beb00c7 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/base.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/base.py @@ -329,6 +329,11 @@ def _prep_wrapped_messages(self, client_info): default_timeout=60.0, client_info=client_info, ), + self.push_credentials: gapic_v1.method.wrap_method( + self.push_credentials, + default_timeout=None, + client_info=client_info, + ), self.get_iam_policy: gapic_v1.method.wrap_method( self.get_iam_policy, default_timeout=None, @@ -582,6 +587,15 @@ def generate_access_token( ]: raise NotImplementedError() + @property + def push_credentials( + self, + ) -> Callable[ + [workstations.PushCredentialsRequest], + Union[operations_pb2.Operation, Awaitable[operations_pb2.Operation]], + ]: + raise NotImplementedError() + @property def list_operations( self, diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/grpc.py b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/grpc.py index 6f9ae8d92ae6..43ef131b8549 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/grpc.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/grpc.py @@ -900,7 +900,8 @@ def generate_access_token( Returns a short-lived credential that can be used to send authenticated and authorized traffic to a - workstation. + workstation. Once generated this token cannot be revoked + and is good for the lifetime of the token. Returns: Callable[[~.GenerateAccessTokenRequest], @@ -920,6 +921,35 @@ def generate_access_token( ) return self._stubs["generate_access_token"] + @property + def push_credentials( + self, + ) -> Callable[[workstations.PushCredentialsRequest], operations_pb2.Operation]: + r"""Return a callable for the push credentials method over gRPC. + + Pushes credentials to a running workstation on behalf of a user. + Once complete, supported credential types + (application_default_credentials) are made available to + processes running in the user container. + + Returns: + Callable[[~.PushCredentialsRequest], + ~.Operation]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "push_credentials" not in self._stubs: + self._stubs["push_credentials"] = self._logged_channel.unary_unary( + "/google.cloud.workstations.v1beta.Workstations/PushCredentials", + request_serializer=workstations.PushCredentialsRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["push_credentials"] + def close(self): self._logged_channel.close() diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/grpc_asyncio.py b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/grpc_asyncio.py index 7eedf7168ed1..9547c1a026d3 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/grpc_asyncio.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/grpc_asyncio.py @@ -929,7 +929,8 @@ def generate_access_token( Returns a short-lived credential that can be used to send authenticated and authorized traffic to a - workstation. + workstation. Once generated this token cannot be revoked + and is good for the lifetime of the token. Returns: Callable[[~.GenerateAccessTokenRequest], @@ -949,6 +950,37 @@ def generate_access_token( ) return self._stubs["generate_access_token"] + @property + def push_credentials( + self, + ) -> Callable[ + [workstations.PushCredentialsRequest], Awaitable[operations_pb2.Operation] + ]: + r"""Return a callable for the push credentials method over gRPC. + + Pushes credentials to a running workstation on behalf of a user. + Once complete, supported credential types + (application_default_credentials) are made available to + processes running in the user container. + + Returns: + Callable[[~.PushCredentialsRequest], + Awaitable[~.Operation]]: + A function that, when called, will call the underlying RPC + on the server. + """ + # Generate a "stub function" on-the-fly which will actually make + # the request. + # gRPC handles serialization and deserialization, so we just need + # to pass in the functions for each. + if "push_credentials" not in self._stubs: + self._stubs["push_credentials"] = self._logged_channel.unary_unary( + "/google.cloud.workstations.v1beta.Workstations/PushCredentials", + request_serializer=workstations.PushCredentialsRequest.serialize, + response_deserializer=operations_pb2.Operation.FromString, + ) + return self._stubs["push_credentials"] + def _prep_wrapped_messages(self, client_info): """Precompute the wrapped methods, overriding the base class method to use async wrappers.""" self._wrapped_methods = { @@ -1133,6 +1165,11 @@ def _prep_wrapped_messages(self, client_info): default_timeout=60.0, client_info=client_info, ), + self.push_credentials: self._wrap_method( + self.push_credentials, + default_timeout=None, + client_info=client_info, + ), self.get_iam_policy: self._wrap_method( self.get_iam_policy, default_timeout=None, diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/rest.py b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/rest.py index 4483c48249a7..956c7fe4e514 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/rest.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/rest.py @@ -198,6 +198,14 @@ def post_list_workstations(self, response): logging.log(f"Received response: {response}") return response + def pre_push_credentials(self, request, metadata): + logging.log(f"Received request: {request}") + return request, metadata + + def post_push_credentials(self, response): + logging.log(f"Received response: {response}") + return response + def pre_start_workstation(self, request, metadata): logging.log(f"Received request: {request}") return request, metadata @@ -993,6 +1001,54 @@ def post_list_workstations_with_metadata( """ return response, metadata + def pre_push_credentials( + self, + request: workstations.PushCredentialsRequest, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[ + workstations.PushCredentialsRequest, Sequence[Tuple[str, Union[str, bytes]]] + ]: + """Pre-rpc interceptor for push_credentials + + Override in a subclass to manipulate the request or metadata + before they are sent to the Workstations server. + """ + return request, metadata + + def post_push_credentials( + self, response: operations_pb2.Operation + ) -> operations_pb2.Operation: + """Post-rpc interceptor for push_credentials + + DEPRECATED. Please use the `post_push_credentials_with_metadata` + interceptor instead. + + Override in a subclass to read or manipulate the response + after it is returned by the Workstations server but before + it is returned to user code. This `post_push_credentials` interceptor runs + before the `post_push_credentials_with_metadata` interceptor. + """ + return response + + def post_push_credentials_with_metadata( + self, + response: operations_pb2.Operation, + metadata: Sequence[Tuple[str, Union[str, bytes]]], + ) -> Tuple[operations_pb2.Operation, Sequence[Tuple[str, Union[str, bytes]]]]: + """Post-rpc interceptor for push_credentials + + Override in a subclass to read or manipulate the response or metadata after it + is returned by the Workstations server but before it is returned to user code. + + We recommend only using this `post_push_credentials_with_metadata` + interceptor in new development instead of the `post_push_credentials` interceptor. + When both interceptors are used, this `post_push_credentials_with_metadata` interceptor runs after the + `post_push_credentials` interceptor. The (possibly modified) response returned by + `post_push_credentials` will be passed to + `post_push_credentials_with_metadata`. + """ + return response, metadata + def pre_start_workstation( self, request: workstations.StartWorkstationRequest, @@ -3820,6 +3876,159 @@ def __call__( ) return resp + class _PushCredentials( + _BaseWorkstationsRestTransport._BasePushCredentials, WorkstationsRestStub + ): + def __hash__(self): + return hash("WorkstationsRestTransport.PushCredentials") + + @staticmethod + def _get_response( + host, + metadata, + query_params, + session, + timeout, + transcoded_request, + body=None, + ): + uri = transcoded_request["uri"] + method = transcoded_request["method"] + headers = dict(metadata) + headers["Content-Type"] = "application/json" + response = getattr(session, method)( + "{host}{uri}".format(host=host, uri=uri), + timeout=timeout, + headers=headers, + params=rest_helpers.flatten_query_params(query_params, strict=True), + data=body, + ) + return response + + def __call__( + self, + request: workstations.PushCredentialsRequest, + *, + retry: OptionalRetry = gapic_v1.method.DEFAULT, + timeout: Optional[float] = None, + metadata: Sequence[Tuple[str, Union[str, bytes]]] = (), + ) -> operations_pb2.Operation: + r"""Call the push credentials method over HTTP. + + Args: + request (~.workstations.PushCredentialsRequest): + The request object. Request message for PushCredentials. + retry (google.api_core.retry.Retry): Designation of what errors, if any, + should be retried. + timeout (float): The timeout for this request. + metadata (Sequence[Tuple[str, Union[str, bytes]]]): Key/value pairs which should be + sent along with the request as metadata. Normally, each value must be of type `str`, + but for metadata keys ending with the suffix `-bin`, the corresponding values must + be of type `bytes`. + + Returns: + ~.operations_pb2.Operation: + This resource represents a + long-running operation that is the + result of a network API call. + + """ + + http_options = ( + _BaseWorkstationsRestTransport._BasePushCredentials._get_http_options() + ) + + request, metadata = self._interceptor.pre_push_credentials( + request, metadata + ) + transcoded_request = _BaseWorkstationsRestTransport._BasePushCredentials._get_transcoded_request( + http_options, request + ) + + body = _BaseWorkstationsRestTransport._BasePushCredentials._get_request_body_json( + transcoded_request + ) + + # Jsonify the query params + query_params = _BaseWorkstationsRestTransport._BasePushCredentials._get_query_params_json( + transcoded_request + ) + + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + request_url = "{host}{uri}".format( + host=self._host, uri=transcoded_request["uri"] + ) + method = transcoded_request["method"] + try: + request_payload = type(request).to_json(request) + except: + request_payload = None + http_request = { + "payload": request_payload, + "requestMethod": method, + "requestUrl": request_url, + "headers": dict(metadata), + } + _LOGGER.debug( + f"Sending request for google.cloud.workstations_v1beta.WorkstationsClient.PushCredentials", + extra={ + "serviceName": "google.cloud.workstations.v1beta.Workstations", + "rpcName": "PushCredentials", + "httpRequest": http_request, + "metadata": http_request["headers"], + }, + ) + + # Send the request + response = WorkstationsRestTransport._PushCredentials._get_response( + self._host, + metadata, + query_params, + self._session, + timeout, + transcoded_request, + body, + ) + + # In case of error, raise the appropriate core_exceptions.GoogleAPICallError exception + # subclass. + if response.status_code >= 400: + raise core_exceptions.from_http_response(response) + + # Return the response + resp = operations_pb2.Operation() + json_format.Parse(response.content, resp, ignore_unknown_fields=True) + + resp = self._interceptor.post_push_credentials(resp) + response_metadata = [(k, str(v)) for k, v in response.headers.items()] + resp, _ = self._interceptor.post_push_credentials_with_metadata( + resp, response_metadata + ) + if CLIENT_LOGGING_SUPPORTED and _LOGGER.isEnabledFor( + logging.DEBUG + ): # pragma: NO COVER + try: + response_payload = json_format.MessageToJson(resp) + except: + response_payload = None + http_response = { + "payload": response_payload, + "headers": dict(response.headers), + "status": response.status_code, + } + _LOGGER.debug( + "Received response for google.cloud.workstations_v1beta.WorkstationsClient.push_credentials", + extra={ + "serviceName": "google.cloud.workstations.v1beta.Workstations", + "rpcName": "PushCredentials", + "metadata": http_response["headers"], + "httpResponse": http_response, + }, + ) + return resp + class _StartWorkstation( _BaseWorkstationsRestTransport._BaseStartWorkstation, WorkstationsRestStub ): @@ -4752,6 +4961,14 @@ def list_workstations( # In C++ this would require a dynamic_cast return self._ListWorkstations(self._session, self._host, self._interceptor) # type: ignore + @property + def push_credentials( + self, + ) -> Callable[[workstations.PushCredentialsRequest], operations_pb2.Operation]: + # The return type is fine, but mypy isn't sophisticated enough to determine what's going on here. + # In C++ this would require a dynamic_cast + return self._PushCredentials(self._session, self._host, self._interceptor) # type: ignore + @property def start_workstation( self, diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/rest_base.py b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/rest_base.py index 1e7a1ee489de..a08657a0771d 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/rest_base.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/services/workstations/transports/rest_base.py @@ -844,6 +844,63 @@ def _get_query_params_json(transcoded_request): query_params["$alt"] = "json;enum-encoding=int" return query_params + class _BasePushCredentials: + def __hash__(self): # pragma: NO COVER + return NotImplementedError("__hash__ must be implemented.") + + __REQUIRED_FIELDS_DEFAULT_VALUES: Dict[str, Any] = {} + + @classmethod + def _get_unset_required_fields(cls, message_dict): + return { + k: v + for k, v in cls.__REQUIRED_FIELDS_DEFAULT_VALUES.items() + if k not in message_dict + } + + @staticmethod + def _get_http_options(): + http_options: List[Dict[str, str]] = [ + { + "method": "post", + "uri": "/v1beta/{workstation=projects/*/locations/*/workstationClusters/*/workstationConfigs/*/workstations/*}:pushCredentials", + "body": "*", + }, + ] + return http_options + + @staticmethod + def _get_transcoded_request(http_options, request): + pb_request = workstations.PushCredentialsRequest.pb(request) + transcoded_request = path_template.transcode(http_options, pb_request) + return transcoded_request + + @staticmethod + def _get_request_body_json(transcoded_request): + # Jsonify the request body + + body = json_format.MessageToJson( + transcoded_request["body"], use_integers_for_enums=True + ) + return body + + @staticmethod + def _get_query_params_json(transcoded_request): + query_params = json.loads( + json_format.MessageToJson( + transcoded_request["query_params"], + use_integers_for_enums=True, + ) + ) + query_params.update( + _BaseWorkstationsRestTransport._BasePushCredentials._get_unset_required_fields( + query_params + ) + ) + + query_params["$alt"] = "json;enum-encoding=int" + return query_params + class _BaseStartWorkstation: def __hash__(self): # pragma: NO COVER return NotImplementedError("__hash__ must be implemented.") diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/types/__init__.py b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/types/__init__.py index bcd583094bb2..b8a909b3eec0 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/types/__init__.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/types/__init__.py @@ -36,6 +36,8 @@ ListWorkstationsRequest, ListWorkstationsResponse, OperationMetadata, + PushCredentialsMetadata, + PushCredentialsRequest, StartWorkstationRequest, StopWorkstationRequest, UpdateWorkstationClusterRequest, @@ -69,6 +71,8 @@ "ListWorkstationsRequest", "ListWorkstationsResponse", "OperationMetadata", + "PushCredentialsMetadata", + "PushCredentialsRequest", "StartWorkstationRequest", "StopWorkstationRequest", "UpdateWorkstationClusterRequest", diff --git a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/types/workstations.py b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/types/workstations.py index 5873eb7bffce..c901224d4c35 100644 --- a/packages/google-cloud-workstations/google/cloud/workstations_v1beta/types/workstations.py +++ b/packages/google-cloud-workstations/google/cloud/workstations_v1beta/types/workstations.py @@ -55,6 +55,8 @@ "StopWorkstationRequest", "GenerateAccessTokenRequest", "GenerateAccessTokenResponse", + "PushCredentialsRequest", + "PushCredentialsMetadata", "OperationMetadata", }, ) @@ -68,7 +70,8 @@ class WorkstationCluster(proto.Message): Attributes: name (str): - Full name of this workstation cluster. + Identifier. Full name of this workstation + cluster. display_name (str): Optional. Human-readable name for this workstation cluster. @@ -120,14 +123,54 @@ class WorkstationCluster(proto.Message): private_cluster_config (google.cloud.workstations_v1beta.types.WorkstationCluster.PrivateClusterConfig): Optional. Configuration for private workstation cluster. + domain_config (google.cloud.workstations_v1beta.types.WorkstationCluster.DomainConfig): + Optional. Configuration options for a custom + domain. degraded (bool): Output only. Whether this workstation cluster is in degraded mode, in which case it may require user action to restore - full functionality. Details can be found in - [conditions][google.cloud.workstations.v1beta.WorkstationCluster.conditions]. + full functionality. The + [conditions][google.cloud.workstations.v1beta.WorkstationCluster.conditions] + field contains detailed information about the status of the + cluster. conditions (MutableSequence[google.rpc.status_pb2.Status]): Output only. Status conditions describing the workstation cluster's current state. + satisfies_pzs (bool): + Output only. Reserved for future use. + satisfies_pzi (bool): + Output only. Reserved for future use. + tags (MutableMapping[str, str]): + Optional. Input only. Immutable. Tag + keys/values directly bound to this resource. For + example: + + "123/environment": "production", + "123/costCenter": "marketing". + gateway_config (google.cloud.workstations_v1beta.types.WorkstationCluster.GatewayConfig): + Optional. Configuration options for Cluster + HTTP Gateway. + workstation_authorization_url (str): + Optional. Specifies the redirect URL for unauthorized + requests received by workstation VMs in this cluster. + + Redirects to this endpoint will send a base64 encoded + ``state`` query param containing the target workstation name + and original request hostname. The endpoint is responsible + for retrieving a token using ``GenerateAccessToken`` and + redirecting back to the original hostname with the token. + workstation_launch_url (str): + Optional. Specifies the launch URL for workstations in this + cluster. Requests sent to unstarted workstations will be + redirected to this URL. + + Requests redirected to the launch endpoint will be sent with + a ``workstation`` and ``project`` query parameter containing + the full workstation resource name and project ID, + respectively. The launch endpoint is responsible for + starting the workstation, polling it until it reaches + ``STATE_RUNNING``, and then issuing a redirect to the + workstation's host URL. """ class PrivateClusterConfig(proto.Message): @@ -147,7 +190,7 @@ class PrivateClusterConfig(proto.Message): mapping that address to the service attachment. service_attachment_uri (str): Output only. Service attachment URI for the workstation - cluster. The service attachemnt is created when private + cluster. The service attachment is created when private endpoint is enabled. To access workstations in the workstation cluster, configure access to the managed service using `Private Service @@ -177,6 +220,34 @@ class PrivateClusterConfig(proto.Message): number=4, ) + class DomainConfig(proto.Message): + r"""Configuration options for a custom domain. + + Attributes: + domain (str): + Immutable. Domain used by Workstations for + HTTP ingress. + """ + + domain: str = proto.Field( + proto.STRING, + number=1, + ) + + class GatewayConfig(proto.Message): + r"""Configuration options for Cluster HTTP Gateway. + + Attributes: + http2_enabled (bool): + Optional. Whether HTTP/2 is enabled for this + workstation cluster. Defaults to false. + """ + + http2_enabled: bool = proto.Field( + proto.BOOL, + number=1, + ) + name: str = proto.Field( proto.STRING, number=1, @@ -239,6 +310,11 @@ class PrivateClusterConfig(proto.Message): number=12, message=PrivateClusterConfig, ) + domain_config: DomainConfig = proto.Field( + proto.MESSAGE, + number=17, + message=DomainConfig, + ) degraded: bool = proto.Field( proto.BOOL, number=13, @@ -248,6 +324,32 @@ class PrivateClusterConfig(proto.Message): number=14, message=status_pb2.Status, ) + satisfies_pzs: bool = proto.Field( + proto.BOOL, + number=18, + ) + satisfies_pzi: bool = proto.Field( + proto.BOOL, + number=19, + ) + tags: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=20, + ) + gateway_config: GatewayConfig = proto.Field( + proto.MESSAGE, + number=21, + message=GatewayConfig, + ) + workstation_authorization_url: str = proto.Field( + proto.STRING, + number=22, + ) + workstation_launch_url: str = proto.Field( + proto.STRING, + number=23, + ) class WorkstationConfig(proto.Message): @@ -264,7 +366,8 @@ class WorkstationConfig(proto.Message): Attributes: name (str): - Full name of this workstation configuration. + Identifier. Full name of this workstation + configuration. display_name (str): Optional. Human-readable name for this workstation configuration. @@ -332,6 +435,23 @@ class WorkstationConfig(proto.Message): Workstations VMs created with this configuration have no maximum running time. This is strongly discouraged because you incur costs and will not pick up security updates. + max_usable_workstations (int): + Optional. Maximum number of workstations under this + configuration a user can have + ``workstations.workstation.use`` permission on. + + Only enforced on CreateWorkstation API calls on the user + issuing the API request. Can be overridden by: + + - granting a user + workstations.workstationConfigs.exemptMaxUsableWorkstationLimit + permission, or + - having a user with that permission create a workstation + and granting another user ``workstations.workstation.use`` + permission on that workstation. + + If not specified, defaults to ``0``, which indicates + unlimited. host (google.cloud.workstations_v1beta.types.WorkstationConfig.Host): Optional. Runtime host for the workstation. persistent_directories (MutableSequence[google.cloud.workstations_v1beta.types.WorkstationConfig.PersistentDirectory]): @@ -386,21 +506,73 @@ class WorkstationConfig(proto.Message): Immutable after the workstation configuration is created. degraded (bool): - Output only. Whether this resource is degraded, in which - case it may require user action to restore full - functionality. See also the + Output only. Whether this workstation configuration is in + degraded mode, in which case it may require user action to + restore full functionality. The [conditions][google.cloud.workstations.v1beta.WorkstationConfig.conditions] - field. + field contains detailed information about the status of the + configuration. conditions (MutableSequence[google.rpc.status_pb2.Status]): Output only. Status conditions describing the - current resource state. + workstation configuration's current state. enable_audit_agent (bool): Optional. Whether to enable Linux ``auditd`` logging on the - workstation. When enabled, a service account must also be - specified that has ``logging.buckets.write`` permission on - the project. Operating system audit logging is distinct from - `Cloud Audit - Logs `__. + workstation. When enabled, a + [service_account][google.cloud.workstations.v1beta.WorkstationConfig.Host.GceInstance.service_account] + must also be specified that has ``roles/logging.logWriter`` + and ``roles/monitoring.metricWriter`` on the project. + Operating system audit logging is distinct from `Cloud Audit + Logs `__ + and `Container output + logging `__. + Operating system audit logs are available in the `Cloud + Logging `__ console + by querying: + + :: + + resource.type="gce_instance" + log_name:"/logs/linux-auditd". + http_options (google.cloud.workstations_v1beta.types.WorkstationConfig.HttpOptions): + Optional. HTTP options that customize the + behavior of the workstation service's HTTP + proxy. + disable_tcp_connections (bool): + Optional. Disables support for plain TCP + connections in the workstation. By default the + service supports TCP connections through a + websocket relay. Setting this option to true + disables that relay, which prevents the usage of + services that require plain TCP connections, + such as SSH. When enabled, all communication + must occur over HTTPS or WSS. + allowed_ports (MutableSequence[google.cloud.workstations_v1beta.types.WorkstationConfig.PortRange]): + Optional. A list of + [PortRange][google.cloud.workstations.v1beta.WorkstationConfig.PortRange]s + specifying single ports or ranges of ports that are + externally accessible in the workstation. Allowed ports must + be one of 22, 80, or within range 1024-65535. If not + specified defaults to ports 22, 80, and ports 1024-65535. + satisfies_pzs (bool): + Output only. Reserved for future use. + satisfies_pzi (bool): + Output only. Reserved for future use. + grant_workstation_admin_role_on_create (bool): + Optional. Grant creator of a workstation + ``roles/workstations.policyAdmin`` role along with + ``roles/workstations.user`` role on the workstation created + by them. This allows workstation users to share access to + either their entire workstation, or individual ports. + Defaults to false. + enable_pushing_credentials (bool): + Optional. Enables pushing user provided credentials to + Workstations by calling workstations.pushCredentials. If + application_default_credentials are supplied to + pushCredentials, the provided token is returned when tools + and applications running in the user container make a + request for Default Application Credentials. Please note + that any credentials supplied are made available to all + users with access to the workstation. """ class Host(proto.Message): @@ -430,10 +602,13 @@ class GceInstance(proto.Message): Optional. The email address of the service account for Cloud Workstations VMs created with this configuration. When specified, be sure that the service account has - ``logginglogEntries.create`` permission on the project so it - can write logs out to Cloud Logging. If using a custom - container image, the service account must have permissions - to pull the specified image. + ``logging.logEntries.create`` and + ``monitoring.timeSeries.create`` permissions on the project + so it can write logs out to Cloud Logging. If using a custom + container image, the service account must have `Artifact + Registry + Reader `__ + permission to pull the specified image. If you as the administrator want to be able to ``ssh`` into the underlying VM, you need to set this value to a service @@ -448,8 +623,7 @@ class GceInstance(proto.Message): service_account_scopes (MutableSequence[str]): Optional. Scopes to grant to the [service_account][google.cloud.workstations.v1beta.WorkstationConfig.Host.GceInstance.service_account]. - Various scopes are automatically added based on feature - usage. When specified, users of workstations under this + When specified, users of workstations under this configuration must have ``iam.serviceAccounts.actAs`` on the service account. tags (MutableSequence[str]): @@ -479,9 +653,11 @@ class GceInstance(proto.Message): addresses). enable_nested_virtualization (bool): Optional. Whether to enable nested virtualization on Cloud - Workstations VMs created under this workstation + Workstations VMs created using this workstation configuration. + Defaults to false. + Nested virtualization lets you run virtual machine (VM) instances inside your workstation. Before enabling nested virtualization, consider the following important @@ -504,15 +680,6 @@ class GceInstance(proto.Message): enabled on workstation configurations that specify a [machine_type][google.cloud.workstations.v1beta.WorkstationConfig.Host.GceInstance.machine_type] in the N1 or N2 machine series. - - **GPUs**: nested virtualization may not be enabled on - workstation configurations with accelerators. - - **Operating System**: Because `Container-Optimized - OS `__ - does not support nested virtualization, when nested - virtualization is enabled, the underlying Compute Engine - VM instances boot from an `Ubuntu - LTS `__ - image. shielded_instance_config (google.cloud.workstations_v1beta.types.WorkstationConfig.Host.GceInstance.GceShieldedInstanceConfig): Optional. A set of Compute Engine Shielded instance options. @@ -526,6 +693,58 @@ class GceInstance(proto.Message): accelerators (MutableSequence[google.cloud.workstations_v1beta.types.WorkstationConfig.Host.GceInstance.Accelerator]): Optional. A list of the type and count of accelerator cards attached to the instance. + boost_configs (MutableSequence[google.cloud.workstations_v1beta.types.WorkstationConfig.Host.GceInstance.BoostConfig]): + Optional. A list of the boost configurations + that workstations created using this workstation + configuration are allowed to use. If specified, + users will have the option to choose from the + list of boost configs when starting a + workstation. + disable_ssh (bool): + Optional. Whether to disable SSH access to + the VM. + vm_tags (MutableMapping[str, str]): + Optional. Resource manager tags to be bound to this + instance. Tag keys and values have the same definition as + `resource manager + tags `__. + Keys must be in the format ``tagKeys/{tag_key_id}``, and + values are in the format ``tagValues/456``. + reservation_affinity (google.cloud.workstations_v1beta.types.WorkstationConfig.Host.GceInstance.ReservationAffinity): + Optional. + `ReservationAffinity `__ + specifies a reservation that can be consumed to create VM + instances. If SPECIFIC_RESERVATION is specified, Cloud + Workstations will only create VMs in the zone where the + reservation is located. This would affect availability since + the service will no longer be resilient to zonal outages. If + ANY_RESERVATION is specified, creating reservations in both + zones that the config creates VMs in will ensure higher + availability. **Important Considerations for Reservation + Affinity:** + + - This feature is intended for advanced users and requires + familiarity with Google Compute Engine reservations. + - Using reservations incurs charges, regardless of + utilization. + - The resources in the pool will consume the specified + reservation. Take this into account when setting the pool + size. + startup_script_uri (str): + Optional. Link to the startup script stored in Cloud + Storage. This script will be run on the host workstation VM + when the VM is created. The URI must be of the form + gs://{bucket-name}/{object-name}. If specifying a startup + script, the service account must have `Permission to access + the bucket and script file in Cloud + Storage `__. + Otherwise, the script must be publicly accessible. Note that + the service regularly updates the OS version of the host VM, + and it is the responsibility of the user to ensure the + script stays compatible with the OS version. + instance_metadata (MutableMapping[str, str]): + Optional. Custom metadata to apply to Compute + Engine instances. """ class GceShieldedInstanceConfig(proto.Message): @@ -591,6 +810,178 @@ class Accelerator(proto.Message): number=2, ) + class BoostConfig(proto.Message): + r"""A boost configuration is a set of resources that a + workstation can use to increase its performance. If you specify + a boost configuration, upon startup, workstation users can + choose to use a VM provisioned under the boost config by passing + the boost config ID in the start request. If the workstation + user does not provide a boost config ID in the start request, + the system will choose a VM from the pool provisioned under the + default config. + + Attributes: + id (str): + Required. The ID to be used for the boost + configuration. + machine_type (str): + Optional. The type of machine that boosted VM instances will + use—for example, ``e2-standard-4``. For more information + about machine types that Cloud Workstations supports, see + the list of `available machine + types `__. + Defaults to ``e2-standard-4``. + accelerators (MutableSequence[google.cloud.workstations_v1beta.types.WorkstationConfig.Host.GceInstance.Accelerator]): + Optional. A list of the type and count of accelerator cards + attached to the boost instance. Defaults to ``none``. + boot_disk_size_gb (int): + Optional. The size of the boot disk for the VM in gigabytes + (GB). The minimum boot disk size is ``30`` GB. Defaults to + ``50`` GB. + enable_nested_virtualization (bool): + Optional. Whether to enable nested virtualization on boosted + Cloud Workstations VMs running using this boost + configuration. + + Defaults to false. + + Nested virtualization lets you run virtual machine (VM) + instances inside your workstation. Before enabling nested + virtualization, consider the following important + considerations. Cloud Workstations instances are subject to + the `same restrictions as Compute Engine + instances `__: + + - **Organization policy**: projects, folders, or + organizations may be restricted from creating nested VMs + if the **Disable VM nested virtualization** constraint is + enforced in the organization policy. For more information, + see the Compute Engine section, `Checking whether nested + virtualization is + allowed `__. + - **Performance**: nested VMs might experience a 10% or + greater decrease in performance for workloads that are + CPU-bound and possibly greater than a 10% decrease for + workloads that are input/output bound. + - **Machine Type**: nested virtualization can only be + enabled on boost configurations that specify a + [machine_type][google.cloud.workstations.v1beta.WorkstationConfig.Host.GceInstance.BoostConfig.machine_type] + in the N1 or N2 machine series. + pool_size (int): + Optional. The number of boost VMs that the system should + keep idle so that workstations can be boosted quickly. + Defaults to ``0``. + reservation_affinity (google.cloud.workstations_v1beta.types.WorkstationConfig.Host.GceInstance.ReservationAffinity): + Optional. + `ReservationAffinity `__ + specifies a reservation that can be consumed to create boost + VM instances. If SPECIFIC_RESERVATION is specified, Cloud + Workstations will only create VMs in the zone where the + reservation is located. This would affect availability since + the service will no longer be resilient to zonal outages. If + ANY_RESERVATION is specified, creating reservations in both + zones that the config creates VMs in will ensure higher + availability. **Important Considerations for Reservation + Affinity:** + + - This feature is intended for advanced users and requires + familiarity with Google Compute Engine reservations. + - Using reservations incurs charges, regardless of + utilization. + - The resources in the pool will consume the specified + reservation. Take this into account when setting the pool + size. + """ + + id: str = proto.Field( + proto.STRING, + number=1, + ) + machine_type: str = proto.Field( + proto.STRING, + number=2, + ) + accelerators: MutableSequence[ + "WorkstationConfig.Host.GceInstance.Accelerator" + ] = proto.RepeatedField( + proto.MESSAGE, + number=3, + message="WorkstationConfig.Host.GceInstance.Accelerator", + ) + boot_disk_size_gb: int = proto.Field( + proto.INT32, + number=4, + ) + enable_nested_virtualization: bool = proto.Field( + proto.BOOL, + number=7, + ) + pool_size: int = proto.Field( + proto.INT32, + number=5, + ) + reservation_affinity: "WorkstationConfig.Host.GceInstance.ReservationAffinity" = proto.Field( + proto.MESSAGE, + number=6, + message="WorkstationConfig.Host.GceInstance.ReservationAffinity", + ) + + class ReservationAffinity(proto.Message): + r"""ReservationAffinity is the configuration of the desired + reservation from which instances can consume resources. + + Attributes: + consume_reservation_type (google.cloud.workstations_v1beta.types.WorkstationConfig.Host.GceInstance.ReservationAffinity.Type): + Optional. Corresponds to the type of + reservation consumption. + key (str): + Optional. Corresponds to the label key of + reservation resource. + values (MutableSequence[str]): + Optional. Corresponds to the label values of + reservation resources. Valid values are either + the name of a reservation in the same project or + "projects/{project}/reservations/{reservation}" + to target a shared reservation in the same zone + but in a different project. + """ + + class Type(proto.Enum): + r"""Indicates whether to consume capacity from a reservation or + not. + + Values: + TYPE_UNSPECIFIED (0): + Default value. This should not be used. + NO_RESERVATION (1): + Do not consume from any reserved capacity. + ANY_RESERVATION (2): + Consume any reservation available. + SPECIFIC_RESERVATION (3): + Must consume from a specific reservation. + Must specify key value fields for specifying the + reservations. + """ + + TYPE_UNSPECIFIED = 0 + NO_RESERVATION = 1 + ANY_RESERVATION = 2 + SPECIFIC_RESERVATION = 3 + + consume_reservation_type: "WorkstationConfig.Host.GceInstance.ReservationAffinity.Type" = proto.Field( + proto.ENUM, + number=1, + enum="WorkstationConfig.Host.GceInstance.ReservationAffinity.Type", + ) + key: str = proto.Field( + proto.STRING, + number=2, + ) + values: MutableSequence[str] = proto.RepeatedField( + proto.STRING, + number=3, + ) + machine_type: str = proto.Field( proto.STRING, number=1, @@ -644,6 +1035,36 @@ class Accelerator(proto.Message): number=11, message="WorkstationConfig.Host.GceInstance.Accelerator", ) + boost_configs: MutableSequence[ + "WorkstationConfig.Host.GceInstance.BoostConfig" + ] = proto.RepeatedField( + proto.MESSAGE, + number=25, + message="WorkstationConfig.Host.GceInstance.BoostConfig", + ) + disable_ssh: bool = proto.Field( + proto.BOOL, + number=13, + ) + vm_tags: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=14, + ) + reservation_affinity: "WorkstationConfig.Host.GceInstance.ReservationAffinity" = proto.Field( + proto.MESSAGE, + number=15, + message="WorkstationConfig.Host.GceInstance.ReservationAffinity", + ) + startup_script_uri: str = proto.Field( + proto.STRING, + number=26, + ) + instance_metadata: MutableMapping[str, str] = proto.MapField( + proto.STRING, + proto.STRING, + number=27, + ) gce_instance: "WorkstationConfig.Host.GceInstance" = proto.Field( proto.MESSAGE, @@ -653,7 +1074,14 @@ class Accelerator(proto.Message): ) class PersistentDirectory(proto.Message): - r"""A directory to persist across workstation sessions. + r"""A directory to persist across workstation sessions. Updates + to this field will not update existing workstations and will + only take effect on new workstations. + + This message has `oneof`_ fields (mutually exclusive fields). + For each oneof, at most one member field can be set at the same time. + Setting any member of the oneof automatically clears all other + members. .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields @@ -662,6 +1090,11 @@ class PersistentDirectory(proto.Message): A PersistentDirectory backed by a Compute Engine persistent disk. + This field is a member of `oneof`_ ``directory_type``. + gce_hd (google.cloud.workstations_v1beta.types.WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability): + A PersistentDirectory backed by a Compute + Engine hyperdisk high availability disk. + This field is a member of `oneof`_ ``directory_type``. mount_path (str): Optional. Location of this directory in the @@ -669,8 +1102,8 @@ class PersistentDirectory(proto.Message): """ class GceRegionalPersistentDisk(proto.Message): - r"""A PersistentDirectory backed by a Compute Engine regional persistent - disk. The + r"""A Persistent Directory backed by a Compute Engine regional + persistent disk. The [persistent_directories][google.cloud.workstations.v1beta.WorkstationConfig.persistent_directories] field is repeated, but it may contain only one entry. It creates a `persistent @@ -693,6 +1126,10 @@ class GceRegionalPersistentDisk(proto.Message): the [disk_type][google.cloud.workstations.v1beta.WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk.disk_type] must be ``"pd-balanced"`` or ``"pd-ssd"``. + max_size_gb (int): + Optional. Maximum size in GB to which this + persistent directory can be resized. Defaults to + unlimited if not set. fs_type (str): Optional. Type of file system that the disk should be formatted with. The workstation image must support this file @@ -709,11 +1146,22 @@ class GceRegionalPersistentDisk(proto.Message): [size_gb][google.cloud.workstations.v1beta.WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk.size_gb] and [fs_type][google.cloud.workstations.v1beta.WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk.fs_type] - must be empty. + must be empty. Must be formatted as ext4 file system with no + partitions. reclaim_policy (google.cloud.workstations_v1beta.types.WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk.ReclaimPolicy): Optional. Whether the persistent disk should be deleted when the workstation is deleted. Valid values are ``DELETE`` and ``RETAIN``. Defaults to ``DELETE``. + archive_timeout (google.protobuf.duration_pb2.Duration): + Optional. Number of seconds to wait after initially creating + or subsequently shutting down the workstation before + converting its disk into a snapshot. This generally saves + costs at the expense of greater startup time on next + workstation start, as the service will need to create a disk + from the archival snapshot. + + A value of ``"0s"`` indicates that the disk will never be + archived. """ class ReclaimPolicy(proto.Enum): @@ -740,6 +1188,10 @@ class ReclaimPolicy(proto.Enum): proto.INT32, number=1, ) + max_size_gb: int = proto.Field( + proto.INT32, + number=7, + ) fs_type: str = proto.Field( proto.STRING, number=2, @@ -757,6 +1209,98 @@ class ReclaimPolicy(proto.Enum): number=4, enum="WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk.ReclaimPolicy", ) + archive_timeout: duration_pb2.Duration = proto.Field( + proto.MESSAGE, + number=6, + message=duration_pb2.Duration, + ) + + class GceHyperdiskBalancedHighAvailability(proto.Message): + r"""A Persistent Directory backed by a Compute Engine `Hyperdisk + Balanced High Availability + Disk `__. + This is a high-availability block storage solution that offers a + balance between performance and cost for most general-purpose + workloads. + + Attributes: + size_gb (int): + Optional. The GB capacity of a persistent home directory for + each workstation created with this configuration. Must be + empty if + [source_snapshot][google.cloud.workstations.v1beta.WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability.source_snapshot] + is set. + + Valid values are ``10``, ``50``, ``100``, ``200``, ``500``, + or ``1000``. Defaults to ``200``. + max_size_gb (int): + Optional. Maximum size in GB to which this + persistent directory can be resized. Defaults to + unlimited if not set. + source_snapshot (str): + Optional. Name of the snapshot to use as the source for the + disk. If set, + [size_gb][google.cloud.workstations.v1beta.WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability.size_gb] + must be empty. Must be formatted as ext4 file system with no + partitions. + reclaim_policy (google.cloud.workstations_v1beta.types.WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability.ReclaimPolicy): + Optional. Whether the persistent disk should be deleted when + the workstation is deleted. Valid values are ``DELETE`` and + ``RETAIN``. Defaults to ``DELETE``. + archive_timeout (google.protobuf.duration_pb2.Duration): + Optional. Number of seconds to wait after initially creating + or subsequently shutting down the workstation before + converting its disk into a snapshot. This generally saves + costs at the expense of greater startup time on next + workstation start, as the service will need to create a disk + from the archival snapshot. + + A value of ``"0s"`` indicates that the disk will never be + archived. + """ + + class ReclaimPolicy(proto.Enum): + r"""Value representing what should happen to the disk after the + workstation is deleted. + + Values: + RECLAIM_POLICY_UNSPECIFIED (0): + Do not use. + DELETE (1): + Delete the persistent disk when deleting the + workstation. + RETAIN (2): + Keep the persistent disk when deleting the + workstation. An administrator must manually + delete the disk. + """ + + RECLAIM_POLICY_UNSPECIFIED = 0 + DELETE = 1 + RETAIN = 2 + + size_gb: int = proto.Field( + proto.INT32, + number=1, + ) + max_size_gb: int = proto.Field( + proto.INT32, + number=5, + ) + source_snapshot: str = proto.Field( + proto.STRING, + number=2, + ) + reclaim_policy: "WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability.ReclaimPolicy" = proto.Field( + proto.ENUM, + number=3, + enum="WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability.ReclaimPolicy", + ) + archive_timeout: duration_pb2.Duration = proto.Field( + proto.MESSAGE, + number=4, + message=duration_pb2.Duration, + ) gce_pd: "WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk" = proto.Field( proto.MESSAGE, @@ -764,6 +1308,12 @@ class ReclaimPolicy(proto.Enum): oneof="directory_type", message="WorkstationConfig.PersistentDirectory.GceRegionalPersistentDisk", ) + gce_hd: "WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability" = proto.Field( + proto.MESSAGE, + number=3, + oneof="directory_type", + message="WorkstationConfig.PersistentDirectory.GceHyperdiskBalancedHighAvailability", + ) mount_path: str = proto.Field( proto.STRING, number=1, @@ -800,10 +1350,20 @@ class GcePersistentDisk(proto.Message): Optional. Name of the snapshot to use as the source for the disk. Must be empty if [source_image][google.cloud.workstations.v1beta.WorkstationConfig.EphemeralDirectory.GcePersistentDisk.source_image] - is set. Updating + is set. Must be empty if + [read_only][google.cloud.workstations.v1beta.WorkstationConfig.EphemeralDirectory.GcePersistentDisk.read_only] + is false. Updating [source_snapshot][google.cloud.workstations.v1beta.WorkstationConfig.EphemeralDirectory.GcePersistentDisk.source_snapshot] will update content in the ephemeral directory after the - workstation is restarted. This field is mutable. + workstation is restarted. + + Only file systems supported by Container-Optimized OS (COS) + are explicitly supported. For a list of supported file + systems, see `the filesystems available in + Container-Optimized + OS `__. + + This field is mutable. source_image (str): Optional. Name of the disk image to use as the source for the disk. Must be empty if @@ -811,7 +1371,14 @@ class GcePersistentDisk(proto.Message): is set. Updating [source_image][google.cloud.workstations.v1beta.WorkstationConfig.EphemeralDirectory.GcePersistentDisk.source_image] will update content in the ephemeral directory after the - workstation is restarted. This field is mutable. + workstation is restarted. + + Only file systems supported by Container-Optimized OS (COS) + are explicitly supported. For a list of supported file + systems, please refer to the `COS + documentation `__. + + This field is mutable. read_only (bool): Optional. Whether the disk is read only. If true, the disk may be shared by multiple VMs and @@ -861,9 +1428,12 @@ class Container(proto.Message): images `__. If using a private image, the ``host.gceInstance.serviceAccount`` field must be specified - in the workstation configuration and must have permission to - pull the specified image. Otherwise, the image must be - publicly accessible. + in the workstation configuration. If using a custom + container image, the service account must have `Artifact + Registry + Reader `__ + permission to pull the specified image. Otherwise, the image + must be publicly accessible. command (MutableSequence[str]): Optional. If set, overrides the default ENTRYPOINT specified by the image. @@ -961,6 +1531,73 @@ class ReadinessCheck(proto.Message): number=2, ) + class HttpOptions(proto.Message): + r"""HTTP options for the running workstations. + + Attributes: + allowed_unauthenticated_cors_preflight_requests (bool): + Optional. By default, the workstations + service makes sure that all requests to the + workstation are authenticated. CORS preflight + requests do not include cookies or custom + headers, and so are considered unauthenticated + and blocked by the workstations service. + Enabling this option allows these + unauthenticated CORS preflight requests through + to the workstation, where it becomes the + responsibility of the destination server in the + workstation to validate the request. + disable_localhost_replacement (bool): + Optional. By default, the workstations + service replaces references to localhost, + 127.0.0.1, and 0.0.0.0 with the workstation's + hostname in http responses from the workstation + so that applications under development run + properly on the workstation. This may intefere + with some applications, and so this option + allows that behavior to be disabled. + """ + + allowed_unauthenticated_cors_preflight_requests: bool = proto.Field( + proto.BOOL, + number=1, + ) + disable_localhost_replacement: bool = proto.Field( + proto.BOOL, + number=2, + ) + + class PortRange(proto.Message): + r"""A PortRange defines a range of ports. Both + [first][google.cloud.workstations.v1beta.WorkstationConfig.PortRange.first] + and + [last][google.cloud.workstations.v1beta.WorkstationConfig.PortRange.last] + are inclusive. To specify a single port, both + [first][google.cloud.workstations.v1beta.WorkstationConfig.PortRange.first] + and + [last][google.cloud.workstations.v1beta.WorkstationConfig.PortRange.last] + should be the same. + + Attributes: + first (int): + Required. Starting port number for the + current range of ports. Valid ports are 22, 80, + and ports within the range 1024-65535. + last (int): + Required. Ending port number for the current + range of ports. Valid ports are 22, 80, and + ports within the range 1024-65535. + """ + + first: int = proto.Field( + proto.INT32, + number=1, + ) + last: int = proto.Field( + proto.INT32, + number=2, + ) + name: str = proto.Field( proto.STRING, number=1, @@ -1016,6 +1653,10 @@ class ReadinessCheck(proto.Message): number=11, message=duration_pb2.Duration, ) + max_usable_workstations: int = proto.Field( + proto.INT32, + number=28, + ) host: Host = proto.Field( proto.MESSAGE, number=12, @@ -1063,6 +1704,36 @@ class ReadinessCheck(proto.Message): proto.BOOL, number=20, ) + http_options: HttpOptions = proto.Field( + proto.MESSAGE, + number=21, + message=HttpOptions, + ) + disable_tcp_connections: bool = proto.Field( + proto.BOOL, + number=24, + ) + allowed_ports: MutableSequence[PortRange] = proto.RepeatedField( + proto.MESSAGE, + number=25, + message=PortRange, + ) + satisfies_pzs: bool = proto.Field( + proto.BOOL, + number=26, + ) + satisfies_pzi: bool = proto.Field( + proto.BOOL, + number=27, + ) + grant_workstation_admin_role_on_create: bool = proto.Field( + proto.BOOL, + number=29, + ) + enable_pushing_credentials: bool = proto.Field( + proto.BOOL, + number=30, + ) class Workstation(proto.Message): @@ -1071,7 +1742,7 @@ class Workstation(proto.Message): Attributes: name (str): - Full name of this workstation. + Identifier. Full name of this workstation. display_name (str): Optional. Human-readable name for this workstation. @@ -1107,6 +1778,9 @@ class Workstation(proto.Message): May be sent on update and delete requests to make sure that the client has an up-to-date value before proceeding. + persistent_directories (MutableSequence[google.cloud.workstations_v1beta.types.Workstation.WorkstationPersistentDirectory]): + Optional. Directories to persist across + workstation sessions. state (google.cloud.workstations_v1beta.types.Workstation.State): Output only. Current state of the workstation. @@ -1120,6 +1794,36 @@ class Workstation(proto.Message): env (MutableMapping[str, str]): Optional. Environment variables passed to the workstation container's entrypoint. + kms_key (str): + Output only. The name of the Google Cloud KMS encryption key + used to encrypt this workstation. The KMS key can only be + configured in the WorkstationConfig. The expected format is + ``projects/*/locations/*/keyRings/*/cryptoKeys/*``. + boost_configs (MutableSequence[google.cloud.workstations_v1beta.types.Workstation.WorkstationBoostConfig]): + Output only. List of available boost + configuration IDs that this workstation can be + boosted up to. + source_workstation (str): + Optional. The source workstation from which + this workstation's persistent directories were + cloned on creation. + satisfies_pzs (bool): + Output only. Reserved for future use. + satisfies_pzi (bool): + Output only. Reserved for future use. + runtime_host (google.cloud.workstations_v1beta.types.Workstation.RuntimeHost): + Optional. Output only. Runtime host for the workstation when + in STATE_RUNNING. + degraded (bool): + Output only. Whether this workstation is in degraded mode, + in which case it may require user action to restore full + functionality. The + [conditions][google.cloud.workstations.v1beta.Workstation.conditions] + field contains detailed information about the status of the + workstation. + conditions (MutableSequence[google.rpc.status_pb2.Status]): + Output only. Status conditions describing the + workstation's current state. """ class State(proto.Enum): @@ -1148,6 +1852,99 @@ class State(proto.Enum): STATE_STOPPING = 3 STATE_STOPPED = 4 + class WorkstationPersistentDirectory(proto.Message): + r"""A directory to persist across workstation sessions. Updates + to this field will only take effect on this workstation after it + is restarted. + + Attributes: + mount_path (str): + Optional. The mount path of the persistent + directory. + size_gb (int): + Optional. Size of the persistent directory in + GB. If specified in an update request, this is + the desired size of the directory. + """ + + mount_path: str = proto.Field( + proto.STRING, + number=2, + ) + size_gb: int = proto.Field( + proto.INT32, + number=3, + ) + + class WorkstationBoostConfig(proto.Message): + r"""Boost configuration for this workstation. This object is + populated from the parent workstation configuration. + + Attributes: + id (str): + Output only. Boost configuration ID. + running (bool): + Output only. Whether or not the current + workstation is actively boosted with this id. + """ + + id: str = proto.Field( + proto.STRING, + number=1, + ) + running: bool = proto.Field( + proto.BOOL, + number=2, + ) + + class RuntimeHost(proto.Message): + r"""Runtime host for the workstation. + + .. _oneof: https://proto-plus-python.readthedocs.io/en/stable/fields.html#oneofs-mutually-exclusive-fields + + Attributes: + gce_instance_host (google.cloud.workstations_v1beta.types.Workstation.RuntimeHost.GceInstanceHost): + Specifies a Compute Engine instance as the + host. + + This field is a member of `oneof`_ ``host_type``. + """ + + class GceInstanceHost(proto.Message): + r"""The Compute Engine instance host. + + Attributes: + name (str): + Optional. Output only. The name of the + Compute Engine instance. + id (str): + Optional. Output only. The ID of the Compute + Engine instance. + zone (str): + Optional. Output only. The zone of the + Compute Engine instance. + """ + + name: str = proto.Field( + proto.STRING, + number=1, + ) + id: str = proto.Field( + proto.STRING, + number=2, + ) + zone: str = proto.Field( + proto.STRING, + number=3, + ) + + gce_instance_host: "Workstation.RuntimeHost.GceInstanceHost" = proto.Field( + proto.MESSAGE, + number=1, + oneof="host_type", + message="Workstation.RuntimeHost.GceInstanceHost", + ) + name: str = proto.Field( proto.STRING, number=1, @@ -1198,6 +1995,13 @@ class State(proto.Enum): proto.STRING, number=9, ) + persistent_directories: MutableSequence[WorkstationPersistentDirectory] = ( + proto.RepeatedField( + proto.MESSAGE, + number=25, + message=WorkstationPersistentDirectory, + ) + ) state: State = proto.Field( proto.ENUM, number=10, @@ -1212,6 +2016,41 @@ class State(proto.Enum): proto.STRING, number=12, ) + kms_key: str = proto.Field( + proto.STRING, + number=15, + ) + boost_configs: MutableSequence[WorkstationBoostConfig] = proto.RepeatedField( + proto.MESSAGE, + number=16, + message=WorkstationBoostConfig, + ) + source_workstation: str = proto.Field( + proto.STRING, + number=17, + ) + satisfies_pzs: bool = proto.Field( + proto.BOOL, + number=18, + ) + satisfies_pzi: bool = proto.Field( + proto.BOOL, + number=19, + ) + runtime_host: RuntimeHost = proto.Field( + proto.MESSAGE, + number=21, + message=RuntimeHost, + ) + degraded: bool = proto.Field( + proto.BOOL, + number=23, + ) + conditions: MutableSequence[status_pb2.Status] = proto.RepeatedField( + proto.MESSAGE, + number=24, + message=status_pb2.Status, + ) class GetWorkstationClusterRequest(proto.Message): @@ -1239,6 +2078,10 @@ class ListWorkstationClustersRequest(proto.Message): page_token (str): Optional. next_page_token value returned from a previous List request, if any. + filter (str): + Optional. Filter the WorkstationClusters to + be listed. Possible filters are described in + https://google.aip.dev/160. """ parent: str = proto.Field( @@ -1253,6 +2096,10 @@ class ListWorkstationClustersRequest(proto.Message): proto.STRING, number=3, ) + filter: str = proto.Field( + proto.STRING, + number=4, + ) class ListWorkstationClustersResponse(proto.Message): @@ -1301,7 +2148,7 @@ class CreateWorkstationClusterRequest(proto.Message): Required. Workstation cluster to create. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. """ @@ -1335,7 +2182,7 @@ class UpdateWorkstationClusterRequest(proto.Message): the workstation cluster should be updated. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. allow_missing (bool): Optional. If set, and the workstation cluster is not found, @@ -1372,7 +2219,7 @@ class DeleteWorkstationClusterRequest(proto.Message): delete. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not apply it. + preview the result, but do not apply it. etag (str): Optional. If set, the request will be rejected if the latest version of the @@ -1429,6 +2276,10 @@ class ListWorkstationConfigsRequest(proto.Message): page_token (str): Optional. next_page_token value returned from a previous List request, if any. + filter (str): + Optional. Filter the WorkstationConfigs to be + listed. Possible filters are described in + https://google.aip.dev/160. """ parent: str = proto.Field( @@ -1443,6 +2294,10 @@ class ListWorkstationConfigsRequest(proto.Message): proto.STRING, number=3, ) + filter: str = proto.Field( + proto.STRING, + number=4, + ) class ListWorkstationConfigsResponse(proto.Message): @@ -1548,10 +2403,11 @@ class CreateWorkstationConfigRequest(proto.Message): Required. ID to use for the workstation configuration. workstation_config (google.cloud.workstations_v1beta.types.WorkstationConfig): - Required. Config to create. + Required. Workstation configuration to + create. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. """ @@ -1579,13 +2435,14 @@ class UpdateWorkstationConfigRequest(proto.Message): Attributes: workstation_config (google.cloud.workstations_v1beta.types.WorkstationConfig): - Required. Config to update. + Required. Workstation configuration to + update. update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. Mask specifying which fields in the workstation configuration should be updated. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. allow_missing (bool): Optional. If set and the workstation configuration is not @@ -1622,7 +2479,7 @@ class DeleteWorkstationConfigRequest(proto.Message): configuration to delete. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. etag (str): Optional. If set, the request is rejected if @@ -1679,6 +2536,10 @@ class ListWorkstationsRequest(proto.Message): page_token (str): Optional. next_page_token value returned from a previous List request, if any. + filter (str): + Optional. Filter the Workstations to be + listed. Possible filters are described in + https://google.aip.dev/160. """ parent: str = proto.Field( @@ -1693,6 +2554,10 @@ class ListWorkstationsRequest(proto.Message): proto.STRING, number=3, ) + filter: str = proto.Field( + proto.STRING, + number=4, + ) class ListWorkstationsResponse(proto.Message): @@ -1797,10 +2662,16 @@ class CreateWorkstationRequest(proto.Message): workstation_id (str): Required. ID to use for the workstation. workstation (google.cloud.workstations_v1beta.types.Workstation): - Required. Workstation to create. + Required. Workstation to create. If source_workstation is + specified, the user must have + ``workstations.workstations.use`` permission on the source + workstation, and the Cloud Workstations Service Agent for + the project where you are creating the new workstation must + have compute.disks.createSnapshot and + compute.snapshots.useReadOnly on the source project. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. """ @@ -1831,15 +2702,15 @@ class UpdateWorkstationRequest(proto.Message): Required. Workstation to update. update_mask (google.protobuf.field_mask_pb2.FieldMask): Required. Mask specifying which fields in the - workstation configuration should be updated. + workstation should be updated. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. allow_missing (bool): - Optional. If set and the workstation configuration is not - found, a new workstation configuration is created. In this - situation, update_mask is ignored. + Optional. If set and the workstation is not found, a new + workstation is created. In this situation, update_mask is + ignored. """ workstation: "Workstation" = proto.Field( @@ -1870,7 +2741,7 @@ class DeleteWorkstationRequest(proto.Message): Required. Name of the workstation to delete. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. etag (str): Optional. If set, the request will be @@ -1901,13 +2772,17 @@ class StartWorkstationRequest(proto.Message): Required. Name of the workstation to start. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. etag (str): Optional. If set, the request will be rejected if the latest version of the workstation on the server does not have this ETag. + boost_config (str): + Optional. If set, the workstation starts + using the boost configuration with the specified + ID. """ name: str = proto.Field( @@ -1922,6 +2797,10 @@ class StartWorkstationRequest(proto.Message): proto.STRING, number=3, ) + boost_config: str = proto.Field( + proto.STRING, + number=4, + ) class StopWorkstationRequest(proto.Message): @@ -1932,7 +2811,7 @@ class StopWorkstationRequest(proto.Message): Required. Name of the workstation to stop. validate_only (bool): Optional. If set, validate the request and - preview the review, but do not actually apply + preview the result, but do not actually apply it. etag (str): Optional. If set, the request will be @@ -1984,6 +2863,13 @@ class GenerateAccessTokenRequest(proto.Message): workstation (str): Required. Name of the workstation for which the access token should be generated. + port (int): + Optional. Port for which the access token should be + generated. If specified, the generated access token grants + access only to the specified port of the workstation. If + specified, values must be within the range [1 - 65535]. If + not specified, the generated access token grants access to + all ports of the workstation. """ expire_time: timestamp_pb2.Timestamp = proto.Field( @@ -2002,6 +2888,10 @@ class GenerateAccessTokenRequest(proto.Message): proto.STRING, number=1, ) + port: int = proto.Field( + proto.INT32, + number=4, + ) class GenerateAccessTokenResponse(proto.Message): @@ -2029,6 +2919,74 @@ class GenerateAccessTokenResponse(proto.Message): ) +class PushCredentialsRequest(proto.Message): + r"""Request message for PushCredentials. + + Attributes: + workstation (str): + Required. Name of the workstation for which + the credentials should be pushed. + application_default_credentials (google.cloud.workstations_v1beta.types.PushCredentialsRequest.OAuthToken): + Optional. Credentials used by Cloud Client + Libraries, Google API Client Libraries, and + other tooling within the user conainer: + + https://cloud.google.com/docs/authentication/application-default-credentials + """ + + class OAuthToken(proto.Message): + r"""OAuth token. + + Attributes: + email (str): + Optional. The email address encapsulated in + the OAuth token. + scopes (str): + Optional. The scopes encapsulated in the + OAuth token. See + https://developers.google.com/identity/protocols/oauth2/scopes + for more information. + access_token (str): + Required. The OAuth token. + expire_time (google.protobuf.timestamp_pb2.Timestamp): + Optional. The time the OAuth access token will expire. This + should be the time the access token was generated plus the + expires_in offset returned from the Access Token Response. + """ + + email: str = proto.Field( + proto.STRING, + number=1, + ) + scopes: str = proto.Field( + proto.STRING, + number=2, + ) + access_token: str = proto.Field( + proto.STRING, + number=3, + ) + expire_time: timestamp_pb2.Timestamp = proto.Field( + proto.MESSAGE, + number=4, + message=timestamp_pb2.Timestamp, + ) + + workstation: str = proto.Field( + proto.STRING, + number=1, + ) + application_default_credentials: OAuthToken = proto.Field( + proto.MESSAGE, + number=2, + message=OAuthToken, + ) + + +class PushCredentialsMetadata(proto.Message): + r"""Metadata message for PushCredentials.""" + + class OperationMetadata(proto.Message): r"""Metadata for long-running operations. diff --git a/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1beta.json b/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1beta.json index a9d21967918d..39c427311dce 100644 --- a/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1beta.json +++ b/packages/google-cloud-workstations/samples/generated_samples/snippet_metadata_google.cloud.workstations.v1beta.json @@ -2474,6 +2474,167 @@ ], "title": "workstations_v1beta_generated_workstations_list_workstations_sync.py" }, + { + "canonical": true, + "clientMethod": { + "async": true, + "client": { + "fullName": "google.cloud.workstations_v1beta.WorkstationsAsyncClient", + "shortName": "WorkstationsAsyncClient" + }, + "fullName": "google.cloud.workstations_v1beta.WorkstationsAsyncClient.push_credentials", + "method": { + "fullName": "google.cloud.workstations.v1beta.Workstations.PushCredentials", + "service": { + "fullName": "google.cloud.workstations.v1beta.Workstations", + "shortName": "Workstations" + }, + "shortName": "PushCredentials" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.workstations_v1beta.types.PushCredentialsRequest" + }, + { + "name": "workstation", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, Union[str, bytes]]]" + } + ], + "resultType": "google.api_core.operation_async.AsyncOperation", + "shortName": "push_credentials" + }, + "description": "Sample for PushCredentials", + "file": "workstations_v1beta_generated_workstations_push_credentials_async.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "workstations_v1beta_generated_Workstations_PushCredentials_async", + "segments": [ + { + "end": 55, + "start": 27, + "type": "FULL" + }, + { + "end": 55, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 52, + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 56, + "start": 53, + "type": "RESPONSE_HANDLING" + } + ], + "title": "workstations_v1beta_generated_workstations_push_credentials_async.py" + }, + { + "canonical": true, + "clientMethod": { + "client": { + "fullName": "google.cloud.workstations_v1beta.WorkstationsClient", + "shortName": "WorkstationsClient" + }, + "fullName": "google.cloud.workstations_v1beta.WorkstationsClient.push_credentials", + "method": { + "fullName": "google.cloud.workstations.v1beta.Workstations.PushCredentials", + "service": { + "fullName": "google.cloud.workstations.v1beta.Workstations", + "shortName": "Workstations" + }, + "shortName": "PushCredentials" + }, + "parameters": [ + { + "name": "request", + "type": "google.cloud.workstations_v1beta.types.PushCredentialsRequest" + }, + { + "name": "workstation", + "type": "str" + }, + { + "name": "retry", + "type": "google.api_core.retry.Retry" + }, + { + "name": "timeout", + "type": "float" + }, + { + "name": "metadata", + "type": "Sequence[Tuple[str, Union[str, bytes]]]" + } + ], + "resultType": "google.api_core.operation.Operation", + "shortName": "push_credentials" + }, + "description": "Sample for PushCredentials", + "file": "workstations_v1beta_generated_workstations_push_credentials_sync.py", + "language": "PYTHON", + "origin": "API_DEFINITION", + "regionTag": "workstations_v1beta_generated_Workstations_PushCredentials_sync", + "segments": [ + { + "end": 55, + "start": 27, + "type": "FULL" + }, + { + "end": 55, + "start": 27, + "type": "SHORT" + }, + { + "end": 40, + "start": 38, + "type": "CLIENT_INITIALIZATION" + }, + { + "end": 45, + "start": 41, + "type": "REQUEST_INITIALIZATION" + }, + { + "end": 52, + "start": 46, + "type": "REQUEST_EXECUTION" + }, + { + "end": 56, + "start": 53, + "type": "RESPONSE_HANDLING" + } + ], + "title": "workstations_v1beta_generated_workstations_push_credentials_sync.py" + }, { "canonical": true, "clientMethod": { diff --git a/packages/google-cloud-workstations/samples/generated_samples/workstations_v1beta_generated_workstations_push_credentials_async.py b/packages/google-cloud-workstations/samples/generated_samples/workstations_v1beta_generated_workstations_push_credentials_async.py new file mode 100644 index 000000000000..d70b287c4356 --- /dev/null +++ b/packages/google-cloud-workstations/samples/generated_samples/workstations_v1beta_generated_workstations_push_credentials_async.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Google LLC +# +# 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. +# +# Generated code. DO NOT EDIT! +# +# Snippet for PushCredentials +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install google-cloud-workstations + + +# [START workstations_v1beta_generated_Workstations_PushCredentials_async] +# This snippet has been automatically generated and should be regarded as a +# code template only. +# It will require modifications to work: +# - It may require correct/in-range values for request initialization. +# - It may require specifying regional endpoints when creating the service +# client as shown in: +# https://googleapis.dev/python/google-api-core/latest/client_options.html +from google.cloud import workstations_v1beta + + +async def sample_push_credentials(): + # Create a client + client = workstations_v1beta.WorkstationsAsyncClient() + + # Initialize request argument(s) + request = workstations_v1beta.PushCredentialsRequest( + workstation="workstation_value", + ) + + # Make the request + operation = await client.push_credentials(request=request) + + print("Waiting for operation to complete...") + + response = await operation.result() + + # Handle the response + print(response) + + +# [END workstations_v1beta_generated_Workstations_PushCredentials_async] diff --git a/packages/google-cloud-workstations/samples/generated_samples/workstations_v1beta_generated_workstations_push_credentials_sync.py b/packages/google-cloud-workstations/samples/generated_samples/workstations_v1beta_generated_workstations_push_credentials_sync.py new file mode 100644 index 000000000000..5d41bb377748 --- /dev/null +++ b/packages/google-cloud-workstations/samples/generated_samples/workstations_v1beta_generated_workstations_push_credentials_sync.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +# Copyright 2026 Google LLC +# +# 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. +# +# Generated code. DO NOT EDIT! +# +# Snippet for PushCredentials +# NOTE: This snippet has been automatically generated for illustrative purposes only. +# It may require modifications to work in your environment. + +# To install the latest published package dependency, execute the following: +# python3 -m pip install google-cloud-workstations + + +# [START workstations_v1beta_generated_Workstations_PushCredentials_sync] +# This snippet has been automatically generated and should be regarded as a +# code template only. +# It will require modifications to work: +# - It may require correct/in-range values for request initialization. +# - It may require specifying regional endpoints when creating the service +# client as shown in: +# https://googleapis.dev/python/google-api-core/latest/client_options.html +from google.cloud import workstations_v1beta + + +def sample_push_credentials(): + # Create a client + client = workstations_v1beta.WorkstationsClient() + + # Initialize request argument(s) + request = workstations_v1beta.PushCredentialsRequest( + workstation="workstation_value", + ) + + # Make the request + operation = client.push_credentials(request=request) + + print("Waiting for operation to complete...") + + response = operation.result() + + # Handle the response + print(response) + + +# [END workstations_v1beta_generated_Workstations_PushCredentials_sync] diff --git a/packages/google-cloud-workstations/tests/unit/gapic/workstations_v1/test_workstations.py b/packages/google-cloud-workstations/tests/unit/gapic/workstations_v1/test_workstations.py index c32c2b5c40b6..d055e9cdf871 100644 --- a/packages/google-cloud-workstations/tests/unit/gapic/workstations_v1/test_workstations.py +++ b/packages/google-cloud-workstations/tests/unit/gapic/workstations_v1/test_workstations.py @@ -1348,6 +1348,8 @@ def test_get_workstation_cluster(request_type, transport: str = "grpc"): subnetwork="subnetwork_value", control_plane_ip="control_plane_ip_value", degraded=True, + workstation_authorization_url="workstation_authorization_url_value", + workstation_launch_url="workstation_launch_url_value", ) response = client.get_workstation_cluster(request) @@ -1368,6 +1370,10 @@ def test_get_workstation_cluster(request_type, transport: str = "grpc"): assert response.subnetwork == "subnetwork_value" assert response.control_plane_ip == "control_plane_ip_value" assert response.degraded is True + assert ( + response.workstation_authorization_url == "workstation_authorization_url_value" + ) + assert response.workstation_launch_url == "workstation_launch_url_value" def test_get_workstation_cluster_non_empty_request_with_auto_populated_field(): @@ -1519,6 +1525,8 @@ async def test_get_workstation_cluster_async( subnetwork="subnetwork_value", control_plane_ip="control_plane_ip_value", degraded=True, + workstation_authorization_url="workstation_authorization_url_value", + workstation_launch_url="workstation_launch_url_value", ) ) response = await client.get_workstation_cluster(request) @@ -1540,6 +1548,10 @@ async def test_get_workstation_cluster_async( assert response.subnetwork == "subnetwork_value" assert response.control_plane_ip == "control_plane_ip_value" assert response.degraded is True + assert ( + response.workstation_authorization_url == "workstation_authorization_url_value" + ) + assert response.workstation_launch_url == "workstation_launch_url_value" def test_get_workstation_cluster_field_headers(): @@ -1747,6 +1759,7 @@ def test_list_workstation_clusters_non_empty_request_with_auto_populated_field() request = workstations.ListWorkstationClustersRequest( parent="parent_value", page_token="page_token_value", + filter="filter_value", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -1762,6 +1775,7 @@ def test_list_workstation_clusters_non_empty_request_with_auto_populated_field() request_msg = workstations.ListWorkstationClustersRequest( parent="parent_value", page_token="page_token_value", + filter="filter_value", ) assert args[0] == request_msg @@ -3349,8 +3363,12 @@ def test_get_workstation_config(request_type, transport: str = "grpc"): uid="uid_value", reconciling=True, etag="etag_value", + max_usable_workstations=2488, replica_zones=["replica_zones_value"], degraded=True, + enable_audit_agent=True, + disable_tcp_connections=True, + grant_workstation_admin_role_on_create=True, ) response = client.get_workstation_config(request) @@ -3367,8 +3385,12 @@ def test_get_workstation_config(request_type, transport: str = "grpc"): assert response.uid == "uid_value" assert response.reconciling is True assert response.etag == "etag_value" + assert response.max_usable_workstations == 2488 assert response.replica_zones == ["replica_zones_value"] assert response.degraded is True + assert response.enable_audit_agent is True + assert response.disable_tcp_connections is True + assert response.grant_workstation_admin_role_on_create is True def test_get_workstation_config_non_empty_request_with_auto_populated_field(): @@ -3516,8 +3538,12 @@ async def test_get_workstation_config_async( uid="uid_value", reconciling=True, etag="etag_value", + max_usable_workstations=2488, replica_zones=["replica_zones_value"], degraded=True, + enable_audit_agent=True, + disable_tcp_connections=True, + grant_workstation_admin_role_on_create=True, ) ) response = await client.get_workstation_config(request) @@ -3535,8 +3561,12 @@ async def test_get_workstation_config_async( assert response.uid == "uid_value" assert response.reconciling is True assert response.etag == "etag_value" + assert response.max_usable_workstations == 2488 assert response.replica_zones == ["replica_zones_value"] assert response.degraded is True + assert response.enable_audit_agent is True + assert response.disable_tcp_connections is True + assert response.grant_workstation_admin_role_on_create is True def test_get_workstation_config_field_headers(): @@ -3744,6 +3774,7 @@ def test_list_workstation_configs_non_empty_request_with_auto_populated_field(): request = workstations.ListWorkstationConfigsRequest( parent="parent_value", page_token="page_token_value", + filter="filter_value", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -3759,6 +3790,7 @@ def test_list_workstation_configs_non_empty_request_with_auto_populated_field(): request_msg = workstations.ListWorkstationConfigsRequest( parent="parent_value", page_token="page_token_value", + filter="filter_value", ) assert args[0] == request_msg @@ -5899,6 +5931,8 @@ def test_get_workstation(request_type, transport: str = "grpc"): etag="etag_value", state=workstations.Workstation.State.STATE_STARTING, host="host_value", + kms_key="kms_key_value", + source_workstation="source_workstation_value", ) response = client.get_workstation(request) @@ -5917,6 +5951,8 @@ def test_get_workstation(request_type, transport: str = "grpc"): assert response.etag == "etag_value" assert response.state == workstations.Workstation.State.STATE_STARTING assert response.host == "host_value" + assert response.kms_key == "kms_key_value" + assert response.source_workstation == "source_workstation_value" def test_get_workstation_non_empty_request_with_auto_populated_field(): @@ -6055,6 +6091,8 @@ async def test_get_workstation_async(request_type, transport: str = "grpc_asynci etag="etag_value", state=workstations.Workstation.State.STATE_STARTING, host="host_value", + kms_key="kms_key_value", + source_workstation="source_workstation_value", ) ) response = await client.get_workstation(request) @@ -6074,6 +6112,8 @@ async def test_get_workstation_async(request_type, transport: str = "grpc_asynci assert response.etag == "etag_value" assert response.state == workstations.Workstation.State.STATE_STARTING assert response.host == "host_value" + assert response.kms_key == "kms_key_value" + assert response.source_workstation == "source_workstation_value" def test_get_workstation_field_headers(): @@ -6273,6 +6313,7 @@ def test_list_workstations_non_empty_request_with_auto_populated_field(): request = workstations.ListWorkstationsRequest( parent="parent_value", page_token="page_token_value", + filter="filter_value", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -6288,6 +6329,7 @@ def test_list_workstations_non_empty_request_with_auto_populated_field(): request_msg = workstations.ListWorkstationsRequest( parent="parent_value", page_token="page_token_value", + filter="filter_value", ) assert args[0] == request_msg @@ -8431,6 +8473,7 @@ def test_start_workstation_non_empty_request_with_auto_populated_field(): request = workstations.StartWorkstationRequest( name="name_value", etag="etag_value", + boost_config="boost_config_value", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -8446,6 +8489,7 @@ def test_start_workstation_non_empty_request_with_auto_populated_field(): request_msg = workstations.StartWorkstationRequest( name="name_value", etag="etag_value", + boost_config="boost_config_value", ) assert args[0] == request_msg @@ -9661,6 +9705,7 @@ def test_list_workstation_clusters_rest_required_fields( # Check that path parameters and body parameters are not mixing in. assert not set(unset_fields) - set( ( + "filter", "page_size", "page_token", ) @@ -9722,6 +9767,7 @@ def test_list_workstation_clusters_rest_unset_required_fields(): assert set(unset_fields) == ( set( ( + "filter", "pageSize", "pageToken", ) @@ -10738,6 +10784,7 @@ def test_list_workstation_configs_rest_required_fields( # Check that path parameters and body parameters are not mixing in. assert not set(unset_fields) - set( ( + "filter", "page_size", "page_token", ) @@ -10799,6 +10846,7 @@ def test_list_workstation_configs_rest_unset_required_fields(): assert set(unset_fields) == ( set( ( + "filter", "pageSize", "pageToken", ) @@ -12087,6 +12135,7 @@ def test_list_workstations_rest_required_fields( # Check that path parameters and body parameters are not mixing in. assert not set(unset_fields) - set( ( + "filter", "page_size", "page_token", ) @@ -12148,6 +12197,7 @@ def test_list_workstations_rest_unset_required_fields(): assert set(unset_fields) == ( set( ( + "filter", "pageSize", "pageToken", ) @@ -14302,6 +14352,8 @@ async def test_get_workstation_cluster_empty_call_grpc_asyncio(): subnetwork="subnetwork_value", control_plane_ip="control_plane_ip_value", degraded=True, + workstation_authorization_url="workstation_authorization_url_value", + workstation_launch_url="workstation_launch_url_value", ) ) await client.get_workstation_cluster(request=None) @@ -14441,8 +14493,12 @@ async def test_get_workstation_config_empty_call_grpc_asyncio(): uid="uid_value", reconciling=True, etag="etag_value", + max_usable_workstations=2488, replica_zones=["replica_zones_value"], degraded=True, + enable_audit_agent=True, + disable_tcp_connections=True, + grant_workstation_admin_role_on_create=True, ) ) await client.get_workstation_config(request=None) @@ -14611,6 +14667,8 @@ async def test_get_workstation_empty_call_grpc_asyncio(): etag="etag_value", state=workstations.Workstation.State.STATE_STARTING, host="host_value", + kms_key="kms_key_value", + source_workstation="source_workstation_value", ) ) await client.get_workstation(request=None) @@ -14902,6 +14960,8 @@ def test_get_workstation_cluster_rest_call_success(request_type): subnetwork="subnetwork_value", control_plane_ip="control_plane_ip_value", degraded=True, + workstation_authorization_url="workstation_authorization_url_value", + workstation_launch_url="workstation_launch_url_value", ) # Wrap the value into a proper Response obj @@ -14927,6 +14987,10 @@ def test_get_workstation_cluster_rest_call_success(request_type): assert response.subnetwork == "subnetwork_value" assert response.control_plane_ip == "control_plane_ip_value" assert response.degraded is True + assert ( + response.workstation_authorization_url == "workstation_authorization_url_value" + ) + assert response.workstation_launch_url == "workstation_launch_url_value" @pytest.mark.parametrize("null_interceptor", [True, False]) @@ -15194,6 +15258,7 @@ def test_create_workstation_cluster_rest_call_success(request_type): "service_attachment_uri": "service_attachment_uri_value", "allowed_projects": ["allowed_projects_value1", "allowed_projects_value2"], }, + "domain_config": {"domain": "domain_value"}, "degraded": True, "conditions": [ { @@ -15207,6 +15272,10 @@ def test_create_workstation_cluster_rest_call_success(request_type): ], } ], + "tags": {}, + "gateway_config": {"http2_enabled": True}, + "workstation_authorization_url": "workstation_authorization_url_value", + "workstation_launch_url": "workstation_launch_url_value", } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -15431,6 +15500,7 @@ def test_update_workstation_cluster_rest_call_success(request_type): "service_attachment_uri": "service_attachment_uri_value", "allowed_projects": ["allowed_projects_value1", "allowed_projects_value2"], }, + "domain_config": {"domain": "domain_value"}, "degraded": True, "conditions": [ { @@ -15444,6 +15514,10 @@ def test_update_workstation_cluster_rest_call_success(request_type): ], } ], + "tags": {}, + "gateway_config": {"http2_enabled": True}, + "workstation_authorization_url": "workstation_authorization_url_value", + "workstation_launch_url": "workstation_launch_url_value", } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -15785,8 +15859,12 @@ def test_get_workstation_config_rest_call_success(request_type): uid="uid_value", reconciling=True, etag="etag_value", + max_usable_workstations=2488, replica_zones=["replica_zones_value"], degraded=True, + enable_audit_agent=True, + disable_tcp_connections=True, + grant_workstation_admin_role_on_create=True, ) # Wrap the value into a proper Response obj @@ -15808,8 +15886,12 @@ def test_get_workstation_config_rest_call_success(request_type): assert response.uid == "uid_value" assert response.reconciling is True assert response.etag == "etag_value" + assert response.max_usable_workstations == 2488 assert response.replica_zones == ["replica_zones_value"] assert response.degraded is True + assert response.enable_audit_agent is True + assert response.disable_tcp_connections is True + assert response.grant_workstation_admin_role_on_create is True @pytest.mark.parametrize("null_interceptor", [True, False]) @@ -16224,6 +16306,7 @@ def test_create_workstation_config_rest_call_success(request_type): "etag": "etag_value", "idle_timeout": {"seconds": 751, "nanos": 543}, "running_timeout": {}, + "max_usable_workstations": 2488, "host": { "gce_instance": { "machine_type": "machine_type_value", @@ -16244,16 +16327,51 @@ def test_create_workstation_config_rest_call_success(request_type): }, "confidential_instance_config": {"enable_confidential_compute": True}, "boot_disk_size_gb": 1792, + "accelerators": [{"type_": "type__value", "count": 553}], + "boost_configs": [ + { + "id": "id_value", + "machine_type": "machine_type_value", + "accelerators": {}, + "boot_disk_size_gb": 1792, + "enable_nested_virtualization": True, + "pool_size": 980, + } + ], + "disable_ssh": True, + "vm_tags": {}, + "startup_script_uri": "startup_script_uri_value", + "instance_metadata": {}, } }, "persistent_directories": [ { "gce_pd": { "size_gb": 739, + "max_size_gb": 1160, "fs_type": "fs_type_value", "disk_type": "disk_type_value", "source_snapshot": "source_snapshot_value", "reclaim_policy": 1, + "archive_timeout": {}, + }, + "gce_hd": { + "size_gb": 739, + "max_size_gb": 1160, + "source_snapshot": "source_snapshot_value", + "reclaim_policy": 1, + "archive_timeout": {}, + }, + "mount_path": "mount_path_value", + } + ], + "ephemeral_directories": [ + { + "gce_pd": { + "disk_type": "disk_type_value", + "source_snapshot": "source_snapshot_value", + "source_image": "source_image_value", + "read_only": True, }, "mount_path": "mount_path_value", } @@ -16285,6 +16403,10 @@ def test_create_workstation_config_rest_call_success(request_type): ], } ], + "enable_audit_agent": True, + "disable_tcp_connections": True, + "allowed_ports": [{"first": 552, "last": 436}], + "grant_workstation_admin_role_on_create": True, } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -16502,6 +16624,7 @@ def test_update_workstation_config_rest_call_success(request_type): "etag": "etag_value", "idle_timeout": {"seconds": 751, "nanos": 543}, "running_timeout": {}, + "max_usable_workstations": 2488, "host": { "gce_instance": { "machine_type": "machine_type_value", @@ -16522,16 +16645,51 @@ def test_update_workstation_config_rest_call_success(request_type): }, "confidential_instance_config": {"enable_confidential_compute": True}, "boot_disk_size_gb": 1792, + "accelerators": [{"type_": "type__value", "count": 553}], + "boost_configs": [ + { + "id": "id_value", + "machine_type": "machine_type_value", + "accelerators": {}, + "boot_disk_size_gb": 1792, + "enable_nested_virtualization": True, + "pool_size": 980, + } + ], + "disable_ssh": True, + "vm_tags": {}, + "startup_script_uri": "startup_script_uri_value", + "instance_metadata": {}, } }, "persistent_directories": [ { "gce_pd": { "size_gb": 739, + "max_size_gb": 1160, "fs_type": "fs_type_value", "disk_type": "disk_type_value", "source_snapshot": "source_snapshot_value", "reclaim_policy": 1, + "archive_timeout": {}, + }, + "gce_hd": { + "size_gb": 739, + "max_size_gb": 1160, + "source_snapshot": "source_snapshot_value", + "reclaim_policy": 1, + "archive_timeout": {}, + }, + "mount_path": "mount_path_value", + } + ], + "ephemeral_directories": [ + { + "gce_pd": { + "disk_type": "disk_type_value", + "source_snapshot": "source_snapshot_value", + "source_image": "source_image_value", + "read_only": True, }, "mount_path": "mount_path_value", } @@ -16563,6 +16721,10 @@ def test_update_workstation_config_rest_call_success(request_type): ], } ], + "enable_audit_agent": True, + "disable_tcp_connections": True, + "allowed_ports": [{"first": 552, "last": 436}], + "grant_workstation_admin_role_on_create": True, } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -16906,6 +17068,8 @@ def test_get_workstation_rest_call_success(request_type): etag="etag_value", state=workstations.Workstation.State.STATE_STARTING, host="host_value", + kms_key="kms_key_value", + source_workstation="source_workstation_value", ) # Wrap the value into a proper Response obj @@ -16929,6 +17093,8 @@ def test_get_workstation_rest_call_success(request_type): assert response.etag == "etag_value" assert response.state == workstations.Workstation.State.STATE_STARTING assert response.host == "host_value" + assert response.kms_key == "kms_key_value" + assert response.source_workstation == "source_workstation_value" @pytest.mark.parametrize("null_interceptor", [True, False]) @@ -17335,8 +17501,19 @@ def test_create_workstation_rest_call_success(request_type): "start_time": {}, "delete_time": {}, "etag": "etag_value", + "persistent_directories": [{"mount_path": "mount_path_value", "size_gb": 739}], "state": 1, "host": "host_value", + "env": {}, + "kms_key": "kms_key_value", + "source_workstation": "source_workstation_value", + "runtime_host": { + "gce_instance_host": { + "name": "name_value", + "id": "id_value", + "zone": "zone_value", + } + }, } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -17551,8 +17728,19 @@ def test_update_workstation_rest_call_success(request_type): "start_time": {}, "delete_time": {}, "etag": "etag_value", + "persistent_directories": [{"mount_path": "mount_path_value", "size_gb": 739}], "state": 1, "host": "host_value", + "env": {}, + "kms_key": "kms_key_value", + "source_workstation": "source_workstation_value", + "runtime_host": { + "gce_instance_host": { + "name": "name_value", + "id": "id_value", + "zone": "zone_value", + } + }, } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency diff --git a/packages/google-cloud-workstations/tests/unit/gapic/workstations_v1beta/test_workstations.py b/packages/google-cloud-workstations/tests/unit/gapic/workstations_v1beta/test_workstations.py index a40a95643153..0e0dadd3fb7f 100644 --- a/packages/google-cloud-workstations/tests/unit/gapic/workstations_v1beta/test_workstations.py +++ b/packages/google-cloud-workstations/tests/unit/gapic/workstations_v1beta/test_workstations.py @@ -1348,6 +1348,10 @@ def test_get_workstation_cluster(request_type, transport: str = "grpc"): subnetwork="subnetwork_value", control_plane_ip="control_plane_ip_value", degraded=True, + satisfies_pzs=True, + satisfies_pzi=True, + workstation_authorization_url="workstation_authorization_url_value", + workstation_launch_url="workstation_launch_url_value", ) response = client.get_workstation_cluster(request) @@ -1368,6 +1372,12 @@ def test_get_workstation_cluster(request_type, transport: str = "grpc"): assert response.subnetwork == "subnetwork_value" assert response.control_plane_ip == "control_plane_ip_value" assert response.degraded is True + assert response.satisfies_pzs is True + assert response.satisfies_pzi is True + assert ( + response.workstation_authorization_url == "workstation_authorization_url_value" + ) + assert response.workstation_launch_url == "workstation_launch_url_value" def test_get_workstation_cluster_non_empty_request_with_auto_populated_field(): @@ -1519,6 +1529,10 @@ async def test_get_workstation_cluster_async( subnetwork="subnetwork_value", control_plane_ip="control_plane_ip_value", degraded=True, + satisfies_pzs=True, + satisfies_pzi=True, + workstation_authorization_url="workstation_authorization_url_value", + workstation_launch_url="workstation_launch_url_value", ) ) response = await client.get_workstation_cluster(request) @@ -1540,6 +1554,12 @@ async def test_get_workstation_cluster_async( assert response.subnetwork == "subnetwork_value" assert response.control_plane_ip == "control_plane_ip_value" assert response.degraded is True + assert response.satisfies_pzs is True + assert response.satisfies_pzi is True + assert ( + response.workstation_authorization_url == "workstation_authorization_url_value" + ) + assert response.workstation_launch_url == "workstation_launch_url_value" def test_get_workstation_cluster_field_headers(): @@ -1747,6 +1767,7 @@ def test_list_workstation_clusters_non_empty_request_with_auto_populated_field() request = workstations.ListWorkstationClustersRequest( parent="parent_value", page_token="page_token_value", + filter="filter_value", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -1762,6 +1783,7 @@ def test_list_workstation_clusters_non_empty_request_with_auto_populated_field() request_msg = workstations.ListWorkstationClustersRequest( parent="parent_value", page_token="page_token_value", + filter="filter_value", ) assert args[0] == request_msg @@ -3349,9 +3371,15 @@ def test_get_workstation_config(request_type, transport: str = "grpc"): uid="uid_value", reconciling=True, etag="etag_value", + max_usable_workstations=2488, replica_zones=["replica_zones_value"], degraded=True, enable_audit_agent=True, + disable_tcp_connections=True, + satisfies_pzs=True, + satisfies_pzi=True, + grant_workstation_admin_role_on_create=True, + enable_pushing_credentials=True, ) response = client.get_workstation_config(request) @@ -3368,9 +3396,15 @@ def test_get_workstation_config(request_type, transport: str = "grpc"): assert response.uid == "uid_value" assert response.reconciling is True assert response.etag == "etag_value" + assert response.max_usable_workstations == 2488 assert response.replica_zones == ["replica_zones_value"] assert response.degraded is True assert response.enable_audit_agent is True + assert response.disable_tcp_connections is True + assert response.satisfies_pzs is True + assert response.satisfies_pzi is True + assert response.grant_workstation_admin_role_on_create is True + assert response.enable_pushing_credentials is True def test_get_workstation_config_non_empty_request_with_auto_populated_field(): @@ -3518,9 +3552,15 @@ async def test_get_workstation_config_async( uid="uid_value", reconciling=True, etag="etag_value", + max_usable_workstations=2488, replica_zones=["replica_zones_value"], degraded=True, enable_audit_agent=True, + disable_tcp_connections=True, + satisfies_pzs=True, + satisfies_pzi=True, + grant_workstation_admin_role_on_create=True, + enable_pushing_credentials=True, ) ) response = await client.get_workstation_config(request) @@ -3538,9 +3578,15 @@ async def test_get_workstation_config_async( assert response.uid == "uid_value" assert response.reconciling is True assert response.etag == "etag_value" + assert response.max_usable_workstations == 2488 assert response.replica_zones == ["replica_zones_value"] assert response.degraded is True assert response.enable_audit_agent is True + assert response.disable_tcp_connections is True + assert response.satisfies_pzs is True + assert response.satisfies_pzi is True + assert response.grant_workstation_admin_role_on_create is True + assert response.enable_pushing_credentials is True def test_get_workstation_config_field_headers(): @@ -3748,6 +3794,7 @@ def test_list_workstation_configs_non_empty_request_with_auto_populated_field(): request = workstations.ListWorkstationConfigsRequest( parent="parent_value", page_token="page_token_value", + filter="filter_value", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -3763,6 +3810,7 @@ def test_list_workstation_configs_non_empty_request_with_auto_populated_field(): request_msg = workstations.ListWorkstationConfigsRequest( parent="parent_value", page_token="page_token_value", + filter="filter_value", ) assert args[0] == request_msg @@ -5903,6 +5951,11 @@ def test_get_workstation(request_type, transport: str = "grpc"): etag="etag_value", state=workstations.Workstation.State.STATE_STARTING, host="host_value", + kms_key="kms_key_value", + source_workstation="source_workstation_value", + satisfies_pzs=True, + satisfies_pzi=True, + degraded=True, ) response = client.get_workstation(request) @@ -5921,6 +5974,11 @@ def test_get_workstation(request_type, transport: str = "grpc"): assert response.etag == "etag_value" assert response.state == workstations.Workstation.State.STATE_STARTING assert response.host == "host_value" + assert response.kms_key == "kms_key_value" + assert response.source_workstation == "source_workstation_value" + assert response.satisfies_pzs is True + assert response.satisfies_pzi is True + assert response.degraded is True def test_get_workstation_non_empty_request_with_auto_populated_field(): @@ -6059,6 +6117,11 @@ async def test_get_workstation_async(request_type, transport: str = "grpc_asynci etag="etag_value", state=workstations.Workstation.State.STATE_STARTING, host="host_value", + kms_key="kms_key_value", + source_workstation="source_workstation_value", + satisfies_pzs=True, + satisfies_pzi=True, + degraded=True, ) ) response = await client.get_workstation(request) @@ -6078,6 +6141,11 @@ async def test_get_workstation_async(request_type, transport: str = "grpc_asynci assert response.etag == "etag_value" assert response.state == workstations.Workstation.State.STATE_STARTING assert response.host == "host_value" + assert response.kms_key == "kms_key_value" + assert response.source_workstation == "source_workstation_value" + assert response.satisfies_pzs is True + assert response.satisfies_pzi is True + assert response.degraded is True def test_get_workstation_field_headers(): @@ -6277,6 +6345,7 @@ def test_list_workstations_non_empty_request_with_auto_populated_field(): request = workstations.ListWorkstationsRequest( parent="parent_value", page_token="page_token_value", + filter="filter_value", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -6292,6 +6361,7 @@ def test_list_workstations_non_empty_request_with_auto_populated_field(): request_msg = workstations.ListWorkstationsRequest( parent="parent_value", page_token="page_token_value", + filter="filter_value", ) assert args[0] == request_msg @@ -8435,6 +8505,7 @@ def test_start_workstation_non_empty_request_with_auto_populated_field(): request = workstations.StartWorkstationRequest( name="name_value", etag="etag_value", + boost_config="boost_config_value", ) # Mock the actual call within the gRPC stub, and fake the request. @@ -8450,6 +8521,7 @@ def test_start_workstation_non_empty_request_with_auto_populated_field(): request_msg = workstations.StartWorkstationRequest( name="name_value", etag="etag_value", + boost_config="boost_config_value", ) assert args[0] == request_msg @@ -9409,13 +9481,75 @@ async def test_generate_access_token_flattened_error_async(): ) -def test_get_workstation_cluster_rest_use_cached_wrapped_rpc(): +@pytest.mark.parametrize( + "request_type", + [ + workstations.PushCredentialsRequest(), + {}, + ], +) +def test_push_credentials(request_type, transport: str = "grpc"): + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.push_credentials), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/spam") + response = client.push_credentials(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + request = workstations.PushCredentialsRequest() + assert args[0] == request + + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) + + +def test_push_credentials_non_empty_request_with_auto_populated_field(): + # This test is a coverage failsafe to make sure that UUID4 fields are + # automatically populated, according to AIP-4235, with non-empty requests. + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Populate all string fields in the request which are not UUID4 + # since we want to check that UUID4 are populated automatically + # if they meet the requirements of AIP 4235. + request = workstations.PushCredentialsRequest( + workstation="workstation_value", + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.push_credentials), "__call__") as call: + call.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client.push_credentials(request=request) + call.assert_called() + _, args, _ = call.mock_calls[0] + request_msg = workstations.PushCredentialsRequest( + workstation="workstation_value", + ) + assert args[0] == request_msg + + +def test_push_credentials_use_cached_wrapped_rpc(): # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, # instead of constructing them on each call with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: client = WorkstationsClient( credentials=ga_credentials.AnonymousCredentials(), - transport="rest", + transport="grpc", ) # Should wrap all calls on client creation @@ -9423,160 +9557,428 @@ def test_get_workstation_cluster_rest_use_cached_wrapped_rpc(): wrapper_fn.reset_mock() # Ensure method has been cached - assert ( - client._transport.get_workstation_cluster - in client._transport._wrapped_methods - ) + assert client._transport.push_credentials in client._transport._wrapped_methods # Replace cached wrapped function with mock mock_rpc = mock.Mock() mock_rpc.return_value.name = ( "foo" # operation_request.operation in compute client(s) expect a string. ) - client._transport._wrapped_methods[ - client._transport.get_workstation_cluster - ] = mock_rpc - + client._transport._wrapped_methods[client._transport.push_credentials] = ( + mock_rpc + ) request = {} - client.get_workstation_cluster(request) + client.push_credentials(request) # Establish that the underlying gRPC stub method was called. assert mock_rpc.call_count == 1 - client.get_workstation_cluster(request) + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.push_credentials(request) # Establish that a new wrapper was not created for this call assert wrapper_fn.call_count == 0 assert mock_rpc.call_count == 2 -def test_get_workstation_cluster_rest_required_fields( - request_type=workstations.GetWorkstationClusterRequest, +@pytest.mark.asyncio +async def test_push_credentials_async_use_cached_wrapped_rpc( + transport: str = "grpc_asyncio", ): - transport_class = transports.WorkstationsRestTransport - - request_init = {} - request_init["name"] = "" - request = request_type(**request_init) - pb_request = request_type.pb(request) - jsonified_request = json.loads( - json_format.MessageToJson(pb_request, use_integers_for_enums=False) - ) - - # verify fields with default values are dropped - - unset_fields = transport_class( - credentials=ga_credentials.AnonymousCredentials() - ).get_workstation_cluster._get_unset_required_fields(jsonified_request) - jsonified_request.update(unset_fields) + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method_async.wrap_method") as wrapper_fn: + client = WorkstationsAsyncClient( + credentials=async_anonymous_credentials(), + transport=transport, + ) - # verify required fields with default values are now present + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() - jsonified_request["name"] = "name_value" + # Ensure method has been cached + assert ( + client._client._transport.push_credentials + in client._client._transport._wrapped_methods + ) - unset_fields = transport_class( - credentials=ga_credentials.AnonymousCredentials() - ).get_workstation_cluster._get_unset_required_fields(jsonified_request) - jsonified_request.update(unset_fields) + # Replace cached wrapped function with mock + mock_rpc = mock.AsyncMock() + mock_rpc.return_value = mock.Mock() + client._client._transport._wrapped_methods[ + client._client._transport.push_credentials + ] = mock_rpc - # verify required fields with non-default values are left alone - assert "name" in jsonified_request - assert jsonified_request["name"] == "name_value" + request = {} + await client.push_credentials(request) - client = WorkstationsClient( - credentials=ga_credentials.AnonymousCredentials(), - transport="rest", - ) - request = request_type(**request_init) + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 - # Designate an appropriate value for the returned response. - return_value = workstations.WorkstationCluster() - # Mock the http request call within the method and fake a response. - with mock.patch.object(Session, "request") as req: - # We need to mock transcode() because providing default values - # for required fields will fail the real version if the http_options - # expect actual values for those fields. - with mock.patch.object(path_template, "transcode") as transcode: - # A uri without fields and an empty body will force all the - # request fields to show up in the query_params. - pb_request = request_type.pb(request) - transcode_result = { - "uri": "v1/sample_method", - "method": "get", - "query_params": pb_request, - } - transcode.return_value = transcode_result + # Operation methods call wrapper_fn to build a cached + # client._transport.operations_client instance on first rpc call. + # Subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() - response_value = Response() - response_value.status_code = 200 + await client.push_credentials(request) - # Convert return value to protobuf type - return_value = workstations.WorkstationCluster.pb(return_value) - json_return_value = json_format.MessageToJson(return_value) + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 - response_value._content = json_return_value.encode("UTF-8") - req.return_value = response_value - req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} - response = client.get_workstation_cluster(request) +@pytest.mark.asyncio +@pytest.mark.parametrize( + "request_type", + [ + workstations.PushCredentialsRequest(), + {}, + ], +) +async def test_push_credentials_async(request_type, transport: str = "grpc_asyncio"): + client = WorkstationsAsyncClient( + credentials=async_anonymous_credentials(), + transport=transport, + ) - expected_params = [("$alt", "json;enum-encoding=int")] - actual_params = req.call_args.kwargs["params"] - assert sorted(expected_params) == sorted(actual_params) + # Everything is optional in proto3 as far as the runtime is concerned, + # and we are mocking out the actual API, so just send an empty request. + request = request_type + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.push_credentials), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + response = await client.push_credentials(request) -def test_get_workstation_cluster_rest_unset_required_fields(): - transport = transports.WorkstationsRestTransport( - credentials=ga_credentials.AnonymousCredentials - ) + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + request = workstations.PushCredentialsRequest() + assert args[0] == request - unset_fields = transport.get_workstation_cluster._get_unset_required_fields({}) - assert set(unset_fields) == (set(()) & set(("name",))) + # Establish that the response is the type that we expect. + assert isinstance(response, future.Future) -def test_get_workstation_cluster_rest_flattened(): +def test_push_credentials_field_headers(): client = WorkstationsClient( credentials=ga_credentials.AnonymousCredentials(), - transport="rest", ) - # Mock the http request call within the method and fake a response. - with mock.patch.object(type(client.transport._session), "request") as req: - # Designate an appropriate value for the returned response. - return_value = workstations.WorkstationCluster() + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = workstations.PushCredentialsRequest() - # get arguments that satisfy an http rule for this method - sample_request = { - "name": "projects/sample1/locations/sample2/workstationClusters/sample3" - } + request.workstation = "workstation_value" - # get truthy value for each flattened field - mock_args = dict( - name="name_value", - ) - mock_args.update(sample_request) + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.push_credentials), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.push_credentials(request) - # Wrap the value into a proper Response obj - response_value = Response() - response_value.status_code = 200 - # Convert return value to protobuf type - return_value = workstations.WorkstationCluster.pb(return_value) - json_return_value = json_format.MessageToJson(return_value) - response_value._content = json_return_value.encode("UTF-8") - req.return_value = response_value - req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + assert args[0] == request - client.get_workstation_cluster(**mock_args) + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "workstation=workstation_value", + ) in kw["metadata"] - # Establish that the underlying call was made with the expected - # request object values. - assert len(req.mock_calls) == 1 - _, args, _ = req.mock_calls[0] - assert path_template.validate( - "%s/v1beta/{name=projects/*/locations/*/workstationClusters/*}" - % client.transport._host, - args[1], - ) + +@pytest.mark.asyncio +async def test_push_credentials_field_headers_async(): + client = WorkstationsAsyncClient( + credentials=async_anonymous_credentials(), + ) + + # Any value that is part of the HTTP/1.1 URI should be sent as + # a field header. Set these to a non-empty value. + request = workstations.PushCredentialsRequest() + + request.workstation = "workstation_value" + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.push_credentials), "__call__") as call: + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/op") + ) + await client.push_credentials(request) + + # Establish that the underlying gRPC stub method was called. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + assert args[0] == request + + # Establish that the field header was sent. + _, _, kw = call.mock_calls[0] + assert ( + "x-goog-request-params", + "workstation=workstation_value", + ) in kw["metadata"] + + +def test_push_credentials_flattened(): + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.push_credentials), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/op") + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + client.push_credentials( + workstation="workstation_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) == 1 + _, args, _ = call.mock_calls[0] + arg = args[0].workstation + mock_val = "workstation_value" + assert arg == mock_val + + +def test_push_credentials_flattened_error(): + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.push_credentials( + workstations.PushCredentialsRequest(), + workstation="workstation_value", + ) + + +@pytest.mark.asyncio +async def test_push_credentials_flattened_async(): + client = WorkstationsAsyncClient( + credentials=async_anonymous_credentials(), + ) + + # Mock the actual call within the gRPC stub, and fake the request. + with mock.patch.object(type(client.transport.push_credentials), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = operations_pb2.Operation(name="operations/op") + + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + # Call the method with a truthy value for each flattened field, + # using the keyword arguments to the method. + response = await client.push_credentials( + workstation="workstation_value", + ) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(call.mock_calls) + _, args, _ = call.mock_calls[0] + arg = args[0].workstation + mock_val = "workstation_value" + assert arg == mock_val + + +@pytest.mark.asyncio +async def test_push_credentials_flattened_error_async(): + client = WorkstationsAsyncClient( + credentials=async_anonymous_credentials(), + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + await client.push_credentials( + workstations.PushCredentialsRequest(), + workstation="workstation_value", + ) + + +def test_get_workstation_cluster_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.get_workstation_cluster + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[ + client._transport.get_workstation_cluster + ] = mock_rpc + + request = {} + client.get_workstation_cluster(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.get_workstation_cluster(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +def test_get_workstation_cluster_rest_required_fields( + request_type=workstations.GetWorkstationClusterRequest, +): + transport_class = transports.WorkstationsRestTransport + + request_init = {} + request_init["name"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson(pb_request, use_integers_for_enums=False) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_workstation_cluster._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["name"] = "name_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).get_workstation_cluster._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "name" in jsonified_request + assert jsonified_request["name"] == "name_value" + + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = workstations.WorkstationCluster() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "get", + "query_params": pb_request, + } + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + # Convert return value to protobuf type + return_value = workstations.WorkstationCluster.pb(return_value) + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} + + response = client.get_workstation_cluster(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert sorted(expected_params) == sorted(actual_params) + + +def test_get_workstation_cluster_rest_unset_required_fields(): + transport = transports.WorkstationsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.get_workstation_cluster._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("name",))) + + +def test_get_workstation_cluster_rest_flattened(): + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = workstations.WorkstationCluster() + + # get arguments that satisfy an http rule for this method + sample_request = { + "name": "projects/sample1/locations/sample2/workstationClusters/sample3" + } + + # get truthy value for each flattened field + mock_args = dict( + name="name_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + # Convert return value to protobuf type + return_value = workstations.WorkstationCluster.pb(return_value) + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} + + client.get_workstation_cluster(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1beta/{name=projects/*/locations/*/workstationClusters/*}" + % client.transport._host, + args[1], + ) def test_get_workstation_cluster_rest_flattened_error(transport: str = "rest"): @@ -9665,6 +10067,7 @@ def test_list_workstation_clusters_rest_required_fields( # Check that path parameters and body parameters are not mixing in. assert not set(unset_fields) - set( ( + "filter", "page_size", "page_token", ) @@ -9726,6 +10129,7 @@ def test_list_workstation_clusters_rest_unset_required_fields(): assert set(unset_fields) == ( set( ( + "filter", "pageSize", "pageToken", ) @@ -10742,6 +11146,7 @@ def test_list_workstation_configs_rest_required_fields( # Check that path parameters and body parameters are not mixing in. assert not set(unset_fields) - set( ( + "filter", "page_size", "page_token", ) @@ -10803,6 +11208,7 @@ def test_list_workstation_configs_rest_unset_required_fields(): assert set(unset_fields) == ( set( ( + "filter", "pageSize", "pageToken", ) @@ -12091,6 +12497,7 @@ def test_list_workstations_rest_required_fields( # Check that path parameters and body parameters are not mixing in. assert not set(unset_fields) - set( ( + "filter", "page_size", "page_token", ) @@ -12152,6 +12559,7 @@ def test_list_workstations_rest_unset_required_fields(): assert set(unset_fields) == ( set( ( + "filter", "pageSize", "pageToken", ) @@ -13539,7 +13947,193 @@ def test_stop_workstation_rest_flattened_error(transport: str = "rest"): ) -def test_generate_access_token_rest_use_cached_wrapped_rpc(): +def test_generate_access_token_rest_use_cached_wrapped_rpc(): + # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, + # instead of constructing them on each call + with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Should wrap all calls on client creation + assert wrapper_fn.call_count > 0 + wrapper_fn.reset_mock() + + # Ensure method has been cached + assert ( + client._transport.generate_access_token + in client._transport._wrapped_methods + ) + + # Replace cached wrapped function with mock + mock_rpc = mock.Mock() + mock_rpc.return_value.name = ( + "foo" # operation_request.operation in compute client(s) expect a string. + ) + client._transport._wrapped_methods[client._transport.generate_access_token] = ( + mock_rpc + ) + + request = {} + client.generate_access_token(request) + + # Establish that the underlying gRPC stub method was called. + assert mock_rpc.call_count == 1 + + client.generate_access_token(request) + + # Establish that a new wrapper was not created for this call + assert wrapper_fn.call_count == 0 + assert mock_rpc.call_count == 2 + + +def test_generate_access_token_rest_required_fields( + request_type=workstations.GenerateAccessTokenRequest, +): + transport_class = transports.WorkstationsRestTransport + + request_init = {} + request_init["workstation"] = "" + request = request_type(**request_init) + pb_request = request_type.pb(request) + jsonified_request = json.loads( + json_format.MessageToJson(pb_request, use_integers_for_enums=False) + ) + + # verify fields with default values are dropped + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).generate_access_token._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with default values are now present + + jsonified_request["workstation"] = "workstation_value" + + unset_fields = transport_class( + credentials=ga_credentials.AnonymousCredentials() + ).generate_access_token._get_unset_required_fields(jsonified_request) + jsonified_request.update(unset_fields) + + # verify required fields with non-default values are left alone + assert "workstation" in jsonified_request + assert jsonified_request["workstation"] == "workstation_value" + + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + request = request_type(**request_init) + + # Designate an appropriate value for the returned response. + return_value = workstations.GenerateAccessTokenResponse() + # Mock the http request call within the method and fake a response. + with mock.patch.object(Session, "request") as req: + # We need to mock transcode() because providing default values + # for required fields will fail the real version if the http_options + # expect actual values for those fields. + with mock.patch.object(path_template, "transcode") as transcode: + # A uri without fields and an empty body will force all the + # request fields to show up in the query_params. + pb_request = request_type.pb(request) + transcode_result = { + "uri": "v1/sample_method", + "method": "post", + "query_params": pb_request, + } + transcode_result["body"] = pb_request + transcode.return_value = transcode_result + + response_value = Response() + response_value.status_code = 200 + + # Convert return value to protobuf type + return_value = workstations.GenerateAccessTokenResponse.pb(return_value) + json_return_value = json_format.MessageToJson(return_value) + + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} + + response = client.generate_access_token(request) + + expected_params = [("$alt", "json;enum-encoding=int")] + actual_params = req.call_args.kwargs["params"] + assert sorted(expected_params) == sorted(actual_params) + + +def test_generate_access_token_rest_unset_required_fields(): + transport = transports.WorkstationsRestTransport( + credentials=ga_credentials.AnonymousCredentials + ) + + unset_fields = transport.generate_access_token._get_unset_required_fields({}) + assert set(unset_fields) == (set(()) & set(("workstation",))) + + +def test_generate_access_token_rest_flattened(): + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = workstations.GenerateAccessTokenResponse() + + # get arguments that satisfy an http rule for this method + sample_request = { + "workstation": "projects/sample1/locations/sample2/workstationClusters/sample3/workstationConfigs/sample4/workstations/sample5" + } + + # get truthy value for each flattened field + mock_args = dict( + workstation="workstation_value", + ) + mock_args.update(sample_request) + + # Wrap the value into a proper Response obj + response_value = Response() + response_value.status_code = 200 + # Convert return value to protobuf type + return_value = workstations.GenerateAccessTokenResponse.pb(return_value) + json_return_value = json_format.MessageToJson(return_value) + response_value._content = json_return_value.encode("UTF-8") + req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} + + client.generate_access_token(**mock_args) + + # Establish that the underlying call was made with the expected + # request object values. + assert len(req.mock_calls) == 1 + _, args, _ = req.mock_calls[0] + assert path_template.validate( + "%s/v1beta/{workstation=projects/*/locations/*/workstationClusters/*/workstationConfigs/*/workstations/*}:generateAccessToken" + % client.transport._host, + args[1], + ) + + +def test_generate_access_token_rest_flattened_error(transport: str = "rest"): + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport=transport, + ) + + # Attempting to call a method with both a request object and flattened + # fields is an error. + with pytest.raises(ValueError): + client.generate_access_token( + workstations.GenerateAccessTokenRequest(), + workstation="workstation_value", + ) + + +def test_push_credentials_rest_use_cached_wrapped_rpc(): # Clients should use _prep_wrapped_messages to create cached wrapped rpcs, # instead of constructing them on each call with mock.patch("google.api_core.gapic_v1.method.wrap_method") as wrapper_fn: @@ -13553,35 +14147,36 @@ def test_generate_access_token_rest_use_cached_wrapped_rpc(): wrapper_fn.reset_mock() # Ensure method has been cached - assert ( - client._transport.generate_access_token - in client._transport._wrapped_methods - ) + assert client._transport.push_credentials in client._transport._wrapped_methods # Replace cached wrapped function with mock mock_rpc = mock.Mock() mock_rpc.return_value.name = ( "foo" # operation_request.operation in compute client(s) expect a string. ) - client._transport._wrapped_methods[client._transport.generate_access_token] = ( + client._transport._wrapped_methods[client._transport.push_credentials] = ( mock_rpc ) request = {} - client.generate_access_token(request) + client.push_credentials(request) # Establish that the underlying gRPC stub method was called. assert mock_rpc.call_count == 1 - client.generate_access_token(request) + # Operation methods build a cached wrapper on first rpc call + # subsequent calls should use the cached wrapper + wrapper_fn.reset_mock() + + client.push_credentials(request) # Establish that a new wrapper was not created for this call assert wrapper_fn.call_count == 0 assert mock_rpc.call_count == 2 -def test_generate_access_token_rest_required_fields( - request_type=workstations.GenerateAccessTokenRequest, +def test_push_credentials_rest_required_fields( + request_type=workstations.PushCredentialsRequest, ): transport_class = transports.WorkstationsRestTransport @@ -13597,7 +14192,7 @@ def test_generate_access_token_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).generate_access_token._get_unset_required_fields(jsonified_request) + ).push_credentials._get_unset_required_fields(jsonified_request) jsonified_request.update(unset_fields) # verify required fields with default values are now present @@ -13606,7 +14201,7 @@ def test_generate_access_token_rest_required_fields( unset_fields = transport_class( credentials=ga_credentials.AnonymousCredentials() - ).generate_access_token._get_unset_required_fields(jsonified_request) + ).push_credentials._get_unset_required_fields(jsonified_request) jsonified_request.update(unset_fields) # verify required fields with non-default values are left alone @@ -13620,7 +14215,7 @@ def test_generate_access_token_rest_required_fields( request = request_type(**request_init) # Designate an appropriate value for the returned response. - return_value = workstations.GenerateAccessTokenResponse() + return_value = operations_pb2.Operation(name="operations/spam") # Mock the http request call within the method and fake a response. with mock.patch.object(Session, "request") as req: # We need to mock transcode() because providing default values @@ -13640,32 +14235,29 @@ def test_generate_access_token_rest_required_fields( response_value = Response() response_value.status_code = 200 - - # Convert return value to protobuf type - return_value = workstations.GenerateAccessTokenResponse.pb(return_value) json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} - response = client.generate_access_token(request) + response = client.push_credentials(request) expected_params = [("$alt", "json;enum-encoding=int")] actual_params = req.call_args.kwargs["params"] assert sorted(expected_params) == sorted(actual_params) -def test_generate_access_token_rest_unset_required_fields(): +def test_push_credentials_rest_unset_required_fields(): transport = transports.WorkstationsRestTransport( credentials=ga_credentials.AnonymousCredentials ) - unset_fields = transport.generate_access_token._get_unset_required_fields({}) + unset_fields = transport.push_credentials._get_unset_required_fields({}) assert set(unset_fields) == (set(()) & set(("workstation",))) -def test_generate_access_token_rest_flattened(): +def test_push_credentials_rest_flattened(): client = WorkstationsClient( credentials=ga_credentials.AnonymousCredentials(), transport="rest", @@ -13674,7 +14266,7 @@ def test_generate_access_token_rest_flattened(): # Mock the http request call within the method and fake a response. with mock.patch.object(type(client.transport._session), "request") as req: # Designate an appropriate value for the returned response. - return_value = workstations.GenerateAccessTokenResponse() + return_value = operations_pb2.Operation(name="operations/spam") # get arguments that satisfy an http rule for this method sample_request = { @@ -13690,27 +14282,25 @@ def test_generate_access_token_rest_flattened(): # Wrap the value into a proper Response obj response_value = Response() response_value.status_code = 200 - # Convert return value to protobuf type - return_value = workstations.GenerateAccessTokenResponse.pb(return_value) json_return_value = json_format.MessageToJson(return_value) response_value._content = json_return_value.encode("UTF-8") req.return_value = response_value req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} - client.generate_access_token(**mock_args) + client.push_credentials(**mock_args) # Establish that the underlying call was made with the expected # request object values. assert len(req.mock_calls) == 1 _, args, _ = req.mock_calls[0] assert path_template.validate( - "%s/v1beta/{workstation=projects/*/locations/*/workstationClusters/*/workstationConfigs/*/workstations/*}:generateAccessToken" + "%s/v1beta/{workstation=projects/*/locations/*/workstationClusters/*/workstationConfigs/*/workstations/*}:pushCredentials" % client.transport._host, args[1], ) -def test_generate_access_token_rest_flattened_error(transport: str = "rest"): +def test_push_credentials_rest_flattened_error(transport: str = "rest"): client = WorkstationsClient( credentials=ga_credentials.AnonymousCredentials(), transport=transport, @@ -13719,8 +14309,8 @@ def test_generate_access_token_rest_flattened_error(transport: str = "rest"): # Attempting to call a method with both a request object and flattened # fields is an error. with pytest.raises(ValueError): - client.generate_access_token( - workstations.GenerateAccessTokenRequest(), + client.push_credentials( + workstations.PushCredentialsRequest(), workstation="workstation_value", ) @@ -14267,6 +14857,26 @@ def test_generate_access_token_empty_call_grpc(): assert args[0] == request_msg +# This test is a coverage failsafe to make sure that totally empty calls, +# i.e. request == None and no flattened fields passed, work. +def test_push_credentials_empty_call_grpc(): + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="grpc", + ) + + # Mock the actual call, and fake the request. + with mock.patch.object(type(client.transport.push_credentials), "__call__") as call: + call.return_value = operations_pb2.Operation(name="operations/op") + client.push_credentials(request=None) + + # Establish that the underlying stub method was called. + call.assert_called() + _, args, _ = call.mock_calls[0] + request_msg = workstations.PushCredentialsRequest() + assert args[0] == request_msg + + def test_transport_kind_grpc_asyncio(): transport = WorkstationsAsyncClient.get_transport_class("grpc_asyncio")( credentials=async_anonymous_credentials() @@ -14306,6 +14916,10 @@ async def test_get_workstation_cluster_empty_call_grpc_asyncio(): subnetwork="subnetwork_value", control_plane_ip="control_plane_ip_value", degraded=True, + satisfies_pzs=True, + satisfies_pzi=True, + workstation_authorization_url="workstation_authorization_url_value", + workstation_launch_url="workstation_launch_url_value", ) ) await client.get_workstation_cluster(request=None) @@ -14445,9 +15059,15 @@ async def test_get_workstation_config_empty_call_grpc_asyncio(): uid="uid_value", reconciling=True, etag="etag_value", + max_usable_workstations=2488, replica_zones=["replica_zones_value"], degraded=True, enable_audit_agent=True, + disable_tcp_connections=True, + satisfies_pzs=True, + satisfies_pzi=True, + grant_workstation_admin_role_on_create=True, + enable_pushing_credentials=True, ) ) await client.get_workstation_config(request=None) @@ -14616,6 +15236,11 @@ async def test_get_workstation_empty_call_grpc_asyncio(): etag="etag_value", state=workstations.Workstation.State.STATE_STARTING, host="host_value", + kms_key="kms_key_value", + source_workstation="source_workstation_value", + satisfies_pzs=True, + satisfies_pzi=True, + degraded=True, ) ) await client.get_workstation(request=None) @@ -14841,6 +15466,30 @@ async def test_generate_access_token_empty_call_grpc_asyncio(): assert args[0] == request_msg +# This test is a coverage failsafe to make sure that totally empty calls, +# i.e. request == None and no flattened fields passed, work. +@pytest.mark.asyncio +async def test_push_credentials_empty_call_grpc_asyncio(): + client = WorkstationsAsyncClient( + credentials=async_anonymous_credentials(), + transport="grpc_asyncio", + ) + + # Mock the actual call, and fake the request. + with mock.patch.object(type(client.transport.push_credentials), "__call__") as call: + # Designate an appropriate return value for the call. + call.return_value = grpc_helpers_async.FakeUnaryUnaryCall( + operations_pb2.Operation(name="operations/spam") + ) + await client.push_credentials(request=None) + + # Establish that the underlying stub method was called. + call.assert_called() + _, args, _ = call.mock_calls[0] + request_msg = workstations.PushCredentialsRequest() + assert args[0] == request_msg + + def test_transport_kind_rest(): transport = WorkstationsClient.get_transport_class("rest")( credentials=ga_credentials.AnonymousCredentials() @@ -14907,6 +15556,10 @@ def test_get_workstation_cluster_rest_call_success(request_type): subnetwork="subnetwork_value", control_plane_ip="control_plane_ip_value", degraded=True, + satisfies_pzs=True, + satisfies_pzi=True, + workstation_authorization_url="workstation_authorization_url_value", + workstation_launch_url="workstation_launch_url_value", ) # Wrap the value into a proper Response obj @@ -14932,6 +15585,12 @@ def test_get_workstation_cluster_rest_call_success(request_type): assert response.subnetwork == "subnetwork_value" assert response.control_plane_ip == "control_plane_ip_value" assert response.degraded is True + assert response.satisfies_pzs is True + assert response.satisfies_pzi is True + assert ( + response.workstation_authorization_url == "workstation_authorization_url_value" + ) + assert response.workstation_launch_url == "workstation_launch_url_value" @pytest.mark.parametrize("null_interceptor", [True, False]) @@ -15199,6 +15858,7 @@ def test_create_workstation_cluster_rest_call_success(request_type): "service_attachment_uri": "service_attachment_uri_value", "allowed_projects": ["allowed_projects_value1", "allowed_projects_value2"], }, + "domain_config": {"domain": "domain_value"}, "degraded": True, "conditions": [ { @@ -15212,6 +15872,12 @@ def test_create_workstation_cluster_rest_call_success(request_type): ], } ], + "satisfies_pzs": True, + "satisfies_pzi": True, + "tags": {}, + "gateway_config": {"http2_enabled": True}, + "workstation_authorization_url": "workstation_authorization_url_value", + "workstation_launch_url": "workstation_launch_url_value", } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -15436,6 +16102,7 @@ def test_update_workstation_cluster_rest_call_success(request_type): "service_attachment_uri": "service_attachment_uri_value", "allowed_projects": ["allowed_projects_value1", "allowed_projects_value2"], }, + "domain_config": {"domain": "domain_value"}, "degraded": True, "conditions": [ { @@ -15449,6 +16116,12 @@ def test_update_workstation_cluster_rest_call_success(request_type): ], } ], + "satisfies_pzs": True, + "satisfies_pzi": True, + "tags": {}, + "gateway_config": {"http2_enabled": True}, + "workstation_authorization_url": "workstation_authorization_url_value", + "workstation_launch_url": "workstation_launch_url_value", } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -15790,9 +16463,15 @@ def test_get_workstation_config_rest_call_success(request_type): uid="uid_value", reconciling=True, etag="etag_value", + max_usable_workstations=2488, replica_zones=["replica_zones_value"], degraded=True, enable_audit_agent=True, + disable_tcp_connections=True, + satisfies_pzs=True, + satisfies_pzi=True, + grant_workstation_admin_role_on_create=True, + enable_pushing_credentials=True, ) # Wrap the value into a proper Response obj @@ -15814,9 +16493,15 @@ def test_get_workstation_config_rest_call_success(request_type): assert response.uid == "uid_value" assert response.reconciling is True assert response.etag == "etag_value" + assert response.max_usable_workstations == 2488 assert response.replica_zones == ["replica_zones_value"] assert response.degraded is True assert response.enable_audit_agent is True + assert response.disable_tcp_connections is True + assert response.satisfies_pzs is True + assert response.satisfies_pzi is True + assert response.grant_workstation_admin_role_on_create is True + assert response.enable_pushing_credentials is True @pytest.mark.parametrize("null_interceptor", [True, False]) @@ -16231,6 +16916,7 @@ def test_create_workstation_config_rest_call_success(request_type): "etag": "etag_value", "idle_timeout": {"seconds": 751, "nanos": 543}, "running_timeout": {}, + "max_usable_workstations": 2488, "host": { "gce_instance": { "machine_type": "machine_type_value", @@ -16252,16 +16938,45 @@ def test_create_workstation_config_rest_call_success(request_type): "confidential_instance_config": {"enable_confidential_compute": True}, "boot_disk_size_gb": 1792, "accelerators": [{"type_": "type__value", "count": 553}], + "boost_configs": [ + { + "id": "id_value", + "machine_type": "machine_type_value", + "accelerators": {}, + "boot_disk_size_gb": 1792, + "enable_nested_virtualization": True, + "pool_size": 980, + "reservation_affinity": { + "consume_reservation_type": 1, + "key": "key_value", + "values": ["values_value1", "values_value2"], + }, + } + ], + "disable_ssh": True, + "vm_tags": {}, + "reservation_affinity": {}, + "startup_script_uri": "startup_script_uri_value", + "instance_metadata": {}, } }, "persistent_directories": [ { "gce_pd": { "size_gb": 739, + "max_size_gb": 1160, "fs_type": "fs_type_value", "disk_type": "disk_type_value", "source_snapshot": "source_snapshot_value", "reclaim_policy": 1, + "archive_timeout": {}, + }, + "gce_hd": { + "size_gb": 739, + "max_size_gb": 1160, + "source_snapshot": "source_snapshot_value", + "reclaim_policy": 1, + "archive_timeout": {}, }, "mount_path": "mount_path_value", } @@ -16305,6 +17020,16 @@ def test_create_workstation_config_rest_call_success(request_type): } ], "enable_audit_agent": True, + "http_options": { + "allowed_unauthenticated_cors_preflight_requests": True, + "disable_localhost_replacement": True, + }, + "disable_tcp_connections": True, + "allowed_ports": [{"first": 552, "last": 436}], + "satisfies_pzs": True, + "satisfies_pzi": True, + "grant_workstation_admin_role_on_create": True, + "enable_pushing_credentials": True, } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -16522,6 +17247,7 @@ def test_update_workstation_config_rest_call_success(request_type): "etag": "etag_value", "idle_timeout": {"seconds": 751, "nanos": 543}, "running_timeout": {}, + "max_usable_workstations": 2488, "host": { "gce_instance": { "machine_type": "machine_type_value", @@ -16543,16 +17269,45 @@ def test_update_workstation_config_rest_call_success(request_type): "confidential_instance_config": {"enable_confidential_compute": True}, "boot_disk_size_gb": 1792, "accelerators": [{"type_": "type__value", "count": 553}], + "boost_configs": [ + { + "id": "id_value", + "machine_type": "machine_type_value", + "accelerators": {}, + "boot_disk_size_gb": 1792, + "enable_nested_virtualization": True, + "pool_size": 980, + "reservation_affinity": { + "consume_reservation_type": 1, + "key": "key_value", + "values": ["values_value1", "values_value2"], + }, + } + ], + "disable_ssh": True, + "vm_tags": {}, + "reservation_affinity": {}, + "startup_script_uri": "startup_script_uri_value", + "instance_metadata": {}, } }, "persistent_directories": [ { "gce_pd": { "size_gb": 739, + "max_size_gb": 1160, "fs_type": "fs_type_value", "disk_type": "disk_type_value", "source_snapshot": "source_snapshot_value", "reclaim_policy": 1, + "archive_timeout": {}, + }, + "gce_hd": { + "size_gb": 739, + "max_size_gb": 1160, + "source_snapshot": "source_snapshot_value", + "reclaim_policy": 1, + "archive_timeout": {}, }, "mount_path": "mount_path_value", } @@ -16596,6 +17351,16 @@ def test_update_workstation_config_rest_call_success(request_type): } ], "enable_audit_agent": True, + "http_options": { + "allowed_unauthenticated_cors_preflight_requests": True, + "disable_localhost_replacement": True, + }, + "disable_tcp_connections": True, + "allowed_ports": [{"first": 552, "last": 436}], + "satisfies_pzs": True, + "satisfies_pzi": True, + "grant_workstation_admin_role_on_create": True, + "enable_pushing_credentials": True, } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -16939,6 +17704,11 @@ def test_get_workstation_rest_call_success(request_type): etag="etag_value", state=workstations.Workstation.State.STATE_STARTING, host="host_value", + kms_key="kms_key_value", + source_workstation="source_workstation_value", + satisfies_pzs=True, + satisfies_pzi=True, + degraded=True, ) # Wrap the value into a proper Response obj @@ -16962,6 +17732,11 @@ def test_get_workstation_rest_call_success(request_type): assert response.etag == "etag_value" assert response.state == workstations.Workstation.State.STATE_STARTING assert response.host == "host_value" + assert response.kms_key == "kms_key_value" + assert response.source_workstation == "source_workstation_value" + assert response.satisfies_pzs is True + assert response.satisfies_pzi is True + assert response.degraded is True @pytest.mark.parametrize("null_interceptor", [True, False]) @@ -17368,9 +18143,35 @@ def test_create_workstation_rest_call_success(request_type): "start_time": {}, "delete_time": {}, "etag": "etag_value", + "persistent_directories": [{"mount_path": "mount_path_value", "size_gb": 739}], "state": 1, "host": "host_value", "env": {}, + "kms_key": "kms_key_value", + "boost_configs": [{"id": "id_value", "running": True}], + "source_workstation": "source_workstation_value", + "satisfies_pzs": True, + "satisfies_pzi": True, + "runtime_host": { + "gce_instance_host": { + "name": "name_value", + "id": "id_value", + "zone": "zone_value", + } + }, + "degraded": True, + "conditions": [ + { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + } + ], } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -17585,9 +18386,35 @@ def test_update_workstation_rest_call_success(request_type): "start_time": {}, "delete_time": {}, "etag": "etag_value", + "persistent_directories": [{"mount_path": "mount_path_value", "size_gb": 739}], "state": 1, "host": "host_value", "env": {}, + "kms_key": "kms_key_value", + "boost_configs": [{"id": "id_value", "running": True}], + "source_workstation": "source_workstation_value", + "satisfies_pzs": True, + "satisfies_pzi": True, + "runtime_host": { + "gce_instance_host": { + "name": "name_value", + "id": "id_value", + "zone": "zone_value", + } + }, + "degraded": True, + "conditions": [ + { + "code": 411, + "message": "message_value", + "details": [ + { + "type_url": "type.googleapis.com/google.protobuf.Duration", + "value": b"\x08\x0c\x10\xdb\x07", + } + ], + } + ], } # The version of a generated dependency at test runtime may differ from the version used during generation. # Delete any fields which are not present in the current runtime dependency @@ -18272,6 +19099,136 @@ def test_generate_access_token_rest_interceptors(null_interceptor): post_with_metadata.assert_called_once() +def test_push_credentials_rest_bad_request( + request_type=workstations.PushCredentialsRequest, +): + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + # send a request that will satisfy transcoding + request_init = { + "workstation": "projects/sample1/locations/sample2/workstationClusters/sample3/workstationConfigs/sample4/workstations/sample5" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a BadRequest error. + with ( + mock.patch.object(Session, "request") as req, + pytest.raises(core_exceptions.BadRequest), + ): + # Wrap the value into a proper Response obj + response_value = mock.Mock() + json_return_value = "" + response_value.json = mock.Mock(return_value={}) + response_value.status_code = 400 + response_value.request = mock.Mock() + req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} + client.push_credentials(request) + + +@pytest.mark.parametrize( + "request_type", + [ + workstations.PushCredentialsRequest, + dict, + ], +) +def test_push_credentials_rest_call_success(request_type): + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), transport="rest" + ) + + # send a request that will satisfy transcoding + request_init = { + "workstation": "projects/sample1/locations/sample2/workstationClusters/sample3/workstationConfigs/sample4/workstations/sample5" + } + request = request_type(**request_init) + + # Mock the http request call within the method and fake a response. + with mock.patch.object(type(client.transport._session), "request") as req: + # Designate an appropriate value for the returned response. + return_value = operations_pb2.Operation(name="operations/spam") + + # Wrap the value into a proper Response obj + response_value = mock.Mock() + response_value.status_code = 200 + json_return_value = json_format.MessageToJson(return_value) + response_value.content = json_return_value.encode("UTF-8") + req.return_value = response_value + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} + response = client.push_credentials(request) + + # Establish that the response is the type that we expect. + json_return_value = json_format.MessageToJson(return_value) + + +@pytest.mark.parametrize("null_interceptor", [True, False]) +def test_push_credentials_rest_interceptors(null_interceptor): + transport = transports.WorkstationsRestTransport( + credentials=ga_credentials.AnonymousCredentials(), + interceptor=None + if null_interceptor + else transports.WorkstationsRestInterceptor(), + ) + client = WorkstationsClient(transport=transport) + + with ( + mock.patch.object(type(client.transport._session), "request") as req, + mock.patch.object(path_template, "transcode") as transcode, + mock.patch.object(operation.Operation, "_set_result_from_operation"), + mock.patch.object( + transports.WorkstationsRestInterceptor, "post_push_credentials" + ) as post, + mock.patch.object( + transports.WorkstationsRestInterceptor, + "post_push_credentials_with_metadata", + ) as post_with_metadata, + mock.patch.object( + transports.WorkstationsRestInterceptor, "pre_push_credentials" + ) as pre, + ): + pre.assert_not_called() + post.assert_not_called() + post_with_metadata.assert_not_called() + pb_message = workstations.PushCredentialsRequest.pb( + workstations.PushCredentialsRequest() + ) + transcode.return_value = { + "method": "post", + "uri": "my_uri", + "body": pb_message, + "query_params": pb_message, + } + + req.return_value = mock.Mock() + req.return_value.status_code = 200 + req.return_value.headers = {"header-1": "value-1", "header-2": "value-2"} + return_value = json_format.MessageToJson(operations_pb2.Operation()) + req.return_value.content = return_value + + request = workstations.PushCredentialsRequest() + metadata = [ + ("key", "val"), + ("cephalopod", "squid"), + ] + pre.return_value = request, metadata + post.return_value = operations_pb2.Operation() + post_with_metadata.return_value = operations_pb2.Operation(), metadata + + client.push_credentials( + request, + metadata=[ + ("key", "val"), + ("cephalopod", "squid"), + ], + ) + + pre.assert_called_once() + post.assert_called_once() + post_with_metadata.assert_called_once() + + def test_get_iam_policy_rest_bad_request( request_type=iam_policy_pb2.GetIamPolicyRequest, ): @@ -19151,6 +20108,25 @@ def test_generate_access_token_empty_call_rest(): assert args[0] == request_msg +# This test is a coverage failsafe to make sure that totally empty calls, +# i.e. request == None and no flattened fields passed, work. +def test_push_credentials_empty_call_rest(): + client = WorkstationsClient( + credentials=ga_credentials.AnonymousCredentials(), + transport="rest", + ) + + # Mock the actual call, and fake the request. + with mock.patch.object(type(client.transport.push_credentials), "__call__") as call: + client.push_credentials(request=None) + + # Establish that the underlying stub method was called. + call.assert_called() + _, args, _ = call.mock_calls[0] + request_msg = workstations.PushCredentialsRequest() + assert args[0] == request_msg + + def test_workstations_rest_lro_client(): client = WorkstationsClient( credentials=ga_credentials.AnonymousCredentials(), @@ -19221,6 +20197,7 @@ def test_workstations_base_transport(): "start_workstation", "stop_workstation", "generate_access_token", + "push_credentials", "set_iam_policy", "get_iam_policy", "test_iam_permissions", @@ -19555,6 +20532,9 @@ def test_workstations_client_transport_session_collision(transport_name): session1 = client1.transport.generate_access_token._session session2 = client2.transport.generate_access_token._session assert session1 != session2 + session1 = client1.transport.push_credentials._session + session2 = client2.transport.push_credentials._session + assert session1 != session2 def test_workstations_grpc_transport_channel():