项目作者: omza

项目描述 :
A Python Wrapper for modeling client side encrypted azure storage tables, queues and blobs
高级语言: Python
项目地址: git://github.com/omza/azurestoragewrap.git
创建时间: 2018-02-12T10:05:48Z
项目社区:https://github.com/omza/azurestoragewrap

开源协议:MIT License

下载


Build Status Coverage Status
PyPI version shields.io PyPI status

azurestoragewrap

A Python Wrapper for modeling client side encrypted azure storage tables, queues and blobs

Inspired by the implementation of data modeling in SQLAlchemy lib - What the great Job! Thank You! -, i wrote this little wrapper around the Azure Storage SDK for Python to simplify modeling data structures and easily implement Client Side Encryption for my own needs.
Would be lucky if this lib helps other peoples too. GitHub Issues, Stars, Forks and Contribution are Welcome! Have fun with azurestoragewrap.

Microsoft Azure Storage is a Microsoft-managed cloud service that provides storage that is highly available, secure, durable, scalable, and redundant. Azure Storage consists of Blob storage, Table Storage, and Queue storage.
All Data can be accessed from anywhere in the world via HTTP or HTTPS.

Table of contents

Getting started

azurestoragewrap is available on PyPi! Get azurestoragewrap via pip

  1. pip install azurestoragewrap

Usage examples

Using azurestoragewrap should be as easy as possible and has to be handle in a few steps:

  • config your settings, incl. your Azure Storage Credentials in a python dictionary
  • initiate the StorageContext
  • model your Data Objects as a subclass of StorageTableModel, StorageQueueModel or StorageBlobModel
  • register your Model to the StorageContext

Configuration

With following Settings you can setup azurestoragewrap Context Objects. First of all you have to configure your Azure Storage Credentials or while testing try the local Emulator which has to be installed and up and running of cause:

  1. AZURE_STORAGE_NAME = ''
  2. AZURE_STORAGE_KEY = ''

or

  1. AZURE_STORAGE_IS_EMULATED = True #True or False,

if you want to use the client side encryption you are welcome to set up a key identifier and a SECRET Key for en- and decryption:

  1. AZURE_KEY_IDENTIFIER = 'azurestoragewrap_test',
  2. AZURE_SECRET_KEY = 'supa-dupa-secret-special-key2901' # Has to be a valid AES length (8,16,32 characters)

As the azurestoragewrap Context Objects are instanciated with **kwargs wrap the config all together in a dictionary:

  1. config = {
  2. 'AZURE_STORAGE_NAME':'',
  3. 'AZURE_STORAGE_KEY':'',
  4. 'AZURE_STORAGE_IS_EMULATED':True,
  5. 'AZURE_KEY_IDENTIFIER':'',
  6. 'AZURE_SECRET_KEY':''
  7. }

Table

Azure Table storage stores large amounts of structured data. The service is a NoSQL datastore which accepts authenticated calls from inside and outside the Azure cloud. Azure tables are ideal for storing structured, non-relational data.

With the parameter above you can create a new StorageTableContext Instance to initiate an Azure Connection:

  1. from azurestoragewrap.table import (
  2. StorageTableContext,
  3. StorageTableModel, PartitionKey, RowKey,
  4. StorageTableQuery
  5. )
  6. db = StorageTableContext(**config)

To handle Table Data you have to model your Table structure like this:

  1. # Model without encryption
  2. class TableOne(StorageTableModel):
  3. Id = PartitionKey(0) #You have to define one Property as PartitionKey (Part of Azure Storage Table Primary Key) with a default Value
  4. Id2 = RowKey('') #You have to define one Property as RowKey (Part of Azure Storage Table Primary Key) with a default Value
  5. #Model with Partly encryption
  6. class TableTwo(StorageTableModel):
  7. Id = PartitionKey('')
  8. Id2 = RowKey('')
  9. Secret = EncryptKey('') # a Property you like to en-/decrypt clientside has to define as "EncryptKey" with an default Value
  10. NonSecret = ''
  11. Secret2 = EncryptKey('second encrypt') # of cause you can mix multiple encrypted and non encrypted Properties in a Table Model

Now you can register your Models defined above:

  1. db.register_model(TableOne())
  2. db.register_model(TableTwo())

