示例#1
0
def CreateLogFile():
    """ ログファイルを作成する。WriteLog を呼び出す前に実行すること。 """
    szRet = "";
    if( DEBUG_MODE ):
        return( "Debug モードのためスキップします。" );

    try:
        szRet = "AppendBlobService";
        blob_service    = AppendBlobService(
            account_name,
            account_key
        );
        szRet = "create_container";
        bIsExists = blob_service.exists(
            log_container_name
        );
        if bIsExists:
            pass;
        else:
            blob_service.create_container(
                log_container_name,
                public_access=PublicAccess.Blob
            );
        bIsExists = blob_service.exists(
            log_container_name,
            log_file_name
        );
        if bIsExists:
            szRet = "already blob."
        else:
            szRet = "create_blob";
            blob_service.create_blob(
                log_container_name,
                log_file_name
            );
        szRet = "OK";
    except:
        #szRet = "Log exception";
        pass;
    return szRet;
示例#2
0
def CreateLogFile():
    """ ログファイルを作成する。WriteLog を呼び出す前に実行すること。 """
    szRet = ""
    try:
        szRet = "AppendBlobService"
        blob_service = AppendBlobService(account_name, account_key)
        szRet = "create_container"
        bIsExists = blob_service.exists(log_container_name)
        if bIsExists:
            pass
        else:
            blob_service.create_container(log_container_name,
                                          public_access=PublicAccess.Blob)
        bIsExists = blob_service.exists(log_container_name, log_file_name)
        if bIsExists:
            szRet = "already blob."
        else:
            szRet = "create_blob"
            blob_service.create_blob(log_container_name, log_file_name)
        szRet = "OK"
    except:
        #szRet = "Log exception";
        pass
    return szRet
