Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Logging: Unique Writer Identity #4595

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions logging/google/cloud/logging/_gax.py
Original file line number Diff line number Diff line change
Expand Up @@ -192,7 +192,8 @@ def list_sinks(self, project, page_size=0, page_token=None):
return page_iterator._GAXIterator(
self._client, page_iter, _item_to_sink)

def sink_create(self, project, sink_name, filter_, destination):
def sink_create(self, project, sink_name, filter_, destination,
unique_writer_identity=False):
"""API call: create a sink resource.

See
Expand All @@ -211,13 +212,23 @@ def sink_create(self, project, sink_name, filter_, destination):
:type destination: str
:param destination: destination URI for the entries exported by
the sink.

:type unique_writer_identity: bool

This comment was marked as spam.

This comment was marked as spam.

This comment was marked as spam.

:param unique_writer_identity: (Optional) determines the kind of
IAM identity returned as
writer_identity in the new 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)
self._gax_api.create_sink(
parent,
sink_pb,
unique_writer_identity=unique_writer_identity,
options=options,
)
except GaxError as exc:
if exc_to_code(exc.cause) == StatusCode.FAILED_PRECONDITION:
path = 'projects/%s/sinks/%s' % (project, sink_name)
Expand Down
16 changes: 14 additions & 2 deletions logging/google/cloud/logging/_http.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ def list_sinks(self, project, page_size=None, page_token=None):
page_token=page_token,
extra_params=extra_params)

def sink_create(self, project, sink_name, filter_, destination):
def sink_create(self, project, sink_name, filter_, destination,
unique_writer_identity=False):
"""API call: create a sink resource.

See
Expand All @@ -248,14 +249,25 @@ def sink_create(self, project, sink_name, filter_, destination):
:type destination: str
:param destination: destination URI for the entries exported by
the sink.

:type unique_writer_identity: bool
:param unique_writer_identity: (Optional) determines the kind of
IAM identity returned as
writer_identity in the new sink.
"""
target = '/projects/%s/sinks' % (project,)
data = {
'name': sink_name,
'filter': filter_,
'destination': destination,
}
self.api_request(method='POST', path=target, data=data)
query_params = {'uniqueWriterIdentity': unique_writer_identity}
self.api_request(
method='POST',
path=target,
data=data,
query_params=query_params,
)

def sink_get(self, project, sink_name):
"""API call: retrieve a sink resource.
Expand Down
13 changes: 11 additions & 2 deletions logging/google/cloud/logging/sink.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,19 @@ class Sink(object):
:type client: :class:`google.cloud.logging.client.Client`
:param client: A client which holds credentials and project configuration
for the sink (which requires a project).

:type unique_writer_identity: bool
:param unique_writer_identity: (Optional) determines the kind of
IAM identity returned as
writer_identity in the new sink.
"""
def __init__(self, name, filter_=None, destination=None, client=None):
def __init__(self, name, filter_=None, destination=None, client=None,
unique_writer_identity=False):
self.name = name
self.filter_ = filter_
self.destination = destination
self._client = client
self._unique_writer_identity = unique_writer_identity

@property
def client(self):
Expand Down Expand Up @@ -116,7 +123,9 @@ def create(self, client=None):
"""
client = self._require_client(client)
client.sinks_api.sink_create(
self.project, self.name, self.filter_, self.destination)
self.project, self.name, self.filter_, self.destination,
unique_writer_identity=self._unique_writer_identity,
)

