1# -------------------------------------------------------------------------
2# Copyright (c) Microsoft Corporation. All rights reserved.
3# Licensed under the MIT License. See License.txt in the project root for
4# license information.
5# --------------------------------------------------------------------------
6from azure.common import (
7    AzureConflictHttpError,
8    AzureHttpError,
9)
10
11from ..common._auth import (
12    _StorageSASAuthentication,
13    _StorageSharedKeyAuthentication,
14)
15from ..common._common_conversion import (
16    _int_to_str,
17    _to_str,
18)
19from ..common._connection import _ServiceParameters
20from ..common._constants import (
21    SERVICE_HOST_BASE,
22    DEFAULT_PROTOCOL,
23)
24from ..common._deserialization import (
25    _convert_xml_to_service_properties,
26    _convert_xml_to_signed_identifiers,
27    _convert_xml_to_service_stats,
28)
29from ..common._error import (
30    _dont_fail_not_exist,
31    _dont_fail_on_exist,
32    _validate_not_none,
33    _ERROR_CONFLICT,
34    _ERROR_STORAGE_MISSING_INFO,
35    _validate_access_policies,
36    _validate_encryption_required,
37    _validate_decryption_required,
38)
39from ..common._http import (
40    HTTPRequest,
41)
42from ..common._serialization import (
43    _convert_signed_identifiers_to_xml,
44    _convert_service_properties_to_xml,
45)
46from ..common._serialization import (
47    _get_request_body,
48    _add_metadata_headers,
49)
50from ..common.models import (
51    Services,
52    ListGenerator,
53    _OperationContext,
54)
55from .sharedaccesssignature import (
56    QueueSharedAccessSignature,
57)
58from ..common.storageclient import StorageClient
59from ._deserialization import (
60    _convert_xml_to_queues,
61    _convert_xml_to_queue_messages,
62    _parse_queue_message_from_headers,
63    _parse_metadata_and_message_count,
64)
65from ._serialization import (
66    _convert_queue_message_xml,
67    _get_path,
68)
69from .models import (
70    QueueMessageFormat,
71)
72from ._constants import (
73    X_MS_VERSION,
74    __version__ as package_version,
75)
76
77_HTTP_RESPONSE_NO_CONTENT = 204
78
79
80class QueueService(StorageClient):
81    '''
82    This is the main class managing queue resources.
83
84    The Queue service stores messages. A queue can contain an unlimited number of
85    messages, each of which can be up to 64KB in size. Messages are generally added
86    to the end of the queue and retrieved from the front of the queue, although
87    first in, first out (FIFO) behavior is not guaranteed.
88
89    :ivar function(data) encode_function:
90        A function used to encode queue messages. Takes as
91        a parameter the data passed to the put_message API and returns the encoded
92        message. Defaults to take text and xml encode, but bytes and other
93        encodings can be used. For example, base64 may be preferable for developing
94        across multiple Azure Storage libraries in different languages. See the
95        :class:`~azure.storage.queue.models.QueueMessageFormat` for xml, base64 and
96        no encoding methods as well as binary equivalents.
97    :ivar function(data) decode_function:
98        A function used to encode decode messages. Takes as
99        a parameter the data returned by the get_messages and peek_messages APIs and
100        returns the decoded message. Defaults to return text and xml decode, but
101        bytes and other decodings can be used. For example, base64 may be preferable
102        for developing across multiple Azure Storage libraries in different languages.
103        See the :class:`~azure.storage.queue.models.QueueMessageFormat` for xml, base64
104        and no decoding methods as well as binary equivalents.
105    :ivar object key_encryption_key:
106        The key-encryption-key optionally provided by the user. If provided, will be used to
107        encrypt/decrypt in supported methods.
108        For methods requiring decryption, either the key_encryption_key OR the resolver must be provided.
109        If both are provided, the resolver will take precedence.
110        Must implement the following methods for APIs requiring encryption:
111        wrap_key(key)--wraps the specified key (bytes) using an algorithm of the user's choice. Returns the encrypted key as bytes.
112        get_key_wrap_algorithm()--returns the algorithm used to wrap the specified symmetric key.
113        get_kid()--returns a string key id for this key-encryption-key.
114        Must implement the following methods for APIs requiring decryption:
115        unwrap_key(key, algorithm)--returns the unwrapped form of the specified symmetric key using the string-specified algorithm.
116        get_kid()--returns a string key id for this key-encryption-key.
117    :ivar function key_resolver_function(kid):
118        A function to resolve keys optionally provided by the user. If provided, will be used to decrypt in supported methods.
119        For methods requiring decryption, either the key_encryption_key OR
120        the resolver must be provided. If both are provided, the resolver will take precedence.
121        It uses the kid string to return a key-encryption-key implementing the interface defined above.
122    :ivar bool require_encryption:
123        A flag that may be set to ensure that all messages successfully uploaded to the queue and all those downloaded and
124        successfully read from the queue are/were encrypted while on the server. If this flag is set, all required
125        parameters for encryption/decryption must be provided. See the above comments on the key_encryption_key and resolver.
126    '''
127
128    def __init__(self, account_name=None, account_key=None, sas_token=None, is_emulated=False,
129                 protocol=DEFAULT_PROTOCOL, endpoint_suffix=SERVICE_HOST_BASE, request_session=None,
130                 connection_string=None, socket_timeout=None, token_credential=None):
131        '''
132        :param str account_name:
133            The storage account name. This is used to authenticate requests
134            signed with an account key and to construct the storage endpoint. It
135            is required unless a connection string is given.
136        :param str account_key:
137            The storage account key. This is used for shared key authentication.
138        :param str sas_token:
139             A shared access signature token to use to authenticate requests
140             instead of the account key. If account key and sas token are both
141             specified, account key will be used to sign.
142        :param bool is_emulated:
143            Whether to use the emulator. Defaults to False. If specified, will
144            override all other parameters besides connection string and request
145            session.
146        :param str protocol:
147            The protocol to use for requests. Defaults to https.
148        :param str endpoint_suffix:
149            The host base component of the url, minus the account name. Defaults
150            to Azure (core.windows.net). Override this to use the China cloud
151            (core.chinacloudapi.cn).
152        :param requests.Session request_session:
153            The session object to use for http requests.
154        :param str connection_string:
155            If specified, this will override all other parameters besides
156            request session. See
157            http://azure.microsoft.com/en-us/documentation/articles/storage-configure-connection-string/
158            for the connection string format.
159        :param int socket_timeout:
160            If specified, this will override the default socket timeout. The timeout specified is in seconds.
161            See DEFAULT_SOCKET_TIMEOUT in _constants.py for the default value.
162        :param token_credential:
163            A token credential used to authenticate HTTPS requests. The token value
164            should be updated before its expiration.
165        :type `~azure.storage.common.TokenCredential`
166        '''
167        service_params = _ServiceParameters.get_service_parameters(
168            'queue',
169            account_name=account_name,
170            account_key=account_key,
171            sas_token=sas_token,
172            token_credential=token_credential,
173            is_emulated=is_emulated,
174            protocol=protocol,
175            endpoint_suffix=endpoint_suffix,
176            request_session=request_session,
177            connection_string=connection_string,
178            socket_timeout=socket_timeout)
179
180        super(QueueService, self).__init__(service_params)
181
182        if self.account_key:
183            self.authentication = _StorageSharedKeyAuthentication(
184                self.account_name,
185                self.account_key,
186                self.is_emulated
187            )
188        elif self.sas_token:
189            self.authentication = _StorageSASAuthentication(self.sas_token)
190        elif self.token_credential:
191            self.authentication = self.token_credential
192        else:
193            raise ValueError(_ERROR_STORAGE_MISSING_INFO)
194
195        self.encode_function = QueueMessageFormat.text_xmlencode
196        self.decode_function = QueueMessageFormat.text_xmldecode
197        self.key_encryption_key = None
198        self.key_resolver_function = None
199        self.require_encryption = False
200        self._X_MS_VERSION = X_MS_VERSION
201        self._update_user_agent_string(package_version)
202
203    def generate_account_shared_access_signature(self, resource_types, permission,
204                                                 expiry, start=None, ip=None, protocol=None):
205        '''
206        Generates a shared access signature for the queue service.
207        Use the returned signature with the sas_token parameter of QueueService.
208
209        :param ResourceTypes resource_types:
210            Specifies the resource types that are accessible with the account SAS.
211        :param AccountPermissions permission:
212            The permissions associated with the shared access signature. The
213            user is restricted to operations allowed by the permissions.
214            Required unless an id is given referencing a stored access policy
215            which contains this field. This field must be omitted if it has been
216            specified in an associated stored access policy.
217        :param expiry:
218            The time at which the shared access signature becomes invalid.
219            Required unless an id is given referencing a stored access policy
220            which contains this field. This field must be omitted if it has
221            been specified in an associated stored access policy. Azure will always
222            convert values to UTC. If a date is passed in without timezone info, it
223            is assumed to be UTC.
224        :type expiry: datetime or str
225        :param start:
226            The time at which the shared access signature becomes valid. If
227            omitted, start time for this call is assumed to be the time when the
228            storage service receives the request. Azure will always convert values
229            to UTC. If a date is passed in without timezone info, it is assumed to
230            be UTC.
231        :type start: datetime or str
232        :param str ip:
233            Specifies an IP address or a range of IP addresses from which to accept requests.
234            If the IP address from which the request originates does not match the IP address
235            or address range specified on the SAS token, the request is not authenticated.
236            For example, specifying sip=168.1.5.65 or sip=168.1.5.60-168.1.5.70 on the SAS
237            restricts the request to those IP addresses.
238        :param str protocol:
239            Specifies the protocol permitted for a request made. The default value
240            is https,http. See :class:`~azure.storage.common.models.Protocol` for possible values.
241        :return: A Shared Access Signature (sas) token.
242        :rtype: str
243        '''
244        _validate_not_none('self.account_name', self.account_name)
245        _validate_not_none('self.account_key', self.account_key)
246
247        sas = QueueSharedAccessSignature(self.account_name, self.account_key)
248        return sas.generate_account(Services.QUEUE, resource_types, permission,
249                                    expiry, start=start, ip=ip, protocol=protocol)
250
251    def generate_queue_shared_access_signature(self, queue_name,
252                                               permission=None,
253                                               expiry=None,
254                                               start=None,
255                                               id=None,
256                                               ip=None, protocol=None, ):
257        '''
258        Generates a shared access signature for the queue.
259        Use the returned signature with the sas_token parameter of QueueService.
260
261        :param str queue_name:
262            The name of the queue to create a SAS token for.
263        :param QueuePermissions permission:
264            The permissions associated with the shared access signature. The
265            user is restricted to operations allowed by the permissions.
266            Required unless an id is given referencing a stored access policy
267            which contains this field. This field must be omitted if it has been
268            specified in an associated stored access policy.
269        :param expiry:
270            The time at which the shared access signature becomes invalid.
271            Required unless an id is given referencing a stored access policy
272            which contains this field. This field must be omitted if it has
273            been specified in an associated stored access policy. Azure will always
274            convert values to UTC. If a date is passed in without timezone info, it
275            is assumed to be UTC.
276        :type expiry: datetime or str
277        :param start:
278            The time at which the shared access signature becomes valid. If
279            omitted, start time for this call is assumed to be the time when the
280            storage service receives the request. Azure will always convert values
281            to UTC. If a date is passed in without timezone info, it is assumed to
282            be UTC.
283        :type start: datetime or str
284        :param str id:
285            A unique value up to 64 characters in length that correlates to a
286            stored access policy. To create a stored access policy, use :func:`~set_queue_acl`.
287        :param str ip:
288            Specifies an IP address or a range of IP addresses from which to accept requests.
289            If the IP address from which the request originates does not match the IP address
290            or address range specified on the SAS token, the request is not authenticated.
291            For example, specifying sip='168.1.5.65' or sip='168.1.5.60-168.1.5.70' on the SAS
292            restricts the request to those IP addresses.
293        :param str protocol:
294            Specifies the protocol permitted for a request made. The default value
295            is https,http. See :class:`~azure.storage.common.models.Protocol` for possible values.
296        :return: A Shared Access Signature (sas) token.
297        :rtype: str
298        '''
299        _validate_not_none('queue_name', queue_name)
300        _validate_not_none('self.account_name', self.account_name)
301        _validate_not_none('self.account_key', self.account_key)
302
303        sas = QueueSharedAccessSignature(self.account_name, self.account_key)
304        return sas.generate_queue(
305            queue_name,
306            permission=permission,
307            expiry=expiry,
308            start=start,
309            id=id,
310            ip=ip,
311            protocol=protocol,
312        )
313
314    def get_queue_service_stats(self, timeout=None):
315        '''
316        Retrieves statistics related to replication for the Queue service. It is
317        only available when read-access geo-redundant replication is enabled for
318        the storage account.
319
320        With geo-redundant replication, Azure Storage maintains your data durable
321        in two locations. In both locations, Azure Storage constantly maintains
322        multiple healthy replicas of your data. The location where you read,
323        create, update, or delete data is the primary storage account location.
324        The primary location exists in the region you choose at the time you
325        create an account via the Azure Management Azure classic portal, for
326        example, North Central US. The location to which your data is replicated
327        is the secondary location. The secondary location is automatically
328        determined based on the location of the primary; it is in a second data
329        center that resides in the same region as the primary location. Read-only
330        access is available from the secondary location, if read-access geo-redundant
331        replication is enabled for your storage account.
332
333        :param int timeout:
334            The timeout parameter is expressed in seconds.
335        :return: The queue service stats.
336        :rtype: :class:`~azure.storage.common.models.ServiceStats`
337        '''
338        request = HTTPRequest()
339        request.method = 'GET'
340        request.host_locations = self._get_host_locations(primary=False, secondary=True)
341        request.path = _get_path()
342        request.query = {
343            'restype': 'service',
344            'comp': 'stats',
345            'timeout': _int_to_str(timeout),
346        }
347
348        return self._perform_request(request, _convert_xml_to_service_stats)
349
350    def get_queue_service_properties(self, timeout=None):
351        '''
352        Gets the properties of a storage account's Queue service, including
353        logging, analytics and CORS rules.
354
355        :param int timeout:
356            The server timeout, expressed in seconds.
357        :return: The queue service properties.
358        :rtype: :class:`~azure.storage.common.models.ServiceProperties`
359        '''
360        request = HTTPRequest()
361        request.method = 'GET'
362        request.host_locations = self._get_host_locations(secondary=True)
363        request.path = _get_path()
364        request.query = {
365            'restype': 'service',
366            'comp': 'properties',
367            'timeout': _int_to_str(timeout),
368        }
369
370        return self._perform_request(request, _convert_xml_to_service_properties)
371
372    def set_queue_service_properties(self, logging=None, hour_metrics=None,
373                                     minute_metrics=None, cors=None, timeout=None):
374        '''
375        Sets the properties of a storage account's Queue service, including
376        Azure Storage Analytics. If an element (ex Logging) is left as None, the
377        existing settings on the service for that functionality are preserved.
378        For more information on Azure Storage Analytics, see
379        https://msdn.microsoft.com/en-us/library/azure/hh343270.aspx.
380
381        :param Logging logging:
382            The logging settings provide request logs.
383        :param Metrics hour_metrics:
384            The hour metrics settings provide a summary of request
385            statistics grouped by API in hourly aggregates for queuess.
386        :param Metrics minute_metrics:
387            The minute metrics settings provide request statistics
388            for each minute for queues.
389        :param cors:
390            You can include up to five CorsRule elements in the
391            list. If an empty list is specified, all CORS rules will be deleted,
392            and CORS will be disabled for the service. For detailed information
393            about CORS rules and evaluation logic, see
394            https://msdn.microsoft.com/en-us/library/azure/dn535601.aspx.
395        :type cors: list(:class:`~azure.storage.common.models.CorsRule`)
396        :param int timeout:
397            The server timeout, expressed in seconds.
398        '''
399        request = HTTPRequest()
400        request.method = 'PUT'
401        request.host_locations = self._get_host_locations()
402        request.path = _get_path()
403        request.query = {
404            'restype': 'service',
405            'comp': 'properties',
406            'timeout': _int_to_str(timeout),
407        }
408        request.body = _get_request_body(
409            _convert_service_properties_to_xml(logging, hour_metrics, minute_metrics, cors))
410        self._perform_request(request)
411
412    def list_queues(self, prefix=None, num_results=None, include_metadata=False,
413                    marker=None, timeout=None):
414        '''
415        Returns a generator to list the queues. The generator will lazily follow
416        the continuation tokens returned by the service and stop when all queues
417        have been returned or num_results is reached.
418
419        If num_results is specified and the account has more than that number of
420        queues, the generator will have a populated next_marker field once it
421        finishes. This marker can be used to create a new generator if more
422        results are desired.
423
424        :param str prefix:
425            Filters the results to return only queues with names that begin
426            with the specified prefix.
427        :param int num_results:
428            The maximum number of queues to return.
429        :param bool include_metadata:
430            Specifies that container metadata be returned in the response.
431        :param str marker:
432            An opaque continuation token. This value can be retrieved from the
433            next_marker field of a previous generator object if num_results was
434            specified and that generator has finished enumerating results. If
435            specified, this generator will begin returning results from the point
436            where the previous generator stopped.
437        :param int timeout:
438            The server timeout, expressed in seconds. This function may make multiple
439            calls to the service in which case the timeout value specified will be
440            applied to each individual call.
441        '''
442        include = 'metadata' if include_metadata else None
443        operation_context = _OperationContext(location_lock=True)
444        kwargs = {'prefix': prefix, 'max_results': num_results, 'include': include,
445                  'marker': marker, 'timeout': timeout, '_context': operation_context}
446        resp = self._list_queues(**kwargs)
447
448        return ListGenerator(resp, self._list_queues, (), kwargs)
449
450    def _list_queues(self, prefix=None, marker=None, max_results=None,
451                     include=None, timeout=None, _context=None):
452        '''
453        Returns a list of queues under the specified account. Makes a single list
454        request to the service. Used internally by the list_queues method.
455
456        :param str prefix:
457            Filters the results to return only queues with names that begin
458            with the specified prefix.
459        :param str marker:
460            A token which identifies the portion of the query to be
461            returned with the next query operation. The operation returns a
462            next_marker element within the response body if the list returned
463            was not complete. This value may then be used as a query parameter
464            in a subsequent call to request the next portion of the list of
465            queues. The marker value is opaque to the client.
466        :param int max_results:
467            The maximum number of queues to return. A single list request may
468            return up to 1000 queues and potentially a continuation token which
469            should be followed to get additional resutls.
470        :param str include:
471            Include this parameter to specify that the container's
472            metadata be returned as part of the response body.
473        :param int timeout:
474            The server timeout, expressed in seconds.
475        '''
476        request = HTTPRequest()
477        request.method = 'GET'
478        request.host_locations = self._get_host_locations(secondary=True)
479        request.path = _get_path()
480        request.query = {
481            'comp': 'list',
482            'prefix': _to_str(prefix),
483            'marker': _to_str(marker),
484            'maxresults': _int_to_str(max_results),
485            'include': _to_str(include),
486            'timeout': _int_to_str(timeout)
487        }
488
489        return self._perform_request(request, _convert_xml_to_queues, operation_context=_context)
490
491    def create_queue(self, queue_name, metadata=None, fail_on_exist=False, timeout=None):
492        '''
493        Creates a queue under the given account.
494
495        :param str queue_name:
496            The name of the queue to create. A queue name must be from 3 through
497            63 characters long and may only contain lowercase letters, numbers,
498            and the dash (-) character. The first and last letters in the queue
499            must be alphanumeric. The dash (-) character cannot be the first or
500            last character. Consecutive dash characters are not permitted in the
501            queue name.
502        :param metadata:
503            A dict containing name-value pairs to associate with the queue as
504            metadata. Note that metadata names preserve the case with which they
505            were created, but are case-insensitive when set or read.
506        :type metadata: dict(str, str)
507        :param bool fail_on_exist:
508            Specifies whether to throw an exception if the queue already exists.
509        :param int timeout:
510            The server timeout, expressed in seconds.
511        :return:
512            A boolean indicating whether the queue was created. If fail_on_exist
513            was set to True, this will throw instead of returning false.
514        :rtype: bool
515        '''
516        _validate_not_none('queue_name', queue_name)
517        request = HTTPRequest()
518        request.method = 'PUT'
519        request.host_locations = self._get_host_locations()
520        request.path = _get_path(queue_name)
521        request.query = {'timeout': _int_to_str(timeout)}
522        _add_metadata_headers(metadata, request)
523
524        def _return_request(request):
525            return request
526
527        if not fail_on_exist:
528            try:
529                response = self._perform_request(request, parser=_return_request)
530                if response.status == _HTTP_RESPONSE_NO_CONTENT:
531                    return False
532                return True
533            except AzureHttpError as ex:
534                _dont_fail_on_exist(ex)
535                return False
536        else:
537            response = self._perform_request(request, parser=_return_request)
538            if response.status == _HTTP_RESPONSE_NO_CONTENT:
539                raise AzureConflictHttpError(
540                    _ERROR_CONFLICT.format(response.message), response.status)
541            return True
542
543    def delete_queue(self, queue_name, fail_not_exist=False, timeout=None):
544        '''
545        Deletes the specified queue and any messages it contains.
546
547        When a queue is successfully deleted, it is immediately marked for deletion
548        and is no longer accessible to clients. The queue is later removed from
549        the Queue service during garbage collection.
550
551        Note that deleting a queue is likely to take at least 40 seconds to complete.
552        If an operation is attempted against the queue while it was being deleted,
553        an :class:`AzureConflictHttpError` will be thrown.
554
555        :param str queue_name:
556            The name of the queue to delete.
557        :param bool fail_not_exist:
558            Specifies whether to throw an exception if the queue doesn't exist.
559        :param int timeout:
560            The server timeout, expressed in seconds.
561        :return:
562            A boolean indicating whether the queue was deleted. If fail_not_exist
563            was set to True, this will throw instead of returning false.
564        :rtype: bool
565        '''
566        _validate_not_none('queue_name', queue_name)
567        request = HTTPRequest()
568        request.method = 'DELETE'
569        request.host_locations = self._get_host_locations()
570        request.path = _get_path(queue_name)
571        request.query = {'timeout': _int_to_str(timeout)}
572        if not fail_not_exist:
573            try:
574                self._perform_request(request)
575                return True
576            except AzureHttpError as ex:
577                _dont_fail_not_exist(ex)
578                return False
579        else:
580            self._perform_request(request)
581            return True
582
583    def get_queue_metadata(self, queue_name, timeout=None):
584        '''
585        Retrieves user-defined metadata and queue properties on the specified
586        queue. Metadata is associated with the queue as name-value pairs.
587
588        :param str queue_name:
589            The name of an existing queue.
590        :param int timeout:
591            The server timeout, expressed in seconds.
592        :return:
593            A dictionary representing the queue metadata with an
594            approximate_message_count int property on the dict estimating the
595            number of messages in the queue.
596        :rtype: dict(str, str)
597        '''
598        _validate_not_none('queue_name', queue_name)
599        request = HTTPRequest()
600        request.method = 'GET'
601        request.host_locations = self._get_host_locations(secondary=True)
602        request.path = _get_path(queue_name)
603        request.query = {
604            'comp': 'metadata',
605            'timeout': _int_to_str(timeout),
606        }
607
608        return self._perform_request(request, _parse_metadata_and_message_count)
609
610    def set_queue_metadata(self, queue_name, metadata=None, timeout=None):
611        '''
612        Sets user-defined metadata on the specified queue. Metadata is
613        associated with the queue as name-value pairs.
614
615        :param str queue_name:
616            The name of an existing queue.
617        :param dict metadata:
618            A dict containing name-value pairs to associate with the
619            queue as metadata.
620        :param int timeout:
621            The server timeout, expressed in seconds.
622        '''
623        _validate_not_none('queue_name', queue_name)
624        request = HTTPRequest()
625        request.method = 'PUT'
626        request.host_locations = self._get_host_locations()
627        request.path = _get_path(queue_name)
628        request.query = {
629            'comp': 'metadata',
630            'timeout': _int_to_str(timeout),
631        }
632        _add_metadata_headers(metadata, request)
633
634        self._perform_request(request)
635
636    def exists(self, queue_name, timeout=None):
637        '''
638        Returns a boolean indicating whether the queue exists.
639
640        :param str queue_name:
641            The name of queue to check for existence.
642        :param int timeout:
643            The server timeout, expressed in seconds.
644        :return: A boolean indicating whether the queue exists.
645        :rtype: bool
646        '''
647        try:
648            self.get_queue_metadata(queue_name, timeout=timeout)
649            return True
650        except AzureHttpError as ex:
651            _dont_fail_not_exist(ex)
652            return False
653
654    def get_queue_acl(self, queue_name, timeout=None):
655        '''
656        Returns details about any stored access policies specified on the
657        queue that may be used with Shared Access Signatures.
658
659        :param str queue_name:
660            The name of an existing queue.
661        :param int timeout:
662            The server timeout, expressed in seconds.
663        :return: A dictionary of access policies associated with the queue.
664        :rtype: dict(str, :class:`~azure.storage.common.models.AccessPolicy`)
665        '''
666        _validate_not_none('queue_name', queue_name)
667        request = HTTPRequest()
668        request.method = 'GET'
669        request.host_locations = self._get_host_locations(secondary=True)
670        request.path = _get_path(queue_name)
671        request.query = {
672            'comp': 'acl',
673            'timeout': _int_to_str(timeout),
674        }
675
676        return self._perform_request(request, _convert_xml_to_signed_identifiers)
677
678    def set_queue_acl(self, queue_name, signed_identifiers=None, timeout=None):
679        '''
680        Sets stored access policies for the queue that may be used with Shared
681        Access Signatures.
682
683        When you set permissions for a queue, the existing permissions are replaced.
684        To update the queue's permissions, call :func:`~get_queue_acl` to fetch
685        all access policies associated with the queue, modify the access policy
686        that you wish to change, and then call this function with the complete
687        set of data to perform the update.
688
689        When you establish a stored access policy on a queue, it may take up to
690        30 seconds to take effect. During this interval, a shared access signature
691        that is associated with the stored access policy will throw an
692        :class:`AzureHttpError` until the access policy becomes active.
693
694        :param str queue_name:
695            The name of an existing queue.
696        :param signed_identifiers:
697            A dictionary of access policies to associate with the queue. The
698            dictionary may contain up to 5 elements. An empty dictionary
699            will clear the access policies set on the service.
700        :type signed_identifiers: dict(str, :class:`~azure.storage.common.models.AccessPolicy`)
701        :param int timeout:
702            The server timeout, expressed in seconds.
703        '''
704        _validate_not_none('queue_name', queue_name)
705        _validate_access_policies(signed_identifiers)
706        request = HTTPRequest()
707        request.method = 'PUT'
708        request.host_locations = self._get_host_locations()
709        request.path = _get_path(queue_name)
710        request.query = {
711            'comp': 'acl',
712            'timeout': _int_to_str(timeout),
713        }
714        request.body = _get_request_body(
715            _convert_signed_identifiers_to_xml(signed_identifiers))
716        self._perform_request(request)
717
718    def put_message(self, queue_name, content, visibility_timeout=None,
719                    time_to_live=None, timeout=None):
720        '''
721        Adds a new message to the back of the message queue.
722
723        The visibility timeout specifies the time that the message will be
724        invisible. After the timeout expires, the message will become visible.
725        If a visibility timeout is not specified, the default value of 0 is used.
726
727        The message time-to-live specifies how long a message will remain in the
728        queue. The message will be deleted from the queue when the time-to-live
729        period expires.
730
731        If the key-encryption-key field is set on the local service object, this method will
732        encrypt the content before uploading.
733
734        :param str queue_name:
735            The name of the queue to put the message into.
736        :param obj content:
737            Message content. Allowed type is determined by the encode_function
738            set on the service. Default is str. The encoded message can be up to
739            64KB in size.
740        :param int visibility_timeout:
741            If not specified, the default value is 0. Specifies the
742            new visibility timeout value, in seconds, relative to server time.
743            The value must be larger than or equal to 0, and cannot be
744            larger than 7 days. The visibility timeout of a message cannot be
745            set to a value later than the expiry time. visibility_timeout
746            should be set to a value smaller than the time-to-live value.
747        :param int time_to_live:
748            Specifies the time-to-live interval for the message, in
749            seconds. The time-to-live may be any positive number or -1 for infinity. If this
750            parameter is omitted, the default time-to-live is 7 days.
751        :param int timeout:
752            The server timeout, expressed in seconds.
753        :return:
754            A :class:`~azure.storage.queue.models.QueueMessage` object.
755            This object is also populated with the content although it is not
756            returned from the service.
757        :rtype: :class:`~azure.storage.queue.models.QueueMessage`
758        '''
759
760        _validate_encryption_required(self.require_encryption, self.key_encryption_key)
761
762        _validate_not_none('queue_name', queue_name)
763        _validate_not_none('content', content)
764        request = HTTPRequest()
765        request.method = 'POST'
766        request.host_locations = self._get_host_locations()
767        request.path = _get_path(queue_name, True)
768        request.query = {
769            'visibilitytimeout': _to_str(visibility_timeout),
770            'messagettl': _to_str(time_to_live),
771            'timeout': _int_to_str(timeout)
772        }
773
774        request.body = _get_request_body(_convert_queue_message_xml(content, self.encode_function,
775                                                                    self.key_encryption_key))
776
777        message_list = self._perform_request(request, _convert_xml_to_queue_messages,
778                                             [self.decode_function, False,
779                                              None, None, content])
780        return message_list[0]
781
782    def get_messages(self, queue_name, num_messages=None,
783                     visibility_timeout=None, timeout=None):
784        '''
785        Retrieves one or more messages from the front of the queue.
786
787        When a message is retrieved from the queue, the response includes the message
788        content and a pop_receipt value, which is required to delete the message.
789        The message is not automatically deleted from the queue, but after it has
790        been retrieved, it is not visible to other clients for the time interval
791        specified by the visibility_timeout parameter.
792
793        If the key-encryption-key or resolver field is set on the local service object, the messages will be
794        decrypted before being returned.
795
796        :param str queue_name:
797            The name of the queue to get messages from.
798        :param int num_messages:
799            A nonzero integer value that specifies the number of
800            messages to retrieve from the queue, up to a maximum of 32. If
801            fewer are visible, the visible messages are returned. By default,
802            a single message is retrieved from the queue with this operation.
803        :param int visibility_timeout:
804            Specifies the new visibility timeout value, in seconds, relative
805            to server time. The new value must be larger than or equal to 1
806            second, and cannot be larger than 7 days. The visibility timeout of
807            a message can be set to a value later than the expiry time.
808        :param int timeout:
809            The server timeout, expressed in seconds.
810        :return: A :class:`~azure.storage.queue.models.QueueMessage` object representing the information passed.
811        :rtype: list(:class:`~azure.storage.queue.models.QueueMessage`)
812        '''
813        _validate_decryption_required(self.require_encryption, self.key_encryption_key,
814                                      self.key_resolver_function)
815
816        _validate_not_none('queue_name', queue_name)
817        request = HTTPRequest()
818        request.method = 'GET'
819        request.host_locations = self._get_host_locations()
820        request.path = _get_path(queue_name, True)
821        request.query = {
822            'numofmessages': _to_str(num_messages),
823            'visibilitytimeout': _to_str(visibility_timeout),
824            'timeout': _int_to_str(timeout)
825        }
826
827        return self._perform_request(request, _convert_xml_to_queue_messages,
828                                     [self.decode_function, self.require_encryption,
829                                      self.key_encryption_key, self.key_resolver_function])
830
831    def peek_messages(self, queue_name, num_messages=None, timeout=None):
832        '''
833        Retrieves one or more messages from the front of the queue, but does
834        not alter the visibility of the message.
835
836        Only messages that are visible may be retrieved. When a message is retrieved
837        for the first time with a call to get_messages, its dequeue_count property
838        is set to 1. If it is not deleted and is subsequently retrieved again, the
839        dequeue_count property is incremented. The client may use this value to
840        determine how many times a message has been retrieved. Note that a call
841        to peek_messages does not increment the value of DequeueCount, but returns
842        this value for the client to read.
843
844        If the key-encryption-key or resolver field is set on the local service object, the messages will be
845        decrypted before being returned.
846
847        :param str queue_name:
848            The name of the queue to peek messages from.
849        :param int num_messages:
850            A nonzero integer value that specifies the number of
851            messages to peek from the queue, up to a maximum of 32. By default,
852            a single message is peeked from the queue with this operation.
853        :param int timeout:
854            The server timeout, expressed in seconds.
855        :return:
856            A list of :class:`~azure.storage.queue.models.QueueMessage` objects. Note that
857            time_next_visible and pop_receipt will not be populated as peek does
858            not pop the message and can only retrieve already visible messages.
859        :rtype: list(:class:`~azure.storage.queue.models.QueueMessage`)
860        '''
861
862        _validate_decryption_required(self.require_encryption, self.key_encryption_key,
863                                      self.key_resolver_function)
864
865        _validate_not_none('queue_name', queue_name)
866        request = HTTPRequest()
867        request.method = 'GET'
868        request.host_locations = self._get_host_locations(secondary=True)
869        request.path = _get_path(queue_name, True)
870        request.query = {
871            'peekonly': 'true',
872            'numofmessages': _to_str(num_messages),
873            'timeout': _int_to_str(timeout)
874        }
875
876        return self._perform_request(request, _convert_xml_to_queue_messages,
877                                     [self.decode_function, self.require_encryption,
878                                      self.key_encryption_key, self.key_resolver_function])
879
880    def delete_message(self, queue_name, message_id, pop_receipt, timeout=None):
881        '''
882        Deletes the specified message.
883
884        Normally after a client retrieves a message with the get_messages operation,
885        the client is expected to process and delete the message. To delete the
886        message, you must have two items of data: id and pop_receipt. The
887        id is returned from the previous get_messages operation. The
888        pop_receipt is returned from the most recent :func:`~get_messages` or
889        :func:`~update_message` operation. In order for the delete_message operation
890        to succeed, the pop_receipt specified on the request must match the
891        pop_receipt returned from the :func:`~get_messages` or :func:`~update_message`
892        operation.
893
894        :param str queue_name:
895            The name of the queue from which to delete the message.
896        :param str message_id:
897            The message id identifying the message to delete.
898        :param str pop_receipt:
899            A valid pop receipt value returned from an earlier call
900            to the :func:`~get_messages` or :func:`~update_message`.
901        :param int timeout:
902            The server timeout, expressed in seconds.
903        '''
904        _validate_not_none('queue_name', queue_name)
905        _validate_not_none('message_id', message_id)
906        _validate_not_none('pop_receipt', pop_receipt)
907        request = HTTPRequest()
908        request.method = 'DELETE'
909        request.host_locations = self._get_host_locations()
910        request.path = _get_path(queue_name, True, message_id)
911        request.query = {
912            'popreceipt': _to_str(pop_receipt),
913            'timeout': _int_to_str(timeout)
914        }
915        self._perform_request(request)
916
917    def clear_messages(self, queue_name, timeout=None):
918        '''
919        Deletes all messages from the specified queue.
920
921        :param str queue_name:
922            The name of the queue whose messages to clear.
923        :param int timeout:
924            The server timeout, expressed in seconds.
925        '''
926        _validate_not_none('queue_name', queue_name)
927        request = HTTPRequest()
928        request.method = 'DELETE'
929        request.host_locations = self._get_host_locations()
930        request.path = _get_path(queue_name, True)
931        request.query = {'timeout': _int_to_str(timeout)}
932        self._perform_request(request)
933
934    def update_message(self, queue_name, message_id, pop_receipt, visibility_timeout,
935                       content=None, timeout=None):
936        '''
937        Updates the visibility timeout of a message. You can also use this
938        operation to update the contents of a message.
939
940        This operation can be used to continually extend the invisibility of a
941        queue message. This functionality can be useful if you want a worker role
942        to "lease" a queue message. For example, if a worker role calls get_messages
943        and recognizes that it needs more time to process a message, it can
944        continually extend the message's invisibility until it is processed. If
945        the worker role were to fail during processing, eventually the message
946        would become visible again and another worker role could process it.
947
948        If the key-encryption-key field is set on the local service object, this method will
949        encrypt the content before uploading.
950
951        :param str queue_name:
952            The name of the queue containing the message to update.
953        :param str message_id:
954            The message id identifying the message to update.
955        :param str pop_receipt:
956            A valid pop receipt value returned from an earlier call
957            to the :func:`~get_messages` or :func:`~update_message` operation.
958        :param int visibility_timeout:
959            Specifies the new visibility timeout value, in seconds,
960            relative to server time. The new value must be larger than or equal
961            to 0, and cannot be larger than 7 days. The visibility timeout of a
962            message cannot be set to a value later than the expiry time. A
963            message can be updated until it has been deleted or has expired.
964        :param obj content:
965            Message content. Allowed type is determined by the encode_function
966            set on the service. Default is str.
967        :param int timeout:
968            The server timeout, expressed in seconds.
969        :return:
970            A list of :class:`~azure.storage.queue.models.QueueMessage` objects. For convenience,
971            this object is also populated with the content, although it is not returned by the service.
972        :rtype: list(:class:`~azure.storage.queue.models.QueueMessage`)
973        '''
974
975        _validate_encryption_required(self.require_encryption, self.key_encryption_key)
976
977        _validate_not_none('queue_name', queue_name)
978        _validate_not_none('message_id', message_id)
979        _validate_not_none('pop_receipt', pop_receipt)
980        _validate_not_none('visibility_timeout', visibility_timeout)
981        request = HTTPRequest()
982        request.method = 'PUT'
983        request.host_locations = self._get_host_locations()
984        request.path = _get_path(queue_name, True, message_id)
985        request.query = {
986            'popreceipt': _to_str(pop_receipt),
987            'visibilitytimeout': _int_to_str(visibility_timeout),
988            'timeout': _int_to_str(timeout)
989        }
990
991        if content is not None:
992            request.body = _get_request_body(_convert_queue_message_xml(content, self.encode_function,
993                                                                        self.key_encryption_key))
994
995        return self._perform_request(request, _parse_queue_message_from_headers)
996