class AzureBlobStore21(implements(StoreInterface)):
    def __init__(self, storage_creds, max_retries=10):
        self.storage_id = storage_creds["name"]
        self.storage_key = storage_creds["key"]

        self.bs = BlockBlobService(account_name=self.storage_id,
                                   account_key=self.storage_key)
        self.append_bs = AppendBlobService(account_name=self.storage_id,
                                           account_key=self.storage_key)

        self.max_retries = max_retries
        self.set_retries(max_retries)

    # ---- HELPER functions ----

    def set_retries(self, count):

        old_count = self.max_retries
        self.max_retries = count

        # bug workaround: standard Retry classes don't retry status=409 (container is being deleted)
        #import azure.storage.common.retry as retry
        #self.bs.retry = retry.LinearRetry(backoff=5, max_attempts=count).retry
        #self.append_bs.retry = retry.LinearRetry(backoff=5, max_attempts=count).retry

        self.bs.retry = utils.make_retry_func(count)
        self.append_bs.retry = utils.make_retry_func(count)

        return old_count

    # ---- MISC part of interface ----

    def get_service_name(self):
        ''' return the unique name of the storage service'''
        return self.storage_id

    def get_retry(self):
        return self.bs.retry

    def set_retry(self, value):
        self.bs.retry = value

    # ---- CONTAINER interface ----

    def does_container_exist(self, container):
        return self.bs.exists(container)

    def create_container(self, container):
        return self.bs.create_container(container)

    def list_containers(self):
        containers = self.bs.list_containers()
        name_list = [contain.name for contain in containers]
        return name_list

    def delete_container(self, container):
        return self.bs.delete_container(container)

    def get_container_properties(self, container):
        props = self.bs.get_container_properties(container)
        return props

    def get_container_metadata(self, container):
        md = self.bs.get_container_metadata(container)
        return md

    # def set_container_metadata(self, container, md_dict):
    #     return self.bs.set_container_metadata(container, md_dict)

    # ---- BLOB interface ----

    def does_blob_exist(self, container, blob_path):
        return self.bs.exists(container, blob_path)

    def create_blob(self, container, blob_path, text, fail_if_exists=False):
        ifn = "*" if fail_if_exists else None

        return self.bs.create_blob_from_text(container,
                                             blob_path,
                                             text,
                                             if_none_match=ifn)

    def create_blob_from_path(self,
                              container,
                              blob_path,
                              source_fn,
                              progress_callback=None):
        result = self.bs.create_blob_from_path(
            container,
            blob_path,
            source_fn,
            progress_callback=progress_callback)
        return result

    def append_blob(self,
                    container,
                    blob_path,
                    text,
                    append_with_rewrite=False):
        # create blob if it doesn't exist

        if not append_with_rewrite:
            # normal handling
            if not self.append_bs.exists(container, blob_path):
                self.append_bs.create_blob(container, blob_path)

            return self.append_bs.append_blob_from_text(
                container, blob_path, text)
        ''' 
        Appends text to a normal blob blob by reading and then rewriting the entire blob.
        Correctly handles concurrency/race conditions.
        Recommended for lots of small items (like 10,000 run names).

        Note: we turn off retries on azure CALL-level so that we can retry on 
        OUR CALL-level.
        '''
        # experimental local retry loop
        old_retry = self.bs.get_retry()
        self.bs.set_retry(utils.make_retry_func(0))
        succeeded = False

        for i in range(20):

            try:
                if self.bs.does_blob_exist(container, blob_path):
                    # read prev contents
                    blob_text = self.bs.get_blob_text(container, blob_path)
                    # append our text
                    new_text = blob_text + text
                    # write blob, ensuring etag matches (no one updated since above read)
                    self.bs.create_blob(container,
                                        blob_path,
                                        new_text,
                                        if_match=blob.properties.etag)
                else:
                    # if no previous blob, just try to create it
                    self.bs.create_blob(container, blob_path, text)
            except BaseException as ex:
                logger.exception(
                    "Error in _append_blob_with_retries, ex={}".format(ex))
                sleep_time = np.random.random() * 4
                console.diag(
                    "XT store received an expected azure exception; will backoff for {:.4f} secs [retry #{}]"
                    .format(sleep_time, i + 1))
                time.sleep(sleep_time)
            else:
                succeeded = True
                break

        # restore retry
        self.bs.set_retry(old_retry)

        if not succeeded:
            errors.service_error(
                "_append_blob_with_rewrite failed (too many retries)")

    def list_blobs(self,
                   container,
                   path=None,
                   return_names=True,
                   recursive=True):
        '''
        NOTE: the semantics here a tricky

        if recursive:
            - return a flat list of all full path names of all files (no directory entries)
        else: 
            - return a flat list of all files and all directory names (add "/" to end of directory names)

        if return_names:
            - return list of names
        else:
            - return a list of objects with following properties:
                .name     (file pathname)
                .properties
                    .content_length   (number)
                    .modified_ns      (time in ns)

        The delimiter trick: this is when we set the delimiter arg = "/" to tell azure to return only the blobs 
        in the specified directory - that is, don't return blobs from child directories.  In this case, azure 
        returns the effective child directory name, followed by a "/", but not its contents (which we hope is faster).
        '''
        delimiter = None if recursive else "/"

        # specific Azure path rules for good results
        if path:
            if path.startswith("/"):
                path = path[
                    1:]  # blob API wants this part of path relative to container

            # we should only add a "/" if path is a folder path
            if path.endswith("*"):
                # we just need to block the addition of "/"
                path = path[0:-1]
            elif not path.endswith("/"):
                path += "/"  # best if path ends with "/"

        blobs = self.bs.list_blobs(container, prefix=path, delimiter=delimiter)

        if return_names:
            blobs = [blob.name for blob in blobs]
        else:
            blobs = list(blobs)
        return blobs

    def delete_blob(self, container, blob_path, snapshot=None):
        dss = DeleteSnapshot()
        return self.bs.delete_blob(container,
                                   blob_path,
                                   delete_snapshots=dss.Include)

    def get_blob_text(self, container, blob_path):
        # watch out for 0-length blobs - they trigger an Azure RETRY error
        text = ""
        # azure storage bug workaround: avoid RETRY errors for 0-length blob
        blob = self.bs.get_blob_properties(container, blob_path)
        if blob.properties.content_length:
            blob = self.bs.get_blob_to_text(container, blob_path)
            text = blob.content
        return text

    def get_blob_to_path(self,
                         container,
                         blob_path,
                         dest_fn,
                         snapshot=None,
                         progress_callback=None):
        # azure storage bug workaround: avoid RETRY errors for 0-length blob
        blob = self.bs.get_blob_properties(container, blob_path)
        if blob.properties.content_length:
            result = self.bs.get_blob_to_path(
                container,
                blob_path,
                dest_fn,
                snapshot=snapshot,
                progress_callback=progress_callback)
            text = result.content
        else:
            md = blob.metadata
            if "hdi_isfolder" in md and md["hdi_isfolder"]:
                # its a directory marker; do NOT create a local file for it
                text = ""
            else:
                # 0-length text file; just write the file outselves
                text = ""
                with open(dest_fn, "wt") as outfile:
                    outfile.write(text)

        return text

    def get_blob_properties(self, container, blob_path):
        props = self.bs.get_blob_properties(container, blob_path)
        return props

    def get_blob_metadata(self, container, blob_path):
        return self.bs.get_blob_metadata(container, blob_path)

    # def set_blob_metadata(self, container, blob_path, md_dict):
    #     return self.bs.set_blob_metadata(container, blob_path, md_dict)

    def copy_blob(self, source_container, source_blob_path, dest_container,
                  dest_blob_path):
        source_blob_url = self.bs.make_blob_url(source_container,
                                                source_blob_path)
        self.bs.copy_blob(dest_container, dest_blob_path, source_blob_url)

    def snapshot_blob(self, container, blob_path):
        blob = self.bs.snapshot_blob(container, blob_path)
        #pd = utils.obj_to_dict(blob)
        return blob