def exists(self, client=None):
"""API call: test for the existence of the sink via a GET request
Expand Down
26 changes: 23 additions & 3 deletions logging/tests/unit/test__gax.py
Original file line number Diff line number Diff line change
Expand Up @@ -737,14 +737,34 @@ def test_sink_create_ok(self):
api.sink_create(
self.PROJECT, self.SINK_NAME, self.FILTER, self.DESTINATION_URI)

parent, sink, options = (
parent, sink, options, unique_writer_identity = (

This comment was marked as spam.

gax_api._create_sink_called_with)
self.assertEqual(parent, self.PROJECT_PATH)
self.assertIsInstance(sink, LogSink)
self.assertEqual(sink.name, self.SINK_NAME)
self.assertEqual(sink.filter, self.FILTER)
self.assertEqual(sink.destination, self.DESTINATION_URI)
self.assertIsNone(options)
self.assertFalse(unique_writer_identity)

def test_sink_create_with_unique_writer_identity(self):
from google.cloud.proto.logging.v2.logging_config_pb2 import LogSink

gax_api = _GAXSinksAPI()
api = self._make_one(gax_api, None)
api.sink_create(
self.PROJECT, self.SINK_NAME, self.FILTER, self.DESTINATION_URI,
unique_writer_identity=True,
)
parent, sink, options, unique_writer_identity = (
gax_api._create_sink_called_with)
self.assertEqual(parent, self.PROJECT_PATH)
self.assertIsInstance(sink, LogSink)
self.assertEqual(sink.name, self.SINK_NAME)
self.assertEqual(sink.filter, self.FILTER)
self.assertEqual(sink.destination, self.DESTINATION_URI)
self.assertIsNone(options)
self.assertTrue(unique_writer_identity)

def test_sink_get_error(self):
from google.cloud.exceptions import NotFound
Expand Down Expand Up @@ -1462,10 +1482,10 @@ def list_sinks(self, parent, page_size, options):
self._list_sinks_called_with = parent, page_size, options
return self._list_sinks_response

def create_sink(self, parent, sink, options):
def create_sink(self, parent, sink, options, unique_writer_identity=False):
from google.gax.errors import GaxError

self._create_sink_called_with = parent, sink, options
self._create_sink_called_with = parent, sink, options, unique_writer_identity
if self._random_gax_error:
raise GaxError('error')
if self._create_sink_conflict:
Expand Down
27 changes: 27 additions & 0 deletions logging/tests/unit/test__http.py
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,33 @@ def test_sink_create_ok(self):
self.assertEqual(conn._called_with['path'], path)
self.assertEqual(conn._called_with['data'], SENT)

def test_sink_create_unique_writer_identity(self):
sent = {
'name': self.SINK_NAME,
'filter': self.FILTER,
'destination': self.DESTINATION_URI,
}

conn = _Connection({})
client = _Client(conn)
api = self._make_one(client)

api.sink_create(
self.PROJECT,
self.SINK_NAME,
self.FILTER,
self.DESTINATION_URI,
unique_writer_identity=True,
)
path = '/projects/%s/sinks' % (self.PROJECT,)
expected = {
'method': 'POST',
'path': path,
'data': sent,
'query_params': {'uniqueWriterIdentity': True},
}
self.assertEqual(conn._called_with, expected)

def test_sink_get_miss(self):
from google.cloud.exceptions import NotFound

Expand Down
23 changes: 19 additions & 4 deletions logging/tests/unit/test_sink.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,14 @@ def test_create_w_bound_client(self):

self.assertEqual(
api._sink_create_called_with,
(self.PROJECT, self.SINK_NAME, self.FILTER, self.DESTINATION_URI))
(
self.PROJECT,
self.SINK_NAME,
self.FILTER,
self.DESTINATION_URI,
False,
),
)

def test_create_w_alternate_client(self):
client1 = _Client(project=self.PROJECT)
Expand All @@ -116,7 +123,14 @@ def test_create_w_alternate_client(self):

self.assertEqual(
api._sink_create_called_with,
(self.PROJECT, self.SINK_NAME, self.FILTER, self.DESTINATION_URI))
(
self.PROJECT,
self.SINK_NAME,
self.FILTER,
self.DESTINATION_URI,
False,
),
)

def test_exists_miss_w_bound_client(self):
client = _Client(project=self.PROJECT)
Expand Down Expand Up @@ -255,9 +269,10 @@ def __init__(self, project):

class _DummySinksAPI(object):

def sink_create(self, project, sink_name, filter_, destination):
def sink_create(self, project, sink_name, filter_, destination,
unique_writer_identity=False):
self._sink_create_called_with = (
project, sink_name, filter_, destination)
project, sink_name, filter_, destination, unique_writer_identity)

def sink_get(self, project, sink_name):
from google.cloud.exceptions import NotFound
Expand Down