def post(self): """Subscribe a machine to a Cloud Pub/Sub topic. Params: backend_project: If specified, project that the machine subscription topic is contained in for the backend. backend_attributes: If specified, JSON-encoded dict of attributes to include in the machine subscription message for the backend. backend_topic: If specified, topic that the machine subscription should be published to for the backend. hostname: Hostname being reclaimed. machine_id: ID of the CatalogMachineEntry being reclaimed. machine_service_account: Service account to authorize to consume the subscription. machine_subscription: Cloud Pub/Sub subscription to create for the machine. machine_subscription_project: Project the Cloud Pub/Sub subscription should live in. machine_topic: Cloud Pub/Sub topic to create for the machine. machine_topic_project: Project the Cloud Pub/Sub topic should live in. """ backend_attributes = json.loads( self.request.get('backend_attributes', {})) backend_project = self.request.get('backend_project') backend_topic = self.request.get('backend_topic') hostname = self.request.get('hostname') machine_id = self.request.get('machine_id') machine_service_account = self.request.get('machine_service_account') machine_subscription = self.request.get('machine_subscription') machine_subscription_project = self.request.get( 'machine_subscription_project') machine_topic = self.request.get('machine_topic') machine_topic_project = self.request.get('machine_topic_project') topic = pubsub.full_topic_name(machine_topic_project, machine_topic) subscription = pubsub.full_subscription_name( machine_subscription_project, machine_subscription) pubsub.ensure_subscription_deleted(subscription) pubsub.ensure_subscription_exists(subscription, topic) with pubsub.iam_policy(subscription) as policy: policy.add_member( 'roles/pubsub.subscriber', 'serviceAccount:%s' % machine_service_account, ) if backend_topic: attributes = backend_attributes.copy() attributes['hostname'] = hostname attributes['subscription'] = machine_subscription attributes['subscription_project'] = machine_subscription_project attributes['topic'] = machine_topic attributes['topic_project'] = machine_topic_project pubsub.publish( pubsub.full_topic_name(backend_project, backend_topic), 'SUBSCRIBED', attributes, ) set_available(ndb.Key(models.CatalogMachineEntry, machine_id))
def test_iam_policy_works(self): self.mock_requests([ # Returns empty policy. { 'url': 'https://pubsub.googleapis.com/v1/projects/a/topics/def:getIamPolicy', 'method': 'GET', 'payload': None, 'response': {'etag': 'blah'}, }, # Changes policy. Same etag is passed. { 'url': 'https://pubsub.googleapis.com/v1/projects/a/topics/def:setIamPolicy', 'method': 'POST', 'payload': { 'policy': { 'bindings': [{'role': 'role', 'members': ['member']}], 'etag': 'blah', }, }, }, ]) with pubsub.iam_policy('projects/a/topics/def') as p: p.add_member('role', 'member')
def post(self): """Subscribe a machine to a Cloud Pub/Sub topic. Params: backend_project: If specified, project that the machine subscription topic is contained in for the backend. backend_attributes: If specified, JSON-encoded dict of attributes to include in the machine subscription message for the backend. backend_topic: If specified, topic that the machine subscription should be published to for the backend. hostname: Hostname being reclaimed. machine_id: ID of the CatalogMachineEntry being reclaimed. machine_service_account: Service account to authorize to consume the subscription. machine_subscription: Cloud Pub/Sub subscription to create for the machine. machine_subscription_project: Project the Cloud Pub/Sub subscription should live in. machine_topic: Cloud Pub/Sub topic to create for the machine. machine_topic_project: Project the Cloud Pub/Sub topic should live in. """ backend_attributes = json.loads(self.request.get('backend_attributes', {})) backend_project = self.request.get('backend_project') backend_topic = self.request.get('backend_topic') hostname = self.request.get('hostname') machine_id = self.request.get('machine_id') machine_service_account = self.request.get('machine_service_account') machine_subscription = self.request.get('machine_subscription') machine_subscription_project = self.request.get( 'machine_subscription_project') machine_topic = self.request.get('machine_topic') machine_topic_project = self.request.get('machine_topic_project') topic = pubsub.full_topic_name(machine_topic_project, machine_topic) subscription = pubsub.full_subscription_name( machine_subscription_project, machine_subscription) pubsub.ensure_subscription_deleted(subscription) pubsub.ensure_subscription_exists(subscription, topic) with pubsub.iam_policy(subscription) as policy: policy.add_member( 'roles/pubsub.subscriber', 'serviceAccount:%s' % machine_service_account, ) if backend_topic: attributes = backend_attributes.copy() attributes['hostname'] = hostname attributes['subscription'] = machine_subscription attributes['subscription_project'] = machine_subscription_project attributes['topic'] = machine_topic attributes['topic_project'] = machine_topic_project pubsub.publish( pubsub.full_topic_name(backend_project, backend_topic), 'SUBSCRIBED', attributes, ) set_available(ndb.Key(models.CatalogMachineEntry, machine_id))
def revoke_stale_authorization(): """Removes pubsub.subscriber role from accounts that no longer have access.""" with pubsub.iam_policy(topic_name()) as p: for iam_ident in p.members('roles/pubsub.subscriber'): email = _iam_ident_to_email(iam_ident) if email: ident = auth.Identity.from_bytes('user:'******'Removing "%s" from subscribers list', iam_ident) p.remove_member('roles/pubsub.subscriber', iam_ident)
def test_iam_policy_skips_put_if_no_change(self): self.mock_requests([ { 'url': 'https://pubsub.googleapis.com/v1/projects/a/topics/def:getIamPolicy', 'method': 'GET', 'payload': None, 'response': {'etag': 'blah'}, }, ]) with pubsub.iam_policy('projects/a/topics/def'): pass
def test_iam_policy_skips_put_if_no_change(self): self.mock_requests( [ { "url": "https://pubsub.googleapis.com/v1/projects/a/topics/def:getIamPolicy", "method": "GET", "payload": None, "response": {"etag": "blah"}, } ] ) with pubsub.iam_policy("projects/a/topics/def"): pass
def test_iam_policy_works(self): self.mock_requests( [ # Returns empty policy. { "url": "https://pubsub.googleapis.com/v1/projects/a/topics/def:getIamPolicy", "method": "GET", "payload": None, "response": {"etag": "blah"}, }, # Changes policy. Same etag is passed. { "url": "https://pubsub.googleapis.com/v1/projects/a/topics/def:setIamPolicy", "method": "POST", "payload": {"policy": {"bindings": [{"role": "role", "members": ["member"]}], "etag": "blah"}}, }, ] ) with pubsub.iam_policy("projects/a/topics/def") as p: p.add_member("role", "member")
def deauthorize_subscriber(email): """Revokes authorization to attach subscriptions to the topic.""" with pubsub.iam_policy(topic_name()) as p: p.remove_member('roles/pubsub.subscriber', _email_to_iam_ident(email))
def authorize_subscriber(email): """Allows given user to attach subscriptions to the topic.""" with pubsub.iam_policy(topic_name()) as p: p.add_member('roles/pubsub.subscriber', _email_to_iam_ident(email))
def is_authorized_subscriber(email): """True if given user can attach subscriptions to the topic.""" with pubsub.iam_policy(topic_name()) as p: return _email_to_iam_ident(email) in p.members('roles/pubsub.subscriber')