Now get started:

  1. #Insert
  2. entity = TableOne()
  3. entity.Id = 1
  4. entity.Id2 = 'Test'
  5. entity = db.insert(entity)
  6. #Select
  7. entity = db.get(TableOne(Id=1, Id2='Test'))
  8. #Delete
  9. db.delete(entity)
  10. #Replace or Merge (encrypted or not)
  11. db.register_model(TableTwo())
  12. writeentity = TableTwo(Id=1, Id2 ='test_partly_encryption', Secret='Secret', NonSecret='')
  13. writeentity = db.insert(writeentity)
  14. mergeentity = TableTwo(Id=1, Id2 ='test_partly_encryption', Secret='', NonSecret='NonSecret')
  15. mergeentity = db.merge(mergeentity)

Table Queries & Relationships (1-n)

If you like to query a Storage Table or define a Relationship within a StorageTableModel feel free to use the StorageTableQuery Object, wich is a subclass of the pyton list object:

  1. class TableTwo(StorageTableModel):
  2. _tablename = 'tabletwo'
  3. Id = PartitionKey('')
  4. Id2 = RowKey('')
  5. db = StorageTableContext(**config)
  6. db.register_model(TableTwo())
  7. # define a adhoc Query
  8. query = StorageTableQuery(TableTwo(), pkcondition='eq', pkforeignkey='PartitionKey', pkcondition='eq', pkforeignkey='RowKey')
  9. entities = db.query(query)

The Query defined above gives you a List of all entities from Azure Storage Table named ‘tabletwo’ where the PartitionKey is equal (eq) to ‘PartitionKey’ AND where the RowKey is equal to ‘RowKey’

  1. # Relationship (1-n) within a Model
  2. class TableTwo(StorageTableModel):
  3. _tablename = 'tabletwo'
  4. Id = PartitionKey('')
  5. Id2 = RowKey('')
  6. class TableThree(StorageTableModel):
  7. Id = PartitionKey(0)
  8. TableThreeId = RowKey('')
  9. OneToN = StorageTableQuery(TableTwo(), pkcondition='eq', pkforeignkey='TableThreeId')
  10. db = StorageTableContext(**config)
  11. db.register_model(TableTwo())
  12. db.register_model(TableThree())
  13. entity = TableThree(Id=1, TableThreeId='Second')
  14. entity.OneToN = db.query(entity.OneToN)

In design time the property ‘OneToN’ of Model ‘TableThree’ is defined as an 1-n relationship to Model ‘TableTwo’ joining the PartitionKey of TableTwo with TableThree.TableThreeId as the foreign Key.
When creating a Instance of TableThree (here ‘entity’) the StorageTableQuery is initiated as well with the given value for ‘TableThreeId’

Queue

Azure Queue storage is a service for storing large numbers of messages - e.g. a backlog of work to process asynchronously. Use Azure Queue Storage to build flexible applications and separate functions for better durability across large workloads. When you design applications for scale, application components can be decoupled, so that they can scale independently. Queue storage gives you asynchronous message queuing for communication between application components, whether they are running in the cloud, on the desktop, on premises or on mobile devices.

To start working with Queue Messages you have to model the properties by subclassing StorageQueueModel. In difference to StorageTables entry, a queue message can only be encrypted client-side completely. Therefore, the encryption will be configured for the entire StorageQueueModel by set ‘_encrypt=True’ and not on the property level like in StorageTableModel.

  1. # Import from azurestoragewrap
  2. from azurestoragewrap.queue import StorageQueueContext, StorageQueueModel
  3. # Model without encryption
  4. class QueueOne(StorageQueueModel):
  5. epgid = 0
  6. statuscode = 1
  7. statusmessage = 'New'
  8. #Model with encryption
  9. class QueueTwo(StorageQueueModel):
  10. _encrypt = True
  11. _queuename = 'encryptedtest'
  12. user = ''
  13. password = ''
  14. server = ''
  15. protocol = ''

After modeling your StorageQueueModels you have create a StorageQueueContext instance with the Parameter mentioned above and register the models in this instance.

  1. queue = StorageQueueContext(**config)
  2. # Register StorageQueueModels like this:
  3. queue.register_model(QueueTwo())
  4. queue.register_model(QueueOne())

