1# Licensed under the Apache License, Version 2.0 (the "License"); you may 2# not use this file except in compliance with the License. You may obtain 3# a copy of the License at 4# 5# http://www.apache.org/licenses/LICENSE-2.0 6# 7# Unless required by applicable law or agreed to in writing, software 8# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 9# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the 10# License for the specific language governing permissions and limitations 11# under the License. 12 13import uuid 14 15from openstack import resource 16 17 18class Subscription(resource.Resource): 19 # FIXME(anyone): The name string of `location` field of Zaqar API response 20 # is lower case. That is inconsistent with the guide from API-WG. This is 21 # a workaround for this issue. 22 location = resource.Header("location") 23 24 resources_key = 'subscriptions' 25 base_path = '/queues/%(queue_name)s/subscriptions' 26 27 # capabilities 28 allow_create = True 29 allow_list = True 30 allow_fetch = True 31 allow_delete = True 32 33 # Properties 34 #: The value in seconds indicating how long the subscription has existed. 35 age = resource.Body("age") 36 #: Alternate id of the subscription. This key is used in response of 37 #: subscription create API to return id of subscription created. 38 subscription_id = resource.Body("subscription_id", alternate_id=True) 39 #: The extra metadata for the subscription. The value must be a dict. 40 #: If the subscriber is `mailto`. The options can contain `from` and 41 #: `subject` to indicate the email's author and title. 42 options = resource.Body("options", type=dict) 43 #: The queue name which the subscription is registered on. 44 source = resource.Body("source") 45 #: The destination of the message. Two kinds of subscribers are supported: 46 #: http/https and email. The http/https subscriber should start with 47 #: `http/https`. The email subscriber should start with `mailto`. 48 subscriber = resource.Body("subscriber") 49 #: Number of seconds the subscription remains alive? The ttl value must 50 #: be great than 60 seconds. The default value is 3600 seconds. 51 ttl = resource.Body("ttl") 52 #: The queue name which the subscription is registered on. 53 queue_name = resource.URI("queue_name") 54 #: The ID to identify the client accessing Zaqar API. Must be specified 55 #: in header for each API request. 56 client_id = resource.Header("Client-ID") 57 #: The ID to identify the project. Must be provided when keystone 58 #: authentication is not enabled in Zaqar service. 59 project_id = resource.Header("X-PROJECT-ID") 60 61 def create(self, session, prepend_key=True, base_path=None): 62 request = self._prepare_request(requires_id=False, 63 prepend_key=prepend_key, 64 base_path=base_path) 65 headers = { 66 "Client-ID": self.client_id or str(uuid.uuid4()), 67 "X-PROJECT-ID": self.project_id or session.get_project_id() 68 } 69 request.headers.update(headers) 70 response = session.post(request.url, 71 json=request.body, headers=request.headers) 72 73 self._translate_response(response) 74 return self 75 76 @classmethod 77 def list(cls, session, paginated=True, base_path=None, **params): 78 """This method is a generator which yields subscription objects. 79 80 This is almost the copy of list method of resource.Resource class. 81 The only difference is the request header now includes `Client-ID` 82 and `X-PROJECT-ID` fields which are required by Zaqar v2 API. 83 """ 84 more_data = True 85 86 if base_path is None: 87 base_path = cls.base_path 88 89 uri = base_path % params 90 headers = { 91 "Client-ID": params.get('client_id', None) or str(uuid.uuid4()), 92 "X-PROJECT-ID": params.get('project_id', None 93 ) or session.get_project_id() 94 } 95 96 query_params = cls._query_mapping._transpose(params, cls) 97 while more_data: 98 resp = session.get(uri, 99 headers=headers, params=query_params) 100 resp = resp.json() 101 resp = resp[cls.resources_key] 102 103 if not resp: 104 more_data = False 105 106 yielded = 0 107 new_marker = None 108 for data in resp: 109 value = cls.existing(**data) 110 new_marker = value.id 111 yielded += 1 112 yield value 113 114 if not paginated: 115 return 116 if "limit" in query_params and yielded < query_params["limit"]: 117 return 118 query_params["limit"] = yielded 119 query_params["marker"] = new_marker 120 121 def fetch(self, session, requires_id=True, 122 base_path=None, error_message=None): 123 request = self._prepare_request(requires_id=requires_id, 124 base_path=base_path) 125 headers = { 126 "Client-ID": self.client_id or str(uuid.uuid4()), 127 "X-PROJECT-ID": self.project_id or session.get_project_id() 128 } 129 130 request.headers.update(headers) 131 response = session.get(request.url, 132 headers=request.headers) 133 self._translate_response(response) 134 135 return self 136 137 def delete(self, session): 138 request = self._prepare_request() 139 headers = { 140 "Client-ID": self.client_id or str(uuid.uuid4()), 141 "X-PROJECT-ID": self.project_id or session.get_project_id() 142 } 143 144 request.headers.update(headers) 145 response = session.delete(request.url, 146 headers=request.headers) 147 148 self._translate_response(response, has_body=False) 149 return self 150