def sink_update(self, project, sink_name, filter_, destination): """API call: update a sink resource. :type project: str :param project: ID of the project containing the sink. :type sink_name: str :param sink_name: the name of the sink :type filter_: str :param filter_: the advanced logs filter expression defining the entries exported by the sink. :type destination: str :param destination: destination URI for the entries exported by the sink. :rtype: dict :returns: The sink object returned from the API (converted from a protobuf to a dictionary). """ options = None path = 'projects/%s/sinks/%s' % (project, sink_name) sink_pb = LogSink(name=path, filter=filter_, destination=destination) try: self._gax_api.update_sink(path, sink_pb, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(path) raise return MessageToDict(sink_pb)
def subscription_modify_ack_deadline(self, subscription_path, ack_ids, ack_deadline): """API call: update ack deadline for retrieved messages See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyAckDeadline :type subscription_path: str :param subscription_path: the fully-qualified path of the new subscription, in format ``projects/<PROJECT>/subscriptions/<SUB_NAME>``. :type ack_ids: list of string :param ack_ids: ack IDs of messages being acknowledged :type ack_deadline: int :param ack_deadline: the deadline (in seconds) by which messages pulled from the back-end must be acknowledged. """ try: self._gax_api.modify_ack_deadline( subscription_path, ack_ids, ack_deadline) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(subscription_path) raise
def metric_update(self, project, metric_name, filter_, description): """API call: update a metric resource. :type project: str :param project: ID of the project containing the metric. :type metric_name: str :param metric_name: the name of the metric :type filter_: str :param filter_: the advanced logs filter expression defining the entries exported by the metric. :type description: str :param description: description of the metric. :rtype: dict :returns: The metric object returned from the API (converted from a protobuf to a dictionary). """ options = None path = 'projects/%s/metrics/%s' % (project, metric_name) metric_pb = LogMetric(name=path, filter=filter_, description=description) try: self._gax_api.update_log_metric(path, metric_pb, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(path) raise return MessageToDict(metric_pb)
def metric_create(self, project, metric_name, filter_, description): """API call: create a metric resource. See: https://cloud.google.com/logging/docs/api/reference/rest/v2/projects.metrics/create :type project: str :param project: ID of the project in which to create the metric. :type metric_name: str :param metric_name: the name of the metric :type filter_: str :param filter_: the advanced logs filter expression defining the entries exported by the metric. :type description: str :param description: description of the metric. """ options = None parent = 'projects/%s' % (project,) metric_pb = LogMetric(name=metric_name, filter=filter_, description=description) try: self._gax_api.create_log_metric(parent, metric_pb, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.FAILED_PRECONDITION: path = 'projects/%s/metrics/%s' % (project, metric_name) raise Conflict(path) raise
def sink_create(self, project, sink_name, filter_, destination): """API call: create a sink resource. See: https://cloud.google.com/logging/docs/api/reference/rest/v2/projects.sinks/create :type project: str :param project: ID of the project in which to create the sink. :type sink_name: str :param sink_name: the name of the sink :type filter_: str :param filter_: the advanced logs filter expression defining the entries exported by the sink. :type destination: str :param destination: destination URI for the entries exported by the sink. """ options = None parent = 'projects/%s' % (project,) sink_pb = LogSink(name=sink_name, filter=filter_, destination=destination) try: self._gax_api.create_sink(parent, sink_pb, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.FAILED_PRECONDITION: path = 'projects/%s/sinks/%s' % (project, sink_name) raise Conflict(path) raise
def topic_list_subscriptions(self, topic_path, page_token=None): """API call: list subscriptions bound to a topic See: https://cloud.google.com/pubsub/reference/rest/v1/projects.topics.subscriptions/list :type topic_path: string :param topic_path: fully-qualified path of the topic, in format ``projects/<PROJECT>/topics/<TOPIC_NAME>``. :type page_token: string :param page_token: opaque marker for the next "page" of subscriptions. If not passed, the API will return the first page of subscriptions. :rtype: list of strings :returns: fully-qualified names of subscriptions for the supplied topic. :raises: :exc:`gcloud.exceptions.NotFound` if the topic does not exist """ options = _build_paging_options(page_token) try: response = self._gax_api.list_topic_subscriptions( topic_path, options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(topic_path) raise subs = [{'topic': topic_path, 'name': subscription} for subscription in response.subscriptions] return subs, response.next_page_token
def topic_publish(self, topic_path, messages): """API call: publish one or more messages to a topic See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/publish :type topic_path: str :param topic_path: fully-qualified path of the topic, in format ``projects/<PROJECT>/topics/<TOPIC_NAME>``. :type messages: list of dict :param messages: messages to be published. :rtype: list of string :returns: list of opaque IDs for published messages. :raises: :exc:`google.cloud.exceptions.NotFound` if the topic does not exist """ options = CallOptions(is_bundling=False) message_pbs = [_message_pb_from_mapping(message) for message in messages] try: result = self._gax_api.publish(topic_path, message_pbs, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(topic_path) raise return result.message_ids
def subscription_pull(self, subscription_path, return_immediately=False, max_messages=1): """API call: retrieve messages for a subscription See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyPushConfig :type subscription_path: str :param subscription_path: the fully-qualified path of the new subscription, in format ``projects/<PROJECT>/subscriptions/<SUB_NAME>``. :type return_immediately: bool :param return_immediately: if True, the back-end returns even if no messages are available; if False, the API call blocks until one or more messages are available. :type max_messages: int :param max_messages: the maximum number of messages to return. :rtype: list of dict :returns: the ``receivedMessages`` element of the response. """ try: response_pb = self._gax_api.pull( subscription_path, max_messages, return_immediately=return_immediately) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(subscription_path) raise return [_received_message_pb_to_mapping(rmpb) for rmpb in response_pb.received_messages]
def _retry_on_unavailable(exc): """Retry only errors whose status code is 'UNAVAILABLE'. :type exc: :class:`~google.gax.errors.GaxError` :param exc: The exception that was caught. :rtype: bool :returns: Boolean indicating if the exception was UNAVAILABLE. """ return exc_to_code(exc) == StatusCode.UNAVAILABLE
def topic_delete(self, topic_path): """API call: delete a topic See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/create :type topic_path: str :param topic_path: fully-qualified path of the new topic, in format ``projects/<PROJECT>/topics/<TOPIC_NAME>``. """ try: self._gax_api.delete_topic(topic_path) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(topic_path) raise
def subscription_create(self, subscription_path, topic_path, ack_deadline=None, push_endpoint=None): """API call: create a subscription See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/create :type subscription_path: str :param subscription_path: the fully-qualified path of the new subscription, in format ``projects/<PROJECT>/subscriptions/<SUB_NAME>``. :type topic_path: str :param topic_path: the fully-qualified path of the topic being subscribed, in format ``projects/<PROJECT>/topics/<TOPIC_NAME>``. :type ack_deadline: int :param ack_deadline: (Optional) the deadline (in seconds) by which messages pulled from the back-end must be acknowledged. :type push_endpoint: str :param push_endpoint: (Optional) URL to which messages will be pushed by the back-end. If not set, the application must pull messages. :rtype: dict :returns: ``Subscription`` resource returned from the API. """ if push_endpoint is not None: push_config = PushConfig(push_endpoint=push_endpoint) else: push_config = None if ack_deadline is None: ack_deadline = 0 try: sub_pb = self._gax_api.create_subscription( subscription_path, topic_path, push_config=push_config, ack_deadline_seconds=ack_deadline) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.FAILED_PRECONDITION: raise Conflict(topic_path) raise return _subscription_pb_to_mapping(sub_pb)
def sink_delete(self, project, sink_name): """API call: delete a sink resource. :type project: str :param project: ID of the project containing the sink. :type sink_name: str :param sink_name: the name of the sink """ options = None path = 'projects/%s/sinks/%s' % (project, sink_name) try: self._gax_api.delete_sink(path, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(path) raise
def subscription_delete(self, subscription_path): """API call: delete a subscription See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/delete :type subscription_path: str :param subscription_path: the fully-qualified path of the subscription, in format ``projects/<PROJECT>/subscriptions/<SUB_NAME>``. """ try: self._gax_api.delete_subscription(subscription_path) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(subscription_path) raise
def logger_delete(self, project, logger_name): """API call: delete all entries in a logger via a DELETE request :type project: str :param project: ID of project containing the log entries to delete :type logger_name: str :param logger_name: name of logger containing the log entries to delete """ options = None path = 'projects/%s/logs/%s' % (project, logger_name) try: self._gax_api.delete_log(path, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(path) raise
def metric_delete(self, project, metric_name): """API call: delete a metric resource. :type project: str :param project: ID of the project containing the metric. :type metric_name: str :param metric_name: the name of the metric """ options = None path = 'projects/%s/metrics/%s' % (project, metric_name) try: self._gax_api.delete_log_metric(path, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(path) raise
def metric_get(self, project, metric_name): """API call: retrieve a metric resource. :type project: string :param project: ID of the project containing the metric. :type metric_name: string :param metric_name: the name of the metric """ options = None path = 'projects/%s/metrics/%s' % (project, metric_name) try: metric_pb = self._gax_api.get_log_metric(path, options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(path) raise return _log_metric_pb_to_mapping(metric_pb)
def sink_get(self, project, sink_name): """API call: retrieve a sink resource. :type project: string :param project: ID of the project containing the sink. :type sink_name: string :param sink_name: the name of the sink """ options = None path = 'projects/%s/sinks/%s' % (project, sink_name) try: sink_pb = self._gax_api.get_sink(path, options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(path) raise return _log_sink_pb_to_mapping(sink_pb)
def topic_list_subscriptions(self, topic, page_size=0, page_token=None): """API call: list subscriptions bound to a topic See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics.subscriptions/list :type topic: :class:`~google.cloud.pubsub.topic.Topic` :param topic: The topic that owns the subscriptions. :type page_size: int :param page_size: maximum number of subscriptions to return, If not passed, defaults to a value set by the API. :type page_token: str :param page_token: opaque marker for the next "page" of subscriptions. If not passed, the API will return the first page of subscriptions. :rtype: :class:`~google.cloud.iterator.Iterator` :returns: Iterator of :class:`~google.cloud.pubsub.subscription.Subscription` accessible to the current API. :raises: :exc:`~google.cloud.exceptions.NotFound` if the topic does not exist. """ if page_token is None: page_token = INITIAL_PAGE options = CallOptions(page_token=page_token) topic_path = topic.full_name try: page_iter = self._gax_api.list_topic_subscriptions( topic_path, page_size=page_size, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(topic_path) raise iter_kwargs = {} if page_size: # page_size can be 0 or explicit None. iter_kwargs['max_results'] = page_size iterator = GAXIterator(self._client, page_iter, _item_to_subscription, **iter_kwargs) iterator.topic = topic return iterator
def subscription_acknowledge(self, subscription_path, ack_ids): """API call: acknowledge retrieved messages See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyPushConfig :type subscription_path: str :param subscription_path: the fully-qualified path of the new subscription, in format ``projects/<PROJECT>/subscriptions/<SUB_NAME>``. :type ack_ids: list of string :param ack_ids: ack IDs of messages being acknowledged """ try: self._gax_api.acknowledge(subscription_path, ack_ids) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(subscription_path) raise
def subscription_get(self, subscription_path): """API call: retrieve a subscription See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/get :type subscription_path: str :param subscription_path: the fully-qualified path of the subscription, in format ``projects/<PROJECT>/subscriptions/<SUB_NAME>``. :rtype: dict :returns: ``Subscription`` resource returned from the API. """ try: sub_pb = self._gax_api.get_subscription(subscription_path) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(subscription_path) raise return _subscription_pb_to_mapping(sub_pb)
def exists(self): """Test whether this instance exists. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.GetInstanceConfig :rtype: bool :returns: True if the instance exists, else false :raises GaxError: for errors other than ``NOT_FOUND`` returned from the call """ api = self._client.instance_admin_api options = _options_with_prefix(self.name) try: api.get_instance(self.name, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: return False raise return True
def sink_get(self, project, sink_name): """API call: retrieve a sink resource. :type project: string :param project: ID of the project containing the sink. :type sink_name: string :param sink_name: the name of the sink :rtype: dict :returns: The sink object returned from the API (converted from a protobuf to a dictionary). """ options = None path = 'projects/%s/sinks/%s' % (project, sink_name) try: sink_pb = self._gax_api.get_sink(path, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(path) raise return _log_sink_pb_to_mapping(sink_pb)
def reload(self): """Reload this database. Refresh any configured schema into :attr:`ddl_statements`. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.GetDatabaseDDL :raises NotFound: if the database does not exist :raises GaxError: for errors other than ``NOT_FOUND`` returned from the call """ api = self._instance._client.database_admin_api options = _options_with_prefix(self.name) try: response = api.get_database_ddl(self.name, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(self.name) raise self._ddl_statements = tuple(response.statements)
def subscription_pull(self, subscription_path, return_immediately=False, max_messages=1): """API call: retrieve messages for a subscription See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyPushConfig :type subscription_path: str :param subscription_path: the fully-qualified path of the new subscription, in format ``projects/<PROJECT>/subscriptions/<SUB_NAME>``. :type return_immediately: bool :param return_immediately: if True, the back-end returns even if no messages are available; if False, the API call blocks until one or more messages are available. :type max_messages: int :param max_messages: the maximum number of messages to return. :rtype: list of dict :returns: the ``receivedMessages`` element of the response. """ try: response_pb = self._gax_api.pull( subscription_path, max_messages, return_immediately=return_immediately) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(subscription_path) raise return [ _received_message_pb_to_mapping(rmpb) for rmpb in response_pb.received_messages ]
def topic_create(self, topic_path): """API call: create a topic See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/create :type topic_path: str :param topic_path: fully-qualified path of the new topic, in format ``projects/<PROJECT>/topics/<TOPIC_NAME>``. :rtype: dict :returns: ``Topic`` resource returned from the API. :raises: :exc:`google.cloud.exceptions.Conflict` if the topic already exists """ try: topic_pb = self._gax_api.create_topic(topic_path) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.FAILED_PRECONDITION: raise Conflict(topic_path) raise return {'name': topic_pb.name}
def metric_get(self, project, metric_name): """API call: retrieve a metric resource. :type project: str :param project: ID of the project containing the metric. :type metric_name: str :param metric_name: the name of the metric :rtype: dict :returns: The metric object returned from the API (converted from a protobuf to a dictionary). """ options = None path = 'projects/%s/metrics/%s' % (project, metric_name) try: metric_pb = self._gax_api.get_log_metric(path, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(path) raise return MessageToDict(metric_pb)
def topic_get(self, topic_path): """API call: retrieve a topic See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.topics/get :type topic_path: str :param topic_path: fully-qualified path of the topic, in format ``projects/<PROJECT>/topics/<TOPIC_NAME>``. :rtype: dict :returns: ``Topic`` resource returned from the API. :raises: :exc:`google.cloud.exceptions.NotFound` if the topic does not exist """ try: topic_pb = self._gax_api.get_topic(topic_path) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(topic_path) raise return {'name': topic_pb.name}
def topic_list_subscriptions(self, topic_path, page_size=0, page_token=None): """API call: list subscriptions bound to a topic See: https://cloud.google.com/pubsub/reference/rest/v1/projects.topics.subscriptions/list :type topic_path: string :param topic_path: fully-qualified path of the topic, in format ``projects/<PROJECT>/topics/<TOPIC_NAME>``. :type page_size: int :param page_size: maximum number of subscriptions to return, If not passed, defaults to a value set by the API. :type page_token: string :param page_token: opaque marker for the next "page" of subscriptions. If not passed, the API will return the first page of subscriptions. :rtype: list of strings :returns: fully-qualified names of subscriptions for the supplied topic. :raises: :exc:`gcloud.exceptions.NotFound` if the topic does not exist """ options = _build_paging_options(page_token) try: page_iter = self._gax_api.list_topic_subscriptions( topic_path, page_size=page_size, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(topic_path) raise subs = page_iter.next() token = page_iter.page_token or None return subs, token
def test_db_run_in_transaction_twice_4181(self): retry = RetryInstanceState(_has_all_ddl) retry(self._db.reload)() with self._db.batch() as batch: batch.delete(COUNTERS_TABLE, self.ALL) def _unit_of_work(transaction, name): transaction.insert(COUNTERS_TABLE, COUNTERS_COLUMNS, [[name, 0]]) self._db.run_in_transaction(_unit_of_work, name='id_1') with self.assertRaises(errors.RetryError) as expected: self._db.run_in_transaction(_unit_of_work, name='id_1') self.assertEqual(exc_to_code(expected.exception.cause), StatusCode.ALREADY_EXISTS) self._db.run_in_transaction(_unit_of_work, name='id_2') with self._db.snapshot() as after: rows = list(after.read(COUNTERS_TABLE, COUNTERS_COLUMNS, self.ALL)) self.assertEqual(len(rows), 2)
def exists(self): """Test for the existence of this session. See https://cloud.google.com/spanner/reference/rpc/google.spanner.v1#google.spanner.v1.Spanner.GetSession :rtype: bool :returns: True if the session exists on the back-end, else False. :raises GaxError: for errors other than ``NOT_FOUND`` returned from the call """ if self._session_id is None: return False api = self._database.spanner_api options = _options_with_prefix(self._database.name) try: api.get_session(self.name, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: return False raise else: return True
def subscription_seek(self, subscription_path, time=None, snapshot=None): """API call: seek a subscription See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/seek :type subscription_path: str :param subscription_path:: the fully-qualified path of the subscription to affect, in format ``projects/<PROJECT>/subscriptions/<SUB_NAME>``. :type time: :class:`.timestamp_pb2.Timestamp` :param time: The time to seek to. :type snapshot: str :param snapshot: The snapshot to seek to. """ try: self._gax_api.seek(subscription_path, time=time, snapshot=snapshot) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(subscription_path) raise
def metric_update(self, project, metric_name, filter_, description): """API call: update a metric resource. :type project: str :param project: ID of the project containing the metric. :type metric_name: str :param metric_name: the name of the metric :type filter_: str :param filter_: the advanced logs filter expression defining the entries exported by the metric. :type description: str :param description: description of the metric. :rtype: dict :returns: The metric object returned from the API (converted from a protobuf to a dictionary). """ options = None path = 'projects/%s/metrics/%s' % (project, metric_name) metric_pb = LogMetric(name=path, filter=filter_, description=description) try: metric_pb = self._gax_api.update_log_metric(path, metric_pb, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(path) raise # NOTE: LogMetric message type does not have an ``Any`` field # so `MessageToDict`` can safely be used. return MessageToDict(metric_pb)
def delete(self): """Mark an instance and all of its databases for permanent deletion. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.instance.v1#google.spanner.admin.instance.v1.InstanceAdmin.DeleteInstance Immediately upon completion of the request: * Billing will cease for all of the instance's reserved resources. Soon afterward: * The instance and all databases within the instance will be deleteed. All data in the databases will be permanently deleted. """ api = self._client.instance_admin_api options = _options_with_prefix(self.name) try: api.delete_instance(self.name, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(self.name) raise
def subscription_modify_push_config(self, subscription_path, push_endpoint): """API call: update push config of a subscription See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/modifyPushConfig :type subscription_path: str :param subscription_path: the fully-qualified path of the new subscription, in format ``projects/<PROJECT>/subscriptions/<SUB_NAME>``. :type push_endpoint: str :param push_endpoint: (Optional) URL to which messages will be pushed by the back-end. If not set, the application must pull messages. """ push_config = PushConfig(push_endpoint=push_endpoint) try: self._gax_api.modify_push_config(subscription_path, push_config) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(subscription_path) raise
def sink_get(self, project, sink_name): """API call: retrieve a sink resource. :type project: str :param project: ID of the project containing the sink. :type sink_name: str :param sink_name: the name of the sink :rtype: dict :returns: The sink object returned from the API (converted from a protobuf to a dictionary). """ options = None path = 'projects/%s/sinks/%s' % (project, sink_name) try: sink_pb = self._gax_api.get_sink(path, options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(path) raise # NOTE: LogSink message type does not have an ``Any`` field # so `MessageToDict`` can safely be used. return MessageToDict(sink_pb)
def update_ddl(self, ddl_statements): """Update DDL for this database. Apply any configured schema from :attr:`ddl_statements`. See https://cloud.google.com/spanner/reference/rpc/google.spanner.admin.database.v1#google.spanner.admin.database.v1.DatabaseAdmin.UpdateDatabase :rtype: :class:`google.cloud.future.operation.Operation` :returns: an operation instance """ client = self._instance._client api = client.database_admin_api options = _options_with_prefix(self.name) try: future = api.update_database_ddl( self.name, ddl_statements, '', options=options) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.NOT_FOUND: raise NotFound(self.name) raise return future
def test_exc_to_code(self): code = grpc.exc_to_code(TestErrors.MyError()) self.assertEqual(code, grpc.StatusCode.UNKNOWN) self.assertEqual(code, grpc.STATUS_CODE_NAMES['UNKNOWN']) self.assertIsNone(grpc.exc_to_code(Exception)) self.assertIsNone(grpc.exc_to_code(grpc.RpcError()))
def subscription_create(self, subscription_path, topic_path, ack_deadline=None, push_endpoint=None, retain_acked_messages=None, message_retention_duration=None): """API call: create a subscription See: https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.subscriptions/create :type subscription_path: str :param subscription_path: the fully-qualified path of the new subscription, in format ``projects/<PROJECT>/subscriptions/<SUB_NAME>``. :type topic_path: str :param topic_path: the fully-qualified path of the topic being subscribed, in format ``projects/<PROJECT>/topics/<TOPIC_NAME>``. :type ack_deadline: int :param ack_deadline: (Optional) the deadline (in seconds) by which messages pulled from the back-end must be acknowledged. :type push_endpoint: str :param push_endpoint: (Optional) URL to which messages will be pushed by the back-end. If not set, the application must pull messages. :type retain_acked_messages: bool :param retain_acked_messages: (Optional) Whether to retain acked messages. If set, acked messages are retained in the subscription's backlog for a duration indicated by `message_retention_duration`. :type message_retention_duration: :class:`datetime.timedelta` :param message_retention_duration: (Optional) Whether to retain acked messages. If set, acked messages are retained in the subscription's backlog for a duration indicated by `message_retention_duration`. If unset, defaults to 7 days. :rtype: dict :returns: ``Subscription`` resource returned from the API. """ if push_endpoint is not None: push_config = PushConfig(push_endpoint=push_endpoint) else: push_config = None if message_retention_duration is not None: message_retention_duration = _timedelta_to_duration_pb( message_retention_duration) try: sub_pb = self._gax_api.create_subscription( subscription_path, topic_path, push_config=push_config, ack_deadline_seconds=ack_deadline, retain_acked_messages=retain_acked_messages, message_retention_duration=message_retention_duration) except GaxError as exc: if exc_to_code(exc.cause) == StatusCode.FAILED_PRECONDITION: raise Conflict(topic_path) raise return MessageToDict(sub_pb)
def _unavailable(exc): return exc_to_code(exc) == StatusCode.UNAVAILABLE
def test_run_in_transaction_w_abort_w_retry_metadata_deadline(self): import datetime from google.gax.errors import GaxError from google.gax.grpc import exc_to_code from grpc import StatusCode from google.cloud.spanner_v1.proto.spanner_pb2 import CommitResponse from google.cloud.spanner_v1.proto.transaction_pb2 import ( Transaction as TransactionPB) from google.cloud._helpers import UTC from google.cloud._helpers import _datetime_to_pb_timestamp from google.cloud.spanner_v1.transaction import Transaction from google.cloud.spanner_v1 import session as MUT from google.cloud._testing import _Monkey TABLE_NAME = 'citizens' COLUMNS = ['email', 'first_name', 'last_name', 'age'] VALUES = [ ['*****@*****.**', 'Phred', 'Phlyntstone', 32], ['*****@*****.**', 'Bharney', 'Rhubble', 31], ] TRANSACTION_ID = b'FACEDACE' RETRY_SECONDS = 1 RETRY_NANOS = 3456 transaction_pb = TransactionPB(id=TRANSACTION_ID) now = datetime.datetime.utcnow().replace(tzinfo=UTC) now_pb = _datetime_to_pb_timestamp(now) response = CommitResponse(commit_timestamp=now_pb) gax_api = _SpannerApi( _begin_transaction_response=transaction_pb, _commit_abort_count=1, _commit_abort_retry_seconds=RETRY_SECONDS, _commit_abort_retry_nanos=RETRY_NANOS, _commit_response=response, ) database = _Database(self.DATABASE_NAME) database.spanner_api = gax_api session = self._make_one(database) session._session_id = 'DEADBEEF' called_with = [] def unit_of_work(txn, *args, **kw): called_with.append((txn, args, kw)) txn.insert(TABLE_NAME, COLUMNS, VALUES) time_module = _FauxTimeModule() with _Monkey(MUT, time=time_module): with self.assertRaises(GaxError) as exc: session.run_in_transaction(unit_of_work, 'abc', some_arg='def', timeout_secs=0.01) self.assertEqual(exc_to_code(exc.exception.cause), StatusCode.ABORTED) self.assertIsNone(time_module._slept) self.assertEqual(len(called_with), 1) txn, args, kw = called_with[0] self.assertIsInstance(txn, Transaction) self.assertIsNone(txn.committed) self.assertEqual(args, ('abc', )) self.assertEqual(kw, {'some_arg': 'def'})
def test_update_document(client, cleanup): document_id = 'for-update' + unique_resource_id('-') document = client.document('made', document_id) # Add to clean-up before API request (in case ``create()`` fails). cleanup(document) # 0. Try to update before the document exists. with pytest.raises(NotFound) as exc_info: document.update({'not': 'there'}) assert exc_info.value.message.startswith(MISSING_ENTITY) assert document_id in exc_info.value.message # 1. Try to update before the document exists (now with an option). option1 = client.write_option(create_if_missing=False) with pytest.raises(NotFound) as exc_info: document.update({'still': 'not-there'}, option=option1) assert exc_info.value.message.startswith(MISSING_ENTITY) assert document_id in exc_info.value.message # 2. Update and create the document (with an option). data = { 'foo': { 'bar': 'baz', }, 'scoop': { 'barn': 981, }, 'other': True, } option2 = client.write_option(create_if_missing=True) write_result2 = document.update(data, option=option2) # 3. Send an update without a field path (no option). field_updates3 = {'foo': {'quux': 800}} write_result3 = document.update(field_updates3) assert_timestamp_less(write_result2.update_time, write_result3.update_time) snapshot3 = document.get() expected3 = { 'foo': field_updates3['foo'], 'scoop': data['scoop'], 'other': data['other'], } assert snapshot3.to_dict() == expected3 # 4. Send an update **with** a field path and a delete and a valid # "last timestamp" option. field_updates4 = { 'scoop.silo': None, 'other': firestore.DELETE_FIELD, } option4 = client.write_option(last_update_time=snapshot3.update_time) write_result4 = document.update(field_updates4, option=option4) assert_timestamp_less(write_result3.update_time, write_result4.update_time) snapshot4 = document.get() expected4 = { 'foo': field_updates3['foo'], 'scoop': { 'barn': data['scoop']['barn'], 'silo': field_updates4['scoop.silo'], }, } assert snapshot4.to_dict() == expected4 # 5. Call ``update()`` with invalid (in the past) "last timestamp" option. assert_timestamp_less(option4._last_update_time, snapshot4.update_time) with pytest.raises(GaxError) as exc_info: document.update({'bad': 'time-past'}, option=option4) assert exc_to_code(exc_info.value.cause) == StatusCode.FAILED_PRECONDITION # 6. Call ``update()`` with invalid (in future) "last timestamp" option. timestamp_pb = timestamp_pb2.Timestamp( seconds=snapshot4.update_time.nanos + 3600, nanos=snapshot4.update_time.nanos, ) option6 = client.write_option(last_update_time=timestamp_pb) with pytest.raises(GaxError) as exc_info: document.set({'bad': 'time-future'}, option=option6) assert exc_to_code(exc_info.value.cause) == StatusCode.FAILED_PRECONDITION