class LogWriter(object):
    """description of class"""

    LOG_CONTAINER_NAME = r'log-files'
    DEBUG_MODE = bool(os.getenv('DEBUG_MODE', False))

    # コンストラクタ
    def __init__(self, name, key, subFolderName=None):
        super(LogWriter, self).__init__()

        self._name = name
        self._key = key
        self.m_szLogFileName = ""
        self.m_szSubFolderName = subFolderName
        self.m_pBlobService = AppendBlobService(name, key)

    #}def __init__

    def _CreateLogFile(self):
        """ ログファイルを作成する。WriteLog を呼び出す前に実行すること。 """

        szRet = ""
        if (LogWriter.DEBUG_MODE):
            return ("Debug モードのためスキップします。")

        try:
            if (0 == len(self.m_szLogFileName)):
                szRet = "create_container"
                bIsExists = self.m_pBlobService.exists(
                    LogWriter.LOG_CONTAINER_NAME)
                if bIsExists:
                    pass
                else:
                    self.m_pBlobService.create_container(
                        LogWriter.LOG_CONTAINER_NAME,
                        public_access=PublicAccess.Blob)

                #ログファイル名の決定
                #// 後ろに追加しているが len で 0 と調べているため空文字列
                if ((self.m_szSubFolderName is not None)
                        and (0 < len(self.m_szSubFolderName))):
                    #// サブフォルダー名が指定されているときは追加する
                    self.m_szLogFileName += self.m_szSubFolderName + "\\"
                #}if
                self.m_szLogFileName += r"{0:%Y-%m-%dT%H-%M-%S.log}".format(
                    datetime.datetime.now())

                bIsExists = self.m_pBlobService.exists(
                    LogWriter.LOG_CONTAINER_NAME, self.m_szLogFileName)
                if bIsExists:
                    szRet = "already blob."
                else:
                    szRet = "create_blob"
                    self.m_pBlobService.create_blob(
                        LogWriter.LOG_CONTAINER_NAME, self.m_szLogFileName)
                szRet = "OK"
            else:
                szRet = "Already called."
                szRet = "OK"
            #}if

        except Exception as e:
            #szRet = "Log exception";
            szRet = szRet + "\r\n" + str(e)
            pass
        return szRet

    #}def

    def WriteLog(self, txt):
        """ ログファイルにテキストを出力する。末尾に改行コードが追加される。 """
        szRet = ""
        szLogText = r"{0:%Y-%m-%d %H:%M:%S}".format(
            datetime.datetime.now()) + r" : " + txt + "\r\n"
        if (LogWriter.DEBUG_MODE):
            print(szLogText)
            return ("Debug モードのためスキップしました。")

        try:
            #ログファイルの作成
            self._CreateLogFile()

            szRet = "append_blob_from_text"
            self.m_pBlobService.append_blob_from_text(
                LogWriter.LOG_CONTAINER_NAME, self.m_szLogFileName, szLogText)
            szRet = "OK"
        except Exception as e:
            #szRet = "Log exception";
            szRet = szRet + "\r\n" + str(e)
        #try

        return szRet

    #}def

    def WriteBlob(self, blob_name, value):
        """ 単一 BLOB ファイルを作成しテキストを保存する。 """
        szRet = ""
        if (LogWriter.DEBUG_MODE):
            return ("Debug モードのため書き込みをしません。")

        try:
            #blob_name = r'sample.txt';

            szRet = "BlockBlobService"
            blob_service = BlockBlobService(self._name, self._key)

            szRet = "create_container"
            blob_service.create_container(LogWriter.LOG_CONTAINER_NAME,
                                          public_access=PublicAccess.Blob)

            szRet = "create_blob_from_bytes"
            #blob_service.create_blob_from_bytes(
            #    log_container_name,
            #    log_blob_name,
            #    b'<center><h1>Hello World!</h1></center>',
            #    content_settings=ContentSettings('text/html')
            #)

            if (isinstance(value, str)):
                szRet = "create_blob_from_text"
                blob_service.create_blob_from_text(
                    LogWriter.LOG_CONTAINER_NAME, blob_name, value)
            else:
                szRet = "create_blob_from_stream"
                blob_service.create_blob_from_stream(
                    LogWriter.LOG_CONTAINER_NAME, blob_name, io.BytesIO(value))
            #}if

            #szRet = "make_blob_url"
            #print(blob_service.make_blob_url(log_container_name, log_blob_name))

            szRet = "OK"
        except:
            print(r"Exception.")
        #try

        return szRet

    #def WriteBlob( blob_name, txt ):

    def MakeBlobUri(self, blob_name):
        blob_service = BlockBlobService(self._name, self._key)
        szRet = blob_service.make_blob_url(LogWriter.LOG_CONTAINER_NAME,
                                           blob_name)

        return (szRet)

    #}def


