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