def set_queue_metadata(self, queue_name, x_ms_meta_name_values=None): ''' Sets user-defined metadata on the specified queue. Metadata is associated with the queue as name-value pairs. queue_name: Name of the queue. x_ms_meta_name_values: Optional. A dict containing name-value pairs to associate with the queue as metadata. ''' _validate_not_none('queue_name', queue_name) request = HTTPRequest() request.method = 'PUT' request.host = self._get_host() request.path = '/' + _str(queue_name) + '?comp=metadata' request.headers = [('x-ms-meta-name-values', x_ms_meta_name_values)] request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_queue_header(request, self.account_name, self.account_key) self._perform_request(request)
def get_queue_metadata(self, queue_name): ''' Retrieves user-defined metadata and queue properties on the specified queue. Metadata is associated with the queue as name-values pairs. queue_name: Name of the queue. ''' _validate_not_none('queue_name', queue_name) request = HTTPRequest() request.method = 'GET' request.host = self._get_host() request.path = '/' + _str(queue_name) + '?comp=metadata' request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_queue_header(request, self.account_name, self.account_key) response = self._perform_request(request) return _parse_response_for_dict_prefix( response, prefixes=['x-ms-meta', 'x-ms-approximate-messages-count'])
def perform_put(self, path, body, x_ms_version=None): ''' Performs a PUT request and returns the response. path: Path to the resource. Ex: '/<subscription-id>/services/hostedservices/<service-name>' body: Body for the PUT request. x_ms_version: If specified, this is used for the x-ms-version header. Otherwise, self.x_ms_version is used. ''' request = HTTPRequest() request.method = 'PUT' request.host = self.host request.path = path request.body = _get_request_body(body) request.path, request.query = _update_request_uri_query(request) request.headers = self._update_management_header(request, x_ms_version) response = self._perform_request(request) return response
def delete_message(self, queue_name, message_id, popreceipt): ''' Deletes the specified message. queue_name: name of the queue. popreceipt: Required. A valid pop receipt value returned from an earlier call to the Get Messages or Update Message operation. ''' _validate_not_none('queue_name', queue_name) _validate_not_none('message_id', message_id) _validate_not_none('popreceipt', popreceipt) request = HTTPRequest() request.method = 'DELETE' request.host = self._get_host() request.path = '/' + str(queue_name) + '/messages/' + str( message_id) + '' request.query = [('popreceipt', _str_or_none(popreceipt))] request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_queue_header(request, self.account_name, self.account_key) response = self._perform_request(request)
def create_container(self, container_name, x_ms_meta_name_values=None, x_ms_blob_public_access=None, fail_on_exist=False): ''' Creates a new container under the specified account. If the container with the same name already exists, the operation fails. x_ms_meta_name_values: Optional. A dict with name_value pairs to associate with the container as metadata. Example:{'Category':'test'} x_ms_blob_public_access: Optional. Possible values include: container, blob. fail_on_exist: specify whether to throw an exception when the container exists. ''' _validate_not_none('container_name', container_name) request = HTTPRequest() request.method = 'PUT' request.host = self._get_host() request.path = '/' + str(container_name) + '?restype=container' request.headers = [('x-ms-meta-name-values', x_ms_meta_name_values), ('x-ms-blob-public-access', _str_or_none(x_ms_blob_public_access))] request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_blob_header(request, self.account_name, self.account_key) if not fail_on_exist: try: self._perform_request(request) return True except WindowsAzureError as e: _dont_fail_on_exist(e) return False else: self._perform_request(request) return True
def insert_or_merge_entity(self, table_name, partition_key, row_key, entity, content_type='application/atom+xml'): ''' Merges an existing entity or inserts a new entity if it does not exist in the table. Because this operation can insert or update an entity, it is also known as an "upsert" operation. table_name: Table name. partition_key: PartitionKey of the entity. row_key: RowKey of the entity. entity: Required. The entity object to insert. Could be a dict format or entity object. content_type: Required. Must be set to application/atom+xml ''' _validate_not_none('table_name', table_name) _validate_not_none('partition_key', partition_key) _validate_not_none('row_key', row_key) _validate_not_none('entity', entity) _validate_not_none('content_type', content_type) request = HTTPRequest() request.method = 'MERGE' request.host = self._get_host() request.path = '/' + _str(table_name) + '(PartitionKey=\'' + _str( partition_key) + '\',RowKey=\'' + _str(row_key) + '\')' request.headers = [('Content-Type', _str_or_none(content_type))] request.body = _get_request_body(_convert_entity_to_xml(entity)) request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_table_header(request) response = self._perform_request(request) return _parse_response_for_dict_filter(response, filter=['etag'])
def delete_rule(self, topic_name, subscription_name, rule_name, fail_not_exist=False): ''' Deletes an existing rule. topic_name: Name of the topic. subscription_name: Name of the subscription. rule_name: Name of the rule to delete. DEFAULT_RULE_NAME=$Default. Use DEFAULT_RULE_NAME to delete default rule for the subscription. fail_not_exist: Specify whether throw exception when rule doesn't exist. ''' _validate_not_none('topic_name', topic_name) _validate_not_none('subscription_name', subscription_name) _validate_not_none('rule_name', rule_name) request = HTTPRequest() request.method = 'DELETE' request.host = self._get_host() request.path = '/' + _str(topic_name) + '/subscriptions/' + \ _str(subscription_name) + \ '/rules/' + _str(rule_name) + '' request.path, request.query = _update_request_uri_query(request) request.headers = self._update_service_bus_header(request) if not fail_not_exist: try: self._perform_request(request) return True except WindowsAzureError as ex: _dont_fail_not_exist(ex) return False else: self._perform_request(request) return True
def get_messages(self, queue_name, numofmessages=None, visibilitytimeout=None): ''' Retrieves one or more messages from the front of the queue. queue_name: Name of the queue. numofmessages: Optional. A nonzero integer value that specifies the number of messages to retrieve from the queue, up to a maximum of 32. If fewer are visible, the visible messages are returned. By default, a single message is retrieved from the queue with this operation. visibilitytimeout: Specifies the new visibility timeout value, in seconds, relative to server time. The new value must be larger than or equal to 1 second, and cannot be larger than 7 days, or larger than 2 hours on REST protocol versions prior to version 2011-08-18. The visibility timeout of a message can be set to a value later than the expiry time. ''' _validate_not_none('queue_name', queue_name) request = HTTPRequest() request.method = 'GET' request.host = self._get_host() request.path = '/' + _str(queue_name) + '/messages' request.query = [('numofmessages', _str_or_none(numofmessages)), ('visibilitytimeout', _str_or_none(visibilitytimeout)) ] request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_queue_header(request, self.account_name, self.account_key) response = self._perform_request(request) return _parse_response(response, QueueMessagesList)
def create_subscription(self, topic_name, subscription_name, subscription=None, fail_on_exist=False): ''' Creates a new subscription. Once created, this subscription resource manifest is immutable. topic_name: Name of the topic. subscription_name: Name of the subscription. fail_on_exist: Specify whether throw exception when subscription exists. ''' _validate_not_none('topic_name', topic_name) _validate_not_none('subscription_name', subscription_name) request = HTTPRequest() request.method = 'PUT' request.host = self._get_host() request.path = '/' + \ _str(topic_name) + '/subscriptions/' + _str(subscription_name) + '' request.body = _get_request_body( _convert_subscription_to_xml(subscription)) request.path, request.query = _update_request_uri_query(request) request.headers = self._update_service_bus_header(request) if not fail_on_exist: try: self._perform_request(request) return True except WindowsAzureError as ex: _dont_fail_on_exist(ex) return False else: self._perform_request(request) return True
def create_queue(self, queue_name, x_ms_meta_name_values=None, fail_on_exist=False): ''' Creates a queue under the given account. queue_name: name of the queue. x_ms_meta_name_values: Optional. A dict containing name-value pairs to associate with the queue as metadata. fail_on_exist: specify whether throw exception when queue exists. ''' _validate_not_none('queue_name', queue_name) request = HTTPRequest() request.method = 'PUT' request.host = self._get_host() request.path = '/' + _str(queue_name) + '' request.headers = [('x-ms-meta-name-values', x_ms_meta_name_values)] request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_queue_header(request, self.account_name, self.account_key) if not fail_on_exist: try: response = self._perform_request(request) if response.status == HTTP_RESPONSE_NO_CONTENT: return False return True except WindowsAzureError as e: _dont_fail_on_exist(e) return False else: response = self._perform_request(request) if response.status == HTTP_RESPONSE_NO_CONTENT: raise WindowsAzureConflictError(azure._ERROR_CONFLICT) return True
def put_block(self, container_name, blob_name, block, blockid, content_md5=None, x_ms_lease_id=None): ''' Creates a new block to be committed as part of a blob. container_name: the name of the container. blob_name: the name of the blob content_md5: Optional. An MD5 hash of the block content. This hash is used to verify the integrity of the blob during transport. When this header is specified, the storage service checks the hash that has arrived with the one that was sent. x_ms_lease_id: Required if the blob has an active lease. To perform this operation on a blob with an active lease, specify the valid lease ID for this header. ''' _validate_not_none('container_name', container_name) _validate_not_none('blob_name', blob_name) _validate_not_none('block', block) _validate_not_none('blockid', blockid) request = HTTPRequest() request.method = 'PUT' request.host = self._get_host() request.path = '/' + str(container_name) + '/' + str( blob_name) + '?comp=block' request.headers = [('Content-MD5', _str_or_none(content_md5)), ('x-ms-lease-id', _str_or_none(x_ms_lease_id))] request.query = [('blockid', base64.b64encode(_str_or_none(blockid)))] request.body = _get_request_body(block) request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_blob_header(request, self.account_name, self.account_key) response = self._perform_request(request)
def peek_lock_subscription_message(self, topic_name, subscription_name, timeout='60'): ''' This operation is used to atomically retrieve and lock a message for processing. The message is guaranteed not to be delivered to other receivers during the lock duration period specified in buffer description. Once the lock expires, the message will be available to other receivers (on the same subscription only) during the lock duration period specified in the topic description. Once the lock expires, the message will be available to other receivers. In order to complete processing of the message, the receiver should issue a delete command with the lock ID received from this operation. To abandon processing of the message and unlock it for other receivers, an Unlock Message command should be issued, or the lock duration period can expire. topic_name: Name of the topic. subscription_name: Name of the subscription. timeout: Optional. The timeout parameter is expressed in seconds. ''' _validate_not_none('topic_name', topic_name) _validate_not_none('subscription_name', subscription_name) request = HTTPRequest() request.method = 'POST' request.host = self._get_host() request.path = '/' + \ _str(topic_name) + '/subscriptions/' + \ _str(subscription_name) + '/messages/head' request.query = [('timeout', _int_or_none(timeout))] request.path, request.query = _update_request_uri_query(request) request.headers = self._update_service_bus_header(request) response = self._perform_request(request) return _create_message(response, self)
def query_entities(self, table_name, filter=None, select=None, top=None): ''' Get entities in a table; includes the $filter and $select options. table_name: the table to query filter: a filter as described at http://msdn.microsoft.com/en-us/library/windowsazure/dd894031.aspx select: the property names to select from the entities top: the maximum number of entities to return ''' _validate_not_none('table_name', table_name) request = HTTPRequest() request.method = 'GET' request.host = _get_table_host(self.account_name, self.use_local_storage) request.path = '/' + str(table_name) + '()' request.query = [('$filter', _str_or_none(filter)), ('$select', _str_or_none(select)), ('$top', _int_or_none(top))] request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_table_header(request) response = self._perform_request(request) return _convert_response_to_feeds(response, _convert_xml_to_entity)
def get_blob_properties(self, container_name, blob_name, x_ms_lease_id=None): ''' Returns all user-defined metadata, standard HTTP properties, and system properties for the blob. x_ms_lease_id: Required if the blob has an active lease. ''' _validate_not_none('container_name', container_name) _validate_not_none('blob_name', blob_name) request = HTTPRequest() request.method = 'HEAD' request.host = self._get_host() request.path = '/' + str(container_name) + '/' + str(blob_name) + '' request.headers = [('x-ms-lease-id', _str_or_none(x_ms_lease_id))] request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_blob_header(request, self.account_name, self.account_key) response = self._perform_request(request) return _parse_response_for_dict(response)
def delete_queue(self, queue_name, fail_not_exist=False): ''' Deletes an existing queue. This operation will also remove all associated state including messages in the queue. fail_not_exist: specify whether to throw an exception if the queue doesn't exist. ''' _validate_not_none('queue_name', queue_name) request = HTTPRequest() request.method = 'DELETE' request.host = self.service_namespace + SERVICE_BUS_HOST_BASE request.path = '/' + str(queue_name) + '' request.path, request.query = _update_request_uri_query(request) request.headers = _update_service_bus_header(request, self.account_key, self.issuer) if not fail_not_exist: try: self._perform_request(request) return True except WindowsAzureError as e: _dont_fail_not_exist(e) return False else: self._perform_request(request) return True
def delete_subscription_message(self, topic_name, subscription_name, sequence_number, lock_token): ''' Completes processing on a locked message and delete it from the subscription. This operation should only be called after processing a previously locked message is successful to maintain At-Least-Once delivery assurances. topic_name: the name of the topic subscription_name: the name of the subscription sequence_name: The sequence number of the message to be deleted as returned in BrokerProperties['SequenceNumber'] by the Peek Message operation. lock_token: The ID of the lock as returned by the Peek Message operation in BrokerProperties['LockToken'] ''' _validate_not_none('topic_name', topic_name) _validate_not_none('subscription_name', subscription_name) _validate_not_none('sequence_number', sequence_number) _validate_not_none('lock_token', lock_token) request = HTTPRequest() request.method = 'DELETE' request.host = self.service_namespace + SERVICE_BUS_HOST_BASE request.path = '/' + str(topic_name) + '/subscriptions/' + str(subscription_name) + '/messages/' + str(sequence_number) + '/' + str(lock_token) + '' request.path, request.query = _update_request_uri_query(request) request.headers = _update_service_bus_header(request, self.account_key, self.issuer) response = self._perform_request(request)
def peek_messages(self, queue_name, numofmessages=None): ''' Retrieves one or more messages from the front of the queue, but does not alter the visibility of the message. queue_name: name of the queue. numofmessages: Optional. A nonzero integer value that specifies the number of messages to peek from the queue, up to a maximum of 32. By default, a single message is peeked from the queue with this operation. ''' _validate_not_none('queue_name', queue_name) request = HTTPRequest() request.method = 'GET' request.host = self._get_host() request.path = '/' + _str(queue_name) + '/messages?peekonly=true' request.query = [('numofmessages', _str_or_none(numofmessages))] request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_queue_header(request, self.account_name, self.account_key) response = self._perform_request(request) return _parse_response(response, QueueMessagesList)
def create_rule(self, topic_name, subscription_name, rule_name, rule=None, fail_on_exist=False): ''' Creates a new rule. Once created, this rule's resource manifest is immutable. topic_name: the name of the topic subscription_name: the name of the subscription rule_name: name of the rule. fail_on_exist: specify whether to throw an exception when the rule exists. ''' _validate_not_none('topic_name', topic_name) _validate_not_none('subscription_name', subscription_name) _validate_not_none('rule_name', rule_name) request = HTTPRequest() request.method = 'PUT' request.host = self._get_host() request.path = '/' + str(topic_name) + '/subscriptions/' + str( subscription_name) + '/rules/' + str(rule_name) + '' request.body = _get_request_body(convert_rule_to_xml(rule)) request.path, request.query = _update_request_uri_query(request) request.headers = _update_service_bus_header(request, self.account_key, self.issuer) if not fail_on_exist: try: self._perform_request(request) return True except WindowsAzureError as e: _dont_fail_on_exist(e) return False else: self._perform_request(request) return True
def insert_entity(self, table_name, entity, content_type='application/atom+xml'): ''' Inserts a new entity into a table. entity: Required. The entity object to insert. Could be a dict format or entity object. Content-Type: this is required and has to be set to application/atom+xml ''' _validate_not_none('table_name', table_name) _validate_not_none('entity', entity) _validate_not_none('content_type', content_type) request = HTTPRequest() request.method = 'POST' request.host = _get_table_host(self.account_name, self.use_local_storage) request.path = '/' + str(table_name) + '' request.headers = [('Content-Type', _str_or_none(content_type))] request.body = _get_request_body(convert_entity_to_xml(entity)) request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_table_header(request) response = self._perform_request(request)
def delete_table(self, table_name, fail_not_exist=False): ''' table_name: Name of the table to delete. fail_not_exist: Specify whether throw exception when table doesn't exist. ''' _validate_not_none('table_name', table_name) request = HTTPRequest() request.method = 'DELETE' request.host = self._get_host() request.path = '/Tables(\'' + _str(table_name) + '\')' request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_table_header(request) if not fail_not_exist: try: self._perform_request(request) return True except WindowsAzureError as e: _dont_fail_not_exist(e) return False else: self._perform_request(request) return True
def get_entity(self, table_name, partition_key, row_key, select=''): ''' Get an entity in a table; includes the $select options. partition_key: PartitionKey of the entity. row_key: RowKey of the entity. select: Property names to select. ''' _validate_not_none('table_name', table_name) _validate_not_none('partition_key', partition_key) _validate_not_none('row_key', row_key) _validate_not_none('select', select) request = HTTPRequest() request.method = 'GET' request.host = self._get_host() request.path = '/' + _str(table_name) + '(PartitionKey=\'' + _str( partition_key) + '\',RowKey=\'' + _str( row_key) + '\')?$select=' + _str(select) + '' request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_table_header(request) response = self._perform_request(request) return _convert_response_to_entity(response)
def query_tables(self, table_name = None, top=None, next_table_name=None): ''' Returns a list of tables under the specified account. table_name: optional, the specific table to query top: the maximum number of tables to return ''' request = HTTPRequest() request.method = 'GET' request.host = self._get_host() if table_name is not None: uri_part_table_name = "('" + table_name + "')" else: uri_part_table_name = "" request.path = '/Tables' + uri_part_table_name + '' request.query = [ ('$top', _int_or_none(top)), ('NextTableName', _str_or_none(next_table_name)) ] request.path, request.query = _update_request_uri_query_local_storage(request, self.use_local_storage) request.headers = _update_storage_table_header(request) response = self._perform_request(request) return _convert_response_to_feeds(response, _convert_xml_to_table)
def _get_token(self, host, path, httpclient): ''' Returns token for the request. host: the service bus service request. path: the service bus service request. ''' wrap_scope = 'http://' + host + path + self.issuer + self.account_key # Check whether has unexpired cache, return cached token if it is still # usable. if wrap_scope in _tokens: token = _tokens[wrap_scope] if not self._token_is_expired(token): return token # get token from accessconstrol server request = HTTPRequest() request.protocol_override = 'https' request.host = host.replace('.servicebus.', '-sb.accesscontrol.') request.method = 'POST' request.path = '/WRAPv0.9' request.body = ('wrap_name=' + url_quote(self.issuer) + '&wrap_password='******'&wrap_scope=' + url_quote('http://' + host + path)).encode('utf-8') request.headers.append(('Content-Length', str(len(request.body)))) resp = httpclient.perform_request(request) token = resp.body.decode('utf-8-sig') token = url_unquote(token[token.find('=') + 1:token.rfind('&')]) _tokens[wrap_scope] = token return token
def send_event(self, hub_name, message, device_id=None, broker_properties=None): ''' Sends a new message event to an Event Hub. ''' _validate_not_none('hub_name', hub_name) request = HTTPRequest() request.method = 'POST' request.host = self._get_host() if device_id: request.path = '/{0}/publishers/{1}/messages?api-version=2014-01'.format( hub_name, device_id) else: request.path = '/{0}/messages?api-version=2014-01'.format(hub_name) if broker_properties: request.headers.append( ('BrokerProperties', str(broker_properties))) request.body = _get_request_body(message) request.path, request.query = _update_request_uri_query(request) request.headers = self._update_service_bus_header(request) self._perform_request(request)
def put_block_list(self, container_name, blob_name, block_list, content_md5=None, x_ms_blob_cache_control=None, x_ms_blob_content_type=None, x_ms_blob_content_encoding=None, x_ms_blob_content_language=None, x_ms_blob_content_md5=None, x_ms_meta_name_values=None, x_ms_lease_id=None): ''' Writes a blob by specifying the list of block IDs that make up the blob. In order to be written as part of a blob, a block must have been successfully written to the server in a prior Put Block (REST API) operation. container_name: the name of container. blob_name: the name of blob x_ms_meta_name_values: Optional. Dict containing name and value pairs. x_ms_blob_cache_control: Optional. Sets the blob's cache control. If specified, this property is stored with the blob and returned with a read request. x_ms_blob_content_type: Optional. Sets the blob's content type. If specified, this property is stored with the blob and returned with a read request. x_ms_blob_content_encoding: Optional. Sets the blob's content encoding. If specified, this property is stored with the blob and returned with a read request. x_ms_blob_content_language: Optional. Set the blob's content language. If specified, this property is stored with the blob and returned with a read request. x_ms_blob_content_md5: Optional. An MD5 hash of the blob content. Note that this hash is not validated, as the hashes for the individual blocks were validated when each was uploaded. content_md5: Optional. An MD5 hash of the block content. This hash is used to verify the integrity of the blob during transport. When this header is specified, the storage service checks the hash that has arrived with the one that was sent. x_ms_lease_id: Required if the blob has an active lease. To perform this operation on a blob with an active lease, specify the valid lease ID for this header. x-ms-meta-name-values: a dict containing name, value for metadata. ''' _validate_not_none('container_name', container_name) _validate_not_none('blob_name', blob_name) _validate_not_none('block_list', block_list) request = HTTPRequest() request.method = 'PUT' request.host = self._get_host() request.path = '/' + str(container_name) + '/' + str( blob_name) + '?comp=blocklist' request.headers = [ ('Content-MD5', _str_or_none(content_md5)), ('x-ms-blob-cache-control', _str_or_none(x_ms_blob_cache_control)), ('x-ms-blob-content-type', _str_or_none(x_ms_blob_content_type)), ('x-ms-blob-content-encoding', _str_or_none(x_ms_blob_content_encoding)), ('x-ms-blob-content-language', _str_or_none(x_ms_blob_content_language)), ('x-ms-blob-content-md5', _str_or_none(x_ms_blob_content_md5)), ('x-ms-meta-name-values', x_ms_meta_name_values), ('x-ms-lease-id', _str_or_none(x_ms_lease_id)) ] request.body = _get_request_body(convert_block_list_to_xml(block_list)) request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_blob_header(request, self.account_name, self.account_key) response = self._perform_request(request)
def commit_batch_requests(self): ''' Commits the batch requests. ''' batch_boundary = b'batch_' + _new_boundary() changeset_boundary = b'changeset_' + _new_boundary() # Commits batch only the requests list is not empty. if self.batch_requests: request = HTTPRequest() request.method = 'POST' request.host = self.batch_requests[0].host request.path = '/$batch' request.headers = [ ('Content-Type', 'multipart/mixed; boundary=' + \ batch_boundary.decode('utf-8')), ('Accept', 'application/atom+xml,application/xml'), ('Accept-Charset', 'UTF-8')] request.body = b'--' + batch_boundary + b'\n' request.body += b'Content-Type: multipart/mixed; boundary=' request.body += changeset_boundary + b'\n\n' content_id = 1 # Adds each request body to the POST data. for batch_request in self.batch_requests: request.body += b'--' + changeset_boundary + b'\n' request.body += b'Content-Type: application/http\n' request.body += b'Content-Transfer-Encoding: binary\n\n' request.body += batch_request.method.encode('utf-8') request.body += b' http://' request.body += batch_request.host.encode('utf-8') request.body += batch_request.path.encode('utf-8') request.body += b' HTTP/1.1\n' request.body += b'Content-ID: ' request.body += str(content_id).encode('utf-8') + b'\n' content_id += 1 # Add different headers for different type requests. if not batch_request.method == 'DELETE': request.body += \ b'Content-Type: application/atom+xml;type=entry\n' for name, value in batch_request.headers: if name == 'If-Match': request.body += name.encode('utf-8') + b': ' request.body += value.encode('utf-8') + b'\n' break request.body += b'Content-Length: ' request.body += str(len( batch_request.body)).encode('utf-8') request.body += b'\n\n' request.body += batch_request.body + b'\n' else: for name, value in batch_request.headers: # If-Match should be already included in # batch_request.headers, but in case it is missing, # just add it. if name == 'If-Match': request.body += name.encode('utf-8') + b': ' request.body += value.encode('utf-8') + b'\n\n' break else: request.body += b'If-Match: *\n\n' request.body += b'--' + changeset_boundary + b'--' + b'\n' request.body += b'--' + batch_boundary + b'--' request.path, request.query = _update_request_uri_query(request) request.headers = _update_storage_table_header(request) self.authentication.sign_request(request) # Submit the whole request as batch request. response = self.perform_request(request) if response.status >= 300: raise HTTPError(response.status, _ERROR_BATCH_COMMIT_FAIL, self.respheader, response.body) # http://www.odata.org/documentation/odata-version-2-0/batch-processing/ # The body of a ChangeSet response is either a response for all the # successfully processed change request within the ChangeSet, # formatted exactly as it would have appeared outside of a batch, # or a single response indicating a failure of the entire ChangeSet. responses = self._parse_batch_response(response.body) if responses and responses[0].status >= 300: self._report_batch_error(responses[0])
request = HTTPRequest() request.method = 'PUT' request.host = self.host request.path = path request.body = _get_request_body(body) request.path, request.query = _update_request_uri_query(request) request.headers = _update_management_header(request) response = self._perform_request(request) if async: return _parse_response_for_async_op(response) return None def _perform_post(self, path, body, response_type=None, async=False): request = HTTPRequest() request.method = 'POST' request.host = self.host request.path = path request.body = _get_request_body(body) request.path, request.query = _update_request_uri_query(request) request.headers = _update_management_header(request) response = self._perform_request(request) if response_type is not None: return _parse_response(response, response_type) if async: return _parse_response_for_async_op(response) return None
def commit_batch_requests(self): ''' Commits the batch requests. ''' batch_boundary = 'batch_a2e9d677-b28b-435e-a89e-87e6a768a431' changeset_boundary = 'changeset_8128b620-b4bb-458c-a177-0959fb14c977' #Commits batch only the requests list is not empty. if self.batch_requests: request = HTTPRequest() request.method = 'POST' request.host = self.batch_requests[0].host request.path = '/$batch' request.headers = [('Content-Type', 'multipart/mixed; boundary=' + batch_boundary), ('Accept', 'application/atom+xml,application/xml'), ('Accept-Charset', 'UTF-8')] request.body = '--' + batch_boundary + '\n' request.body += 'Content-Type: multipart/mixed; boundary=' + changeset_boundary + '\n\n' content_id = 1 # Adds each request body to the POST data. for batch_request in self.batch_requests: request.body += '--' + changeset_boundary + '\n' request.body += 'Content-Type: application/http\n' request.body += 'Content-Transfer-Encoding: binary\n\n' request.body += batch_request.method + ' http://' + batch_request.host + batch_request.path + ' HTTP/1.1\n' request.body += 'Content-ID: ' + str(content_id) + '\n' content_id += 1 # Add different headers for different type requests. if not batch_request.method == 'DELETE': request.body += 'Content-Type: application/atom+xml;type=entry\n' request.body += 'Content-Length: ' + str(len(batch_request.body)) + '\n\n' request.body += batch_request.body + '\n' else: find_if_match = False for name, value in batch_request.headers: #If-Match should be already included in batch_request.headers, but in case it is missing, just add it. if name == 'If-Match': request.body += name + ': ' + value + '\n\n' break else: request.body += 'If-Match: *\n\n' request.body += '--' + changeset_boundary + '--' + '\n' request.body += '--' + batch_boundary + '--' request.path, request.query = _update_request_uri_query(request) request.headers = _update_storage_table_header(request) auth = _sign_storage_table_request(request, self.account_name, self.account_key) request.headers.append(('Authorization', auth)) #Submit the whole request as batch request. response = self.perform_request(request) resp = response.body if response.status >= 300: raise HTTPError(status, azure._ERROR_BATCH_COMMIT_FAIL, self.respheader, resp) return resp
class _ServiceManagementClient(object): def __init__(self, subscription_id=None, cert_file=None, host=MANAGEMENT_HOST): self.requestid = None self.subscription_id = subscription_id self.cert_file = cert_file self.host = host if not self.cert_file: if os.environ.has_key(AZURE_MANAGEMENT_CERTFILE): self.cert_file = os.environ[AZURE_MANAGEMENT_CERTFILE] if not self.subscription_id: if os.environ.has_key(AZURE_MANAGEMENT_SUBSCRIPTIONID): self.subscription_id = os.environ[ AZURE_MANAGEMENT_SUBSCRIPTIONID] if not self.cert_file or not self.subscription_id: raise WindowsAzureError( 'You need to provide subscription id and certificate file') self._httpclient = _HTTPClient(service_instance=self, cert_file=self.cert_file) self._filter = self._httpclient.perform_request def with_filter(self, filter): '''Returns a new service which will process requests with the specified filter. Filtering operations can include logging, automatic retrying, etc... The filter is a lambda which receives the HTTPRequest and another lambda. The filter can perform any pre-processing on the request, pass it off to the next lambda, and then perform any post-processing on the response.''' res = ServiceManagementService(self.subscription_id, self.cert_file) old_filter = self._filter def new_filter(request): return filter(request, old_filter) res._filter = new_filter return res def set_proxy(self, host, port, user=None, password=None): ''' Sets the proxy server host and port for the HTTP CONNECT Tunnelling. host: Address of the proxy. Ex: '192.168.0.100' port: Port of the proxy. Ex: 6000 user: User for proxy authorization. password: Password for proxy authorization. ''' self._httpclient.set_proxy(host, port, user, password) #--Helper functions -------------------------------------------------- def _perform_request(self, request): try: resp = self._filter(request) except HTTPError as e: return _management_error_handler(e) return resp def _perform_get(self, path, response_type): request = HTTPRequest() request.method = 'GET' request.host = self.host request.path = path request.path, request.query = _update_request_uri_query(request) request.headers = _update_management_header(request) response = self._perform_request(request) if response_type is not None: return _parse_response(response, response_type) return response def _perform_put(self, path, body, async=False): request = HTTPRequest() request.method = 'PUT' request.host = self.host request.path = path request.body = _get_request_body(body) request.path, request.query = _update_request_uri_query(request) request.headers = _update_management_header(request) response = self._perform_request(request) if async: return _parse_response_for_async_op(response) return None
def put_page(self, container_name, blob_name, page, x_ms_range, x_ms_page_write, timeout=None, content_md5=None, x_ms_lease_id=None, x_ms_if_sequence_number_lte=None, x_ms_if_sequence_number_lt=None, x_ms_if_sequence_number_eq=None, if_modified_since=None, if_unmodified_since=None, if_match=None, if_none_match=None): ''' Writes a range of pages to a page blob. container_name: the name of container. blob_name: the name of blob timeout: the timeout parameter is expressed in seconds. x_ms_range: Required. Specifies the range of bytes to be written as a page. Both the start and end of the range must be specified. Must be in format: bytes=startByte-endByte. Given that pages must be aligned with 512-byte boundaries, the start offset must be a modulus of 512 and the end offset must be a modulus of 512-1. Examples of valid byte ranges are 0-511, 512-1023, etc. x_ms_page_write: Required. You may specify one of the following options : 1. update(lower case): Writes the bytes specified by the request body into the specified range. The Range and Content-Length headers must match to perform the update. 2. clear(lower case): Clears the specified range and releases the space used in storage for that range. To clear a range, set the Content-Length header to zero, and the Range header to a value that indicates the range to clear, up to maximum blob size. x_ms_lease_id: Required if the blob has an active lease. To perform this operation on a blob with an active lease, specify the valid lease ID for this header. ''' _validate_not_none('container_name', container_name) _validate_not_none('blob_name', blob_name) _validate_not_none('page', page) _validate_not_none('x_ms_range', x_ms_range) _validate_not_none('x_ms_page_write', x_ms_page_write) request = HTTPRequest() request.method = 'PUT' request.host = self._get_host() request.path = '/' + str(container_name) + '/' + str( blob_name) + '?comp=page' request.headers = [ ('x-ms-range', _str_or_none(x_ms_range)), ('Content-MD5', _str_or_none(content_md5)), ('x-ms-page-write', _str_or_none(x_ms_page_write)), ('x-ms-lease-id', _str_or_none(x_ms_lease_id)), ('x-ms-if-sequence-number-lte', _str_or_none(x_ms_if_sequence_number_lte)), ('x-ms-if-sequence-number-lt', _str_or_none(x_ms_if_sequence_number_lt)), ('x-ms-if-sequence-number-eq', _str_or_none(x_ms_if_sequence_number_eq)), ('If-Modified-Since', _str_or_none(if_modified_since)), ('If-Unmodified-Since', _str_or_none(if_unmodified_since)), ('If-Match', _str_or_none(if_match)), ('If-None-Match', _str_or_none(if_none_match)) ] request.query = [('timeout', _int_or_none(timeout))] request.body = _get_request_body(page) request.path, request.query = _update_request_uri_query_local_storage( request, self.use_local_storage) request.headers = _update_storage_blob_header(request, self.account_name, self.account_key) response = self._perform_request(request)