#}class
示例#5
0
import io
from azure.storage.blob import BlockBlobService
from azure.storage.blob import AppendBlobService

STORAGE_ACCOUNT_NAME = os.environ['STORAGE_ACCOUNT_NAME']
STORAGE_ACCOUNT_KEY = os.environ['STORAGE_ACCOUNT_KEY']

LOGS_CONTAINER_NAME = 'logs'
LOGS_ARCHIVE_CONTAINER_NAME = 'logs-archive'

append_blob_service = AppendBlobService(account_name=STORAGE_ACCOUNT_NAME,
                                        account_key=STORAGE_ACCOUNT_KEY)
block_blob_service = BlockBlobService(account_name=STORAGE_ACCOUNT_NAME,
                                      account_key=STORAGE_ACCOUNT_KEY)

if not append_blob_service.exists(LOGS_CONTAINER_NAME):
    exit(0)

if not block_blob_service.exists(LOGS_ARCHIVE_CONTAINER_NAME):
    block_blob_service.create_container(LOGS_ARCHIVE_CONTAINER_NAME)

generator = append_blob_service.list_blobs(LOGS_CONTAINER_NAME)
for blob in generator:
    with io.BytesIO() as stream:
        append_blob_service.get_blob_to_stream(
            container_name=LOGS_CONTAINER_NAME,
            blob_name=blob.name,
            stream=stream,
            max_connections=2)
        stream.seek(0)
        block_blob_service.create_blob_from_stream(
class Results(object):
    """
    Handles interacting with encrypted results in blob storage.
    """
    def __init__(self, logger, redisHost, redisPort):
        """
        Initializes a new instance of the JobStatus class.

        :param logger logger: The logger instance to use for logging
        :param str redis_host: Redis host where the Redis Q is running
        :param int redis_port: Redis port where the Redis Q is running
        """
        self.logger = logger
        self.config = Config()
        self.redis_host = redisHost
        self.redis_port = redisPort
        # create an instance of AESCipher to use for encryption
        aesHelper = AESHelper(self.config)
        self.aescipher = aesHelper.create_aescipher_from_config()
        if (self.init_storage_services() is False):
            raise Exception(
                "Errors occurred instantiating results storage service.")

    def init_storage_services(self):
        """
        Initializes the storage service clients using values from config.py.
        :return: True on success. False on failure.
        :rtype: boolean
        """
        try:
            # creates instance of BlockBlobService and AppendBlobService to use for completed results storage
            self.storage_service = BlockBlobService(
                account_name=self.config.storage_account_name,
                sas_token=self.config.results_container_sas_token)
            self.append_storage_service = AppendBlobService(
                account_name=self.config.storage_account_name,
                sas_token=self.config.results_container_sas_token)
            self.storage_service.create_container(
                self.config.results_container_name)

            # creates instances of Azure QueueService
            self.job_status_queue_service = QueueService(
                account_name=self.config.storage_account_name,
                sas_token=self.config.job_status_queue_sas_token)
            self.job_status_queue_service.encode_function = models.QueueMessageFormat.noencode
            self.results_queue_service = QueueService(
                account_name=self.config.storage_account_name,
                sas_token=self.config.results_queue_sas_token)
            self.results_queue_service.create_queue(
                self.config.results_container_name)
            self.results_queue_service.encode_function = models.QueueMessageFormat.noencode

            # creates instance of Redis client to use for job status storage
            pool = redis.ConnectionPool(host=self.redis_host,
                                        port=self.redis_port)
            self.storage_service_cache = redis.Redis(connection_pool=pool)

            return True
        except Exception as ex:
            self.log_exception(ex, self.init_storage_services.__name__)
            return False

    def log_exception(self, exception, functionName):
        """
        Logs an exception to the logger instance for this class.

        :param Exception exception: The exception thrown.
        :param str functionName: Name of the function where the exception occurred.
        """
        self.logger.debug("Exception occurred in: " + functionName)
        self.logger.debug(type(exception))
        self.logger.debug(exception)

    def write_result(self, result):
        """
        Encrypts and writes result to queue

        :param str result: The result to write to queue
        :return: True on success. False on failure.
        :rtype: boolean
        """
        try:
            # encrypt the encoded result and then encode it
            encryptedResult = base64.b64encode(self.aescipher.encrypt(result))

            # put the encoded result into the azure queue for future consolidation
            self.results_queue_service.put_message(
                self.config.results_queue_name, encryptedResult)

            return True
        except Exception as ex:
            self.log_exception(ex, self.write_result.__name__)
            return False

    def count_consolidated_results(self):
        """
        Returns a count of results that were consolidated.

        "return: int count: Total count of results that were consolidated.
        """
        try:
            consolidatedResults = self.storage_service_cache.get(
                self.config.results_consolidated_count_redis_key)
            return consolidatedResults
        except Exception as ex:
            self.log_exception(ex, self.count_consolidated_results.__name__)
            return False

        except Exception as ex:
            self.log_exception(
                ex, self.consolidate_results.__name__ +
                " - Error consolidating result blob.")

    def consolidate_results(self):
        """
        Consolidates all individual result files into single result file in storage. Blobs are deleted once they
        are added to the consolidated file.

        "return: int count: Total count of results consolidated in result file.
        """
        try:
            # ensure the consolidated append blob exists
            if not self.append_storage_service.exists(
                    self.config.results_container_name,
                    blob_name=self.config.results_consolidated_file):
                self.append_storage_service.create_blob(
                    self.config.results_container_name,
                    self.config.results_consolidated_file)

            result_messages = []
            with io.BytesIO() as consolidated_result:
                while len(result_messages
                          ) < self.config.result_consolidation_size:
                    messages = self.results_queue_service.get_messages(
                        self.config.results_queue_name,
                        min(self.config.result_consolidation_size, 32))

                    # If the queue is empty, stop and consolidate
                    if not messages:
                        break

                    # add the message to the memory stream
                    for msg in messages:
                        consolidated_result.write(msg.content + "\n")
                        result_messages.append(msg)

                # append the results to the consolidated file
                consolidated_result.seek(0)
                self.append_storage_service.append_blob_from_stream(
                    self.config.results_container_name,
                    self.config.results_consolidated_file, consolidated_result)

            # remove all of the messages from the queue
            num_of_consolidated_results = len(result_messages)
            for msg in result_messages:
                self.results_queue_service.delete_message(
                    self.config.results_queue_name, msg.id, msg.pop_receipt)
            self.storage_service_cache.incrby(
                self.config.results_consolidated_count_redis_key,
                num_of_consolidated_results)

            # write the count of results we consolidated out to queue to provide status
            self.job_status_queue_service.put_message(
                self.config.job_status_queue_name,
                str(num_of_consolidated_results) + " results consolidated.")

            return len(result_messages)

        except Exception as ex:
            self.log_exception(ex, self.consolidate_results.__name__)
            return len(result_messages)

    def get_total_jobs_consolidated_status(self):
        """
        Write out the the current state of the workload; the percentage of jobs that are completed and consolidated
        "return: float status: percentage of completed jobs
        """
        # log out total job status
        total_scheduled_jobs = self.storage_service_cache.get(
            self.config.scheduled_jobs_count_redis_key)
        total_consolidated_results = self.storage_service_cache.get(
            self.config.results_consolidated_count_redis_key)

        if total_consolidated_results is None:
            total_consolidated_results = "0"

        status_message = "Total: " + total_consolidated_results + "/" + total_scheduled_jobs + " jobs have been successfully processed and consolidated."
        self.logger.info(status_message)
        self.job_status_queue_service.put_message(
            self.config.job_status_queue_name, status_message)

        return float(total_consolidated_results) / int(total_scheduled_jobs)