Now you are able to peek, put, get update and delete queue messages like this:

  1. # queue.put()
  2. # add a queue message at the end of the queue just put it:
  3. message = QueueOne(epgid = 1, resolution = 'test_put')
  4. queue.put(message)
  5. # queue.peek()
  6. # lookup (peek) the first message in the queue. firstmessage will be an instance of class QueueOne
  7. firstmessage = queue.peek(QueueOne())
  8. # queue.get()
  9. # will get the first message in the queue. firstmessage will be an instance of class QueueOne. Use the get instead of the peek method if you like to further process the message (update or delete)
  10. firstmessage = queue.get(QueueOne())
  11. #or if you like to hide current message (like below 10 seconds) to e.g. other worker sessions
  12. firstmessage = queue.get(QueueOne(), hide=10)
  13. # queue.delete()
  14. # if your worker session processed a queue message completely it makes sense to delete it from the queue like this:
  15. firstmessage = queue.get(QueueOne())
  16. # ... further processing ...
  17. queue.delete(firstmessage)
  18. # queue.update()
  19. # or your worker session will update the queue message e.g. a error raises during processing
  20. firstmessage = queue.get(QueueOne())
  21. try:
  22. # ... further processing raises en error...
  23. except Exception as e:
  24. firstmessage.statuscode = -1
  25. firstmessage.statusmessage = e
  26. queue.update(firstmessage)

Blob

Azure Blob storage is a service for storing large amounts of unstructured object data, such as text or binary data - e.g. to serve images or documents directly to a browser.

You can start working with Blobs quite similar to StorageQueues. First you have to model the properties by subclassing StorageBlobModel. Like StorageQueues messages a blob just can be encrypted only entirely. In Azure a Blob is stored within a Container.
Therefore, you can set the container name with ‘_containername’ on model level. The custom properties you like to define in your model will be stored in azure as custom blob metadata.
Therefor the content of a property is limited to 8Kb.

  1. # Import from azurestoragewrap
  2. from azurestoragewrap.blob import StorageBlobModel, StorageBlobContext
  3. #Model with encryption
  4. class BlobOne(StorageQueueModel):
  5. _encrypt = True
  6. _containername = 'encryptedtest'
  7. user = ''
  8. password = ''
  9. server = ''
  10. protocol = ''
  11. # Model without encryption
  12. class BlobTwo(StorageBlobModel):
  13. epgid = 0
  14. statuscode = 1
  15. statusmessage = 'New'

After modeling your StorageBlobModels you have create a StorageBlobContext instance with the Parameter mentioned above and register the models in this instance.

  1. container = StorageBlobContext(**config)
  2. # Register StorageQueueModels like this:
  3. container.register_model(BlobTwo())
  4. container.register_model(BlobOne())

Now you are able to upload a Blob to Azure like this:

  1. # container.upload()
  2. #
  3. blob = BlobOne(name = 'blob_from_text',
  4. user='bla',
  5. password='blabla',
  6. server='blablabla',
  7. protocol='sbla')
  8. # add the blob content from a text
  9. blob.fromtext('Test Blob')
  10. container.upload(blob)
  11. # or
  12. blob = BlobOne(name = 'blob_from_file',
  13. user='bla',
  14. password='blabla',
  15. server='blablabla',
  16. protocol='sbla')
  17. # add the blob content from a local file
  18. path_to_file = os.path.join(os.path.dirname(__file__), 'oliver.jpg') # e.g.
  19. blob.fromfile(path_to_file)
  20. container.upload(blob)
  21. # thats it

of cause you like to download a uloaded Blob as well:

  1. # container.download()
  2. #
  3. blob = BlobOne(name = 'blob_from_text')
  4. container.download(blob)
  5. # download blob content to a text
  6. content = blob.totext()
  7. # or
  8. blob = BlobOne(name = 'blob_from_file')
  9. container.download(blob)
  10. # download blob content to local path or file
  11. blob.tofile(os.path.dirname(__file__),True)
  12. # thats it

If you want to retrieve a list of Blobs in type of StorageBlobModel you can easily like this:

  1. # container.list()
  2. #
  3. blobs = container.list(BlobOne())
  4. for blob in blobs:
  5. log.info(blob.name)

or if you want to delete a blob, just do it like this:

  1. # container.delete()
  2. #
  3. blob = BlobOne(name = 'blob_from_file')
  4. if container.delete(blob):
  5. print('blob {!s} is deleted'.format(blob.name))

Meta