- Better error reporting.
- Flask now uses application's logger instead of its own. - ucloud file scanner refactored.
This commit is contained in:
		
					parent
					
						
							
								eea6c1568e
							
						
					
				
			
			
				commit
				
					
						972bb5a920
					
				
			
		
					 14 changed files with 157 additions and 154 deletions
				
			
		| 
						 | 
					@ -6,44 +6,23 @@ import importlib
 | 
				
			||||||
import multiprocessing as mp
 | 
					import multiprocessing as mp
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import colorama
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
from logging.handlers import SysLogHandler
 | 
					from logging.handlers import SysLogHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ucloud.configure.main import configure_parser
 | 
					from ucloud.configure.main import configure_parser
 | 
				
			||||||
 | 
					from ucloud.common.logging import NoTracebackStreamHandler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def exception_hook(exc_type, exc_value, exc_traceback):
 | 
					def exception_hook(exc_type, exc_value, exc_traceback):
 | 
				
			||||||
 | 
					    logger = logging.getLogger(__name__)
 | 
				
			||||||
    logger.error(
 | 
					    logger.error(
 | 
				
			||||||
        'Uncaught exception',
 | 
					        'Uncaught exception',
 | 
				
			||||||
        exc_info=(exc_type, exc_value, exc_traceback)
 | 
					        exc_info=(exc_type, exc_value, exc_traceback)
 | 
				
			||||||
    )
 | 
					    )
 | 
				
			||||||
    # print('Error: ', end='')
 | 
					 | 
				
			||||||
    # print(exc_type, exc_value, exc_traceback)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class NoTracebackStreamHandler(logging.StreamHandler):
 | 
					sys.excepthook = exception_hook
 | 
				
			||||||
    def handle(self, record):
 | 
					 | 
				
			||||||
        info, cache = record.exc_info, record.exc_text
 | 
					 | 
				
			||||||
        record.exc_info, record.exc_text = None, None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        if record.levelname == 'WARNING':
 | 
					 | 
				
			||||||
            color = colorama.Fore.YELLOW
 | 
					 | 
				
			||||||
        elif record.levelname == 'ERROR':
 | 
					 | 
				
			||||||
            color = colorama.Fore.LIGHTRED_EX
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            color = colorama.Fore.RED
 | 
					 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            print(color)
 | 
					 | 
				
			||||||
            super().handle(record)
 | 
					 | 
				
			||||||
        finally:
 | 
					 | 
				
			||||||
            record.exc_info = info
 | 
					 | 
				
			||||||
            record.exc_text = cache
 | 
					 | 
				
			||||||
            print(colorama.Style.RESET_ALL)
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == '__main__':
 | 
					if __name__ == '__main__':
 | 
				
			||||||
    sys.excepthook = exception_hook
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    arg_parser = argparse.ArgumentParser()
 | 
					    arg_parser = argparse.ArgumentParser()
 | 
				
			||||||
    subparsers = arg_parser.add_subparsers(dest="command")
 | 
					    subparsers = arg_parser.add_subparsers(dest="command")
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
| 
						 | 
					@ -68,7 +47,7 @@ if __name__ == '__main__':
 | 
				
			||||||
        arg_parser.print_help()
 | 
					        arg_parser.print_help()
 | 
				
			||||||
    else:
 | 
					    else:
 | 
				
			||||||
        # Setting up root logger
 | 
					        # Setting up root logger
 | 
				
			||||||
        logger = logging.getLogger('ucloud')
 | 
					        logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        syslog_handler = SysLogHandler(address='/dev/log')
 | 
					        syslog_handler = SysLogHandler(address='/dev/log')
 | 
				
			||||||
        syslog_handler.setLevel(logging.DEBUG)
 | 
					        syslog_handler.setLevel(logging.DEBUG)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										1
									
								
								setup.py
									
										
									
									
									
								
							
							
						
						
									
										1
									
								
								setup.py
									
										
									
									
									
								
							| 
						 | 
					@ -40,6 +40,7 @@ setup(name='ucloud',
 | 
				
			||||||
          'colorama',
 | 
					          'colorama',
 | 
				
			||||||
          'sphinx-rtd-theme',
 | 
					          'sphinx-rtd-theme',
 | 
				
			||||||
          'etcd3 @ https://github.com/kragniz/python-etcd3/tarball/master#egg=etcd3',
 | 
					          'etcd3 @ https://github.com/kragniz/python-etcd3/tarball/master#egg=etcd3',
 | 
				
			||||||
 | 
					          'werkzeug'
 | 
				
			||||||
      ],
 | 
					      ],
 | 
				
			||||||
      scripts=['scripts/ucloud'],
 | 
					      scripts=['scripts/ucloud'],
 | 
				
			||||||
      data_files=[(os.path.expanduser('~/ucloud/'), ['conf/ucloud.conf'])],
 | 
					      data_files=[(os.path.expanduser('~/ucloud/'), ['conf/ucloud.conf'])],
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -10,7 +10,8 @@ from pyotp import TOTP
 | 
				
			||||||
from ucloud.shared import shared
 | 
					from ucloud.shared import shared
 | 
				
			||||||
from ucloud.settings import settings
 | 
					from ucloud.settings import settings
 | 
				
			||||||
 | 
					
 | 
				
			||||||
logger = logging.getLogger("ucloud.api.helper")
 | 
					logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def check_otp(name, realm, token):
 | 
					def check_otp(name, realm, token):
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,11 +1,14 @@
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
import pynetbox
 | 
					import pynetbox
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					import urllib3
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from uuid import uuid4
 | 
					from uuid import uuid4
 | 
				
			||||||
from os.path import join as join_path
 | 
					from os.path import join as join_path
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from flask import Flask, request
 | 
					from flask import Flask, request
 | 
				
			||||||
from flask_restful import Resource, Api
 | 
					from flask_restful import Resource, Api
 | 
				
			||||||
 | 
					from werkzeug.exceptions import HTTPException
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ucloud.common import counters
 | 
					from ucloud.common import counters
 | 
				
			||||||
from ucloud.common.vm import VMStatus
 | 
					from ucloud.common.vm import VMStatus
 | 
				
			||||||
| 
						 | 
					@ -15,10 +18,33 @@ from ucloud.shared import shared
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from . import schemas
 | 
					from . import schemas
 | 
				
			||||||
from .helper import generate_mac, mac2ipv6
 | 
					from .helper import generate_mac, mac2ipv6
 | 
				
			||||||
from . import logger
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def get_parent(obj, attr):
 | 
				
			||||||
 | 
					    parent = getattr(obj, attr)
 | 
				
			||||||
 | 
					    child = parent
 | 
				
			||||||
 | 
					    while parent is not None:
 | 
				
			||||||
 | 
					        child = parent
 | 
				
			||||||
 | 
					        parent = getattr(parent, attr)
 | 
				
			||||||
 | 
					    return child
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app = Flask(__name__)
 | 
					app = Flask(__name__)
 | 
				
			||||||
api = Api(app)
 | 
					api = Api(app)
 | 
				
			||||||
 | 
					app.logger.handlers.clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.errorhandler(Exception)
 | 
				
			||||||
 | 
					def handle_exception(e):
 | 
				
			||||||
 | 
					    app.logger.error(e)
 | 
				
			||||||
 | 
					    # pass through HTTP errors
 | 
				
			||||||
 | 
					    if isinstance(e, HTTPException):
 | 
				
			||||||
 | 
					        return e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # now you're handling non-HTTP exceptions only
 | 
				
			||||||
 | 
					    return {'message': 'Server Error'}, 500
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CreateVM(Resource):
 | 
					class CreateVM(Resource):
 | 
				
			||||||
| 
						 | 
					@ -438,8 +464,8 @@ class CreateNetwork(Resource):
 | 
				
			||||||
                            "is_pool": True,
 | 
					                            "is_pool": True,
 | 
				
			||||||
                        }
 | 
					                        }
 | 
				
			||||||
                    )
 | 
					                    )
 | 
				
			||||||
                except Exception:
 | 
					                except Exception as err:
 | 
				
			||||||
                    logger.exception("Exception occur while contacting netbox")
 | 
					                    app.logger.error(err)
 | 
				
			||||||
                    return {"message": "Error occured while creating network."}
 | 
					                    return {"message": "Error occured while creating network."}
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    network_entry["ipv6"] = prefix["prefix"]
 | 
					                    network_entry["ipv6"] = prefix["prefix"]
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -27,7 +27,7 @@ def readable_errors(func):
 | 
				
			||||||
    @wraps(func)
 | 
					    @wraps(func)
 | 
				
			||||||
    def wrapper(*args, **kwargs):
 | 
					    def wrapper(*args, **kwargs):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            func(*args, **kwargs)
 | 
					            return func(*args, **kwargs)
 | 
				
			||||||
        except etcd3.exceptions.ConnectionFailedError as err:
 | 
					        except etcd3.exceptions.ConnectionFailedError as err:
 | 
				
			||||||
            raise etcd3.exceptions.ConnectionFailedError('etcd connection failed') from err
 | 
					            raise etcd3.exceptions.ConnectionFailedError('etcd connection failed') from err
 | 
				
			||||||
        except etcd3.exceptions.ConnectionTimeoutError as err:
 | 
					        except etcd3.exceptions.ConnectionTimeoutError as err:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										24
									
								
								ucloud/common/logging.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								ucloud/common/logging.py
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					import colorama
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class NoTracebackStreamHandler(logging.StreamHandler):
 | 
				
			||||||
 | 
					    def handle(self, record):
 | 
				
			||||||
 | 
					        info, cache = record.exc_info, record.exc_text
 | 
				
			||||||
 | 
					        record.exc_info, record.exc_text = None, None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if record.levelname == 'WARNING':
 | 
				
			||||||
 | 
					            color = colorama.Fore.YELLOW
 | 
				
			||||||
 | 
					        elif record.levelname in ['ERROR', 'EXCEPTION']:
 | 
				
			||||||
 | 
					            color = colorama.Fore.LIGHTRED_EX
 | 
				
			||||||
 | 
					        elif record.levelname == 'INFO':
 | 
				
			||||||
 | 
					            color = colorama.Fore.LIGHTBLUE_EX
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            color = colorama.Fore.WHITE
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            print(color, end='', flush=True)
 | 
				
			||||||
 | 
					            super().handle(record)
 | 
				
			||||||
 | 
					        finally:
 | 
				
			||||||
 | 
					            record.exc_info = info
 | 
				
			||||||
 | 
					            record.exc_text = cache
 | 
				
			||||||
 | 
					            print(colorama.Style.RESET_ALL, end='', flush=True)
 | 
				
			||||||
| 
						 | 
					@ -11,6 +11,8 @@ from ucloud.settings import settings as config
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ImageStorageHandler(ABC):
 | 
					class ImageStorageHandler(ABC):
 | 
				
			||||||
 | 
					    handler_name = 'base'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __init__(self, image_base, vm_base):
 | 
					    def __init__(self, image_base, vm_base):
 | 
				
			||||||
        self.image_base = image_base
 | 
					        self.image_base = image_base
 | 
				
			||||||
        self.vm_base = vm_base
 | 
					        self.vm_base = vm_base
 | 
				
			||||||
| 
						 | 
					@ -45,13 +47,17 @@ class ImageStorageHandler(ABC):
 | 
				
			||||||
    def delete_vm_image(self, path):
 | 
					    def delete_vm_image(self, path):
 | 
				
			||||||
        raise NotImplementedError()
 | 
					        raise NotImplementedError()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def execute_command(self, command, report=True):
 | 
					    def execute_command(self, command, report=True, error_origin=None):
 | 
				
			||||||
 | 
					        if not error_origin:
 | 
				
			||||||
 | 
					            error_origin = self.handler_name
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        command = list(map(str, command))
 | 
					        command = list(map(str, command))
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            output = sp.check_output(command, stderr=sp.PIPE)
 | 
					            sp.check_output(command, stderr=sp.PIPE)
 | 
				
			||||||
        except Exception as e:
 | 
					        except sp.CalledProcessError as e:
 | 
				
			||||||
 | 
					            _stderr = e.stderr.decode('utf-8').strip()
 | 
				
			||||||
            if report:
 | 
					            if report:
 | 
				
			||||||
                logger.exception(e)
 | 
					                logger.exception('%s:- %s', error_origin, _stderr)
 | 
				
			||||||
            return False
 | 
					            return False
 | 
				
			||||||
        return True
 | 
					        return True
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -66,6 +72,8 @@ class ImageStorageHandler(ABC):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class FileSystemBasedImageStorageHandler(ImageStorageHandler):
 | 
					class FileSystemBasedImageStorageHandler(ImageStorageHandler):
 | 
				
			||||||
 | 
					    handler_name = 'Filesystem'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def import_image(self, src, dest, protect=False):
 | 
					    def import_image(self, src, dest, protect=False):
 | 
				
			||||||
        dest = join_path(self.image_base, dest)
 | 
					        dest = join_path(self.image_base, dest)
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
| 
						 | 
					@ -118,17 +126,23 @@ class FileSystemBasedImageStorageHandler(ImageStorageHandler):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class CEPHBasedImageStorageHandler(ImageStorageHandler):
 | 
					class CEPHBasedImageStorageHandler(ImageStorageHandler):
 | 
				
			||||||
 | 
					    handler_name = 'Ceph'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def import_image(self, src, dest, protect=False):
 | 
					    def import_image(self, src, dest, protect=False):
 | 
				
			||||||
        dest = join_path(self.image_base, dest)
 | 
					        dest = join_path(self.image_base, dest)
 | 
				
			||||||
        command = ["rbd", "import", src, dest]
 | 
					        import_command = ["rbd", "import", src, dest]
 | 
				
			||||||
 | 
					        commands = [import_command]
 | 
				
			||||||
        if protect:
 | 
					        if protect:
 | 
				
			||||||
            snap_create_command = ["rbd", "snap", "create", "{}@protected".format(dest)]
 | 
					            snap_create_command = ["rbd", "snap", "create", "{}@protected".format(dest)]
 | 
				
			||||||
            snap_protect_command = ["rbd", "snap", "protect", "{}@protected".format(dest)]
 | 
					            snap_protect_command = ["rbd", "snap", "protect", "{}@protected".format(dest)]
 | 
				
			||||||
 | 
					            commands.append(snap_create_command)
 | 
				
			||||||
 | 
					            commands.append(snap_protect_command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            return self.execute_command(command) and self.execute_command(snap_create_command) and\
 | 
					        result = True
 | 
				
			||||||
                self.execute_command(snap_protect_command)
 | 
					        for command in commands:
 | 
				
			||||||
 | 
					            result = result and self.execute_command(command)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        return self.execute_command(command)
 | 
					        return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def make_vm_image(self, src, dest):
 | 
					    def make_vm_image(self, src, dest):
 | 
				
			||||||
        src = join_path(self.image_base, src)
 | 
					        src = join_path(self.image_base, src)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -3,7 +3,6 @@ import os
 | 
				
			||||||
import pathlib
 | 
					import pathlib
 | 
				
			||||||
import subprocess as sp
 | 
					import subprocess as sp
 | 
				
			||||||
import time
 | 
					import time
 | 
				
			||||||
import sys
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
from uuid import uuid4
 | 
					from uuid import uuid4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,30 +10,6 @@ from . import logger
 | 
				
			||||||
from ucloud.settings import settings
 | 
					from ucloud.settings import settings
 | 
				
			||||||
from ucloud.shared import shared
 | 
					from ucloud.shared import shared
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def getxattr(file, attr):
 | 
					 | 
				
			||||||
    """Get specified user extended attribute (arg:attr) of a file (arg:file)"""
 | 
					 | 
				
			||||||
    try:
 | 
					 | 
				
			||||||
        attr = "user." + attr
 | 
					 | 
				
			||||||
        value = sp.check_output(['getfattr', file,
 | 
					 | 
				
			||||||
                                 '--name', attr,
 | 
					 | 
				
			||||||
                                 '--only-values',
 | 
					 | 
				
			||||||
                                 '--absolute-names'], stderr=sp.DEVNULL)
 | 
					 | 
				
			||||||
        value = value.decode("utf-8")
 | 
					 | 
				
			||||||
    except sp.CalledProcessError as e:
 | 
					 | 
				
			||||||
        value = None
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return value
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def setxattr(file, attr, value):
 | 
					 | 
				
			||||||
    """Set specified user extended attribute (arg:attr) equal to (arg:value)
 | 
					 | 
				
			||||||
       of a file (arg:file)"""
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    attr = "user." + attr
 | 
					 | 
				
			||||||
    sp.check_output(['setfattr', file,
 | 
					 | 
				
			||||||
                     '--name', attr,
 | 
					 | 
				
			||||||
                     '--value', str(value)])
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
def sha512sum(file: str):
 | 
					def sha512sum(file: str):
 | 
				
			||||||
    """Use sha512sum utility to compute sha512 sum of arg:file
 | 
					    """Use sha512sum utility to compute sha512 sum of arg:file
 | 
				
			||||||
| 
						 | 
					@ -60,31 +35,7 @@ def sha512sum(file: str):
 | 
				
			||||||
    return None
 | 
					    return None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
try:
 | 
					def track_file(file, base_dir):
 | 
				
			||||||
    sp.check_output(['which', 'getfattr'])
 | 
					 | 
				
			||||||
    sp.check_output(['which', 'setfattr'])
 | 
					 | 
				
			||||||
except Exception as e:
 | 
					 | 
				
			||||||
    logger.error("You don't seems to have both getfattr and setfattr")
 | 
					 | 
				
			||||||
    sys.exit(1)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def main():
 | 
					 | 
				
			||||||
    base_dir = settings['storage']['file_dir']
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Recursively Get All Files and Folder below BASE_DIR
 | 
					 | 
				
			||||||
    files = glob.glob("{}/**".format(base_dir), recursive=True)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    # Retain only Files
 | 
					 | 
				
			||||||
    files = list(filter(os.path.isfile, files))
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    untracked_files = list(
 | 
					 | 
				
			||||||
        filter(lambda f: not bool(getxattr(f, "utracked")), files)
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    tracked_files = list(
 | 
					 | 
				
			||||||
        filter(lambda f: f not in untracked_files, files)
 | 
					 | 
				
			||||||
    )
 | 
					 | 
				
			||||||
    for file in untracked_files:
 | 
					 | 
				
			||||||
    file_id = uuid4()
 | 
					    file_id = uuid4()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Get Username
 | 
					    # Get Username
 | 
				
			||||||
| 
						 | 
					@ -95,12 +46,6 @@ def main():
 | 
				
			||||||
    # which is mostly not true.
 | 
					    # which is mostly not true.
 | 
				
			||||||
    creation_date = time.ctime(os.stat(file).st_ctime)
 | 
					    creation_date = time.ctime(os.stat(file).st_ctime)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        # Get File Size
 | 
					 | 
				
			||||||
        size = os.path.getsize(file)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        # Compute sha512 sum
 | 
					 | 
				
			||||||
        sha_sum = sha512sum(file)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    file_path = pathlib.Path(file).parts[-1]
 | 
					    file_path = pathlib.Path(file).parts[-1]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # Create Entry
 | 
					    # Create Entry
 | 
				
			||||||
| 
						 | 
					@ -108,15 +53,33 @@ def main():
 | 
				
			||||||
    entry_value = {
 | 
					    entry_value = {
 | 
				
			||||||
        "filename": file_path,
 | 
					        "filename": file_path,
 | 
				
			||||||
        "owner": owner,
 | 
					        "owner": owner,
 | 
				
			||||||
            "sha512sum": sha_sum,
 | 
					        "sha512sum": sha512sum(file),
 | 
				
			||||||
        "creation_date": creation_date,
 | 
					        "creation_date": creation_date,
 | 
				
			||||||
            "size": size
 | 
					        "size": os.path.getsize(file)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    logger.info("Tracking %s", file)
 | 
					    logger.info("Tracking %s", file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    shared.etcd_client.put(entry_key, entry_value, value_in_json=True)
 | 
					    shared.etcd_client.put(entry_key, entry_value, value_in_json=True)
 | 
				
			||||||
        setxattr(file, "utracked", True)
 | 
					    os.setxattr(file, 'user.utracked', b'True')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main():
 | 
				
			||||||
 | 
					    base_dir = settings['storage']['file_dir']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Recursively Get All Files and Folder below BASE_DIR
 | 
				
			||||||
 | 
					    files = glob.glob("{}/**".format(base_dir), recursive=True)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Retain only Files
 | 
				
			||||||
 | 
					    files = [file for file in files if os.path.isfile(file)]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    untracked_files = []
 | 
				
			||||||
 | 
					    for file in files:
 | 
				
			||||||
 | 
					        try:
 | 
				
			||||||
 | 
					            os.getxattr(file, 'user.utracked')
 | 
				
			||||||
 | 
					        except OSError:
 | 
				
			||||||
 | 
					            track_file(file, base_dir)
 | 
				
			||||||
 | 
					            untracked_files.append(file)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -16,8 +16,7 @@ vmm = virtualmachine.VMM()
 | 
				
			||||||
def update_heartbeat(hostname):
 | 
					def update_heartbeat(hostname):
 | 
				
			||||||
    """Update Last HeartBeat Time for :param hostname: in etcd"""
 | 
					    """Update Last HeartBeat Time for :param hostname: in etcd"""
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    client = shared.etcd_client
 | 
					    host_pool = shared.host_pool
 | 
				
			||||||
    host_pool = HostPool(client)
 | 
					 | 
				
			||||||
    this_host = next(filter(lambda h: h.hostname == hostname, host_pool.hosts), None)
 | 
					    this_host = next(filter(lambda h: h.hostname == hostname, host_pool.hosts), None)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    while True:
 | 
					    while True:
 | 
				
			||||||
| 
						 | 
					@ -27,7 +26,7 @@ def update_heartbeat(hostname):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def main(hostname):
 | 
					def main(hostname):
 | 
				
			||||||
    host_pool = HostPool(shared.etcd_client)
 | 
					    host_pool = shared.host_pool
 | 
				
			||||||
    host = next(filter(lambda h: h.hostname == hostname, host_pool.hosts), None)
 | 
					    host = next(filter(lambda h: h.hostname == hostname, host_pool.hosts), None)
 | 
				
			||||||
    assert host is not None, "No such host with name = {}".format(hostname)
 | 
					    assert host is not None, "No such host with name = {}".format(hostname)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,29 +44,7 @@ def capture_all_exception(func):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            func(*args, **kwargs)
 | 
					            func(*args, **kwargs)
 | 
				
			||||||
        except Exception:
 | 
					        except Exception:
 | 
				
			||||||
            logger.info("Exception absorbed by captual_all_exception()")
 | 
					            logger.exception('Unhandled exception occur in %s. For more details see Syslog.', __name__)
 | 
				
			||||||
            logger.exception(func.__name__)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    return wrapper
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
def need_running_vm(func):
 | 
					 | 
				
			||||||
    @wraps(func)
 | 
					 | 
				
			||||||
    def wrapper(self, e):
 | 
					 | 
				
			||||||
        vm = self.get_vm(self.running_vms, e.key)
 | 
					 | 
				
			||||||
        if vm:
 | 
					 | 
				
			||||||
            try:
 | 
					 | 
				
			||||||
                status = vm.handle.command("query-status")
 | 
					 | 
				
			||||||
                logger.debug("VM Status Check - %s", status)
 | 
					 | 
				
			||||||
            except Exception as exception:
 | 
					 | 
				
			||||||
                logger.info("%s failed - VM %s %s", func.__name__, e, exception)
 | 
					 | 
				
			||||||
            else:
 | 
					 | 
				
			||||||
                return func(e)
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
            return None
 | 
					 | 
				
			||||||
        else:
 | 
					 | 
				
			||||||
            logger.info("%s failed because VM %s is not running", func.__name__, e.key)
 | 
					 | 
				
			||||||
            return None
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return wrapper
 | 
					    return wrapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -168,7 +146,6 @@ class VMM:
 | 
				
			||||||
                self.create(vm_entry)
 | 
					                self.create(vm_entry)
 | 
				
			||||||
                self.launch_vm(vm_entry)
 | 
					                self.launch_vm(vm_entry)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @need_running_vm
 | 
					 | 
				
			||||||
    @capture_all_exception
 | 
					    @capture_all_exception
 | 
				
			||||||
    def stop(self, vm_entry):
 | 
					    def stop(self, vm_entry):
 | 
				
			||||||
        vm = self.get_vm(self.running_vms, vm_entry.key)
 | 
					        vm = self.get_vm(self.running_vms, vm_entry.key)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,6 +1,6 @@
 | 
				
			||||||
import json
 | 
					import json
 | 
				
			||||||
import os
 | 
					import os
 | 
				
			||||||
import subprocess
 | 
					import subprocess as sp
 | 
				
			||||||
import sys
 | 
					import sys
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from os.path import isdir
 | 
					from os.path import isdir
 | 
				
			||||||
| 
						 | 
					@ -13,7 +13,7 @@ from ucloud.imagescanner import logger
 | 
				
			||||||
def qemu_img_type(path):
 | 
					def qemu_img_type(path):
 | 
				
			||||||
    qemu_img_info_command = ["qemu-img", "info", "--output", "json", path]
 | 
					    qemu_img_info_command = ["qemu-img", "info", "--output", "json", path]
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        qemu_img_info = subprocess.check_output(qemu_img_info_command)
 | 
					        qemu_img_info = sp.check_output(qemu_img_info_command)
 | 
				
			||||||
    except Exception as e:
 | 
					    except Exception as e:
 | 
				
			||||||
        logger.exception(e)
 | 
					        logger.exception(e)
 | 
				
			||||||
        return None
 | 
					        return None
 | 
				
			||||||
| 
						 | 
					@ -29,7 +29,7 @@ def check():
 | 
				
			||||||
        )
 | 
					        )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    try:
 | 
					    try:
 | 
				
			||||||
        subprocess.check_output(['which', 'qemu-img'])
 | 
					        sp.check_output(['which', 'qemu-img'])
 | 
				
			||||||
    except Exception:
 | 
					    except Exception:
 | 
				
			||||||
        print("qemu-img missing")
 | 
					        print("qemu-img missing")
 | 
				
			||||||
        sys.exit(1)
 | 
					        sys.exit(1)
 | 
				
			||||||
| 
						 | 
					@ -67,9 +67,10 @@ def main():
 | 
				
			||||||
            if qemu_img_type(image_full_path) == "qcow2":
 | 
					            if qemu_img_type(image_full_path) == "qcow2":
 | 
				
			||||||
                try:
 | 
					                try:
 | 
				
			||||||
                    # Convert .qcow2 to .raw
 | 
					                    # Convert .qcow2 to .raw
 | 
				
			||||||
                    subprocess.check_output(qemu_img_convert_command)
 | 
					                    sp.check_output(qemu_img_convert_command,)
 | 
				
			||||||
                except Exception as e:
 | 
					
 | 
				
			||||||
                    logger.exception(e)
 | 
					                except sp.CalledProcessError:
 | 
				
			||||||
 | 
					                    logger.exception('Image convertion from .qcow2 to .raw failed.')
 | 
				
			||||||
                else:
 | 
					                else:
 | 
				
			||||||
                    # Import and Protect
 | 
					                    # Import and Protect
 | 
				
			||||||
                    r_status = shared.storage_handler.import_image(src="image.raw",
 | 
					                    r_status = shared.storage_handler.import_image(src="image.raw",
 | 
				
			||||||
| 
						 | 
					@ -79,17 +80,17 @@ def main():
 | 
				
			||||||
                        # Everything is successfully done
 | 
					                        # Everything is successfully done
 | 
				
			||||||
                        image.value["status"] = "CREATED"
 | 
					                        image.value["status"] = "CREATED"
 | 
				
			||||||
                        shared.etcd_client.put(image.key, json.dumps(image.value))
 | 
					                        shared.etcd_client.put(image.key, json.dumps(image.value))
 | 
				
			||||||
 | 
					                finally:
 | 
				
			||||||
 | 
					                    try:
 | 
				
			||||||
 | 
					                        os.remove("image.raw")
 | 
				
			||||||
 | 
					                    except Exception:
 | 
				
			||||||
 | 
					                        pass
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            else:
 | 
					            else:
 | 
				
			||||||
                # The user provided image is either not found or of invalid format
 | 
					                # The user provided image is either not found or of invalid format
 | 
				
			||||||
                image.value["status"] = "INVALID_IMAGE"
 | 
					                image.value["status"] = "INVALID_IMAGE"
 | 
				
			||||||
                shared.etcd_client.put(image.key, json.dumps(image.value))
 | 
					                shared.etcd_client.put(image.key, json.dumps(image.value))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try:
 | 
					 | 
				
			||||||
            os.remove("image.raw")
 | 
					 | 
				
			||||||
        except Exception:
 | 
					 | 
				
			||||||
            pass
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
if __name__ == "__main__":
 | 
					if __name__ == "__main__":
 | 
				
			||||||
    main()
 | 
					    main()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -0,0 +1,3 @@
 | 
				
			||||||
 | 
					import logging
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					logger = logging.getLogger(__name__)
 | 
				
			||||||
| 
						 | 
					@ -2,12 +2,27 @@ import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from flask import Flask, request
 | 
					from flask import Flask, request
 | 
				
			||||||
from flask_restful import Resource, Api
 | 
					from flask_restful import Resource, Api
 | 
				
			||||||
 | 
					from werkzeug.exceptions import HTTPException
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ucloud.settings import settings
 | 
					from ucloud.settings import settings
 | 
				
			||||||
from ucloud.shared import shared
 | 
					from ucloud.shared import shared
 | 
				
			||||||
 | 
					
 | 
				
			||||||
app = Flask(__name__)
 | 
					app = Flask(__name__)
 | 
				
			||||||
api = Api(app)
 | 
					api = Api(app)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					app.logger.handlers.clear()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					@app.errorhandler(Exception)
 | 
				
			||||||
 | 
					def handle_exception(e):
 | 
				
			||||||
 | 
					    app.logger.error(e)
 | 
				
			||||||
 | 
					    # pass through HTTP errors
 | 
				
			||||||
 | 
					    if isinstance(e, HTTPException):
 | 
				
			||||||
 | 
					        return e
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # now you're handling non-HTTP exceptions only
 | 
				
			||||||
 | 
					    return {'message': 'Server Error'}, 500
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
def get_vm_entry(mac_addr):
 | 
					def get_vm_entry(mac_addr):
 | 
				
			||||||
    return next(filter(lambda vm: mac_addr in list(zip(*vm.network))[1], shared.vm_pool.vms), None)
 | 
					    return next(filter(lambda vm: mac_addr in list(zip(*vm.network))[1], shared.vm_pool.vms), None)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,7 +5,6 @@ import os
 | 
				
			||||||
 | 
					
 | 
				
			||||||
from ucloud.common.etcd_wrapper import Etcd3Wrapper
 | 
					from ucloud.common.etcd_wrapper import Etcd3Wrapper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
logger = logging.getLogger(__name__)
 | 
					logger = logging.getLogger(__name__)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,8 +13,9 @@ class CustomConfigParser(configparser.RawConfigParser):
 | 
				
			||||||
        try:
 | 
					        try:
 | 
				
			||||||
            result = super().__getitem__(key)
 | 
					            result = super().__getitem__(key)
 | 
				
			||||||
        except KeyError as err:
 | 
					        except KeyError as err:
 | 
				
			||||||
            raise KeyError("Key '{}' not found in config file"\
 | 
					            raise KeyError(
 | 
				
			||||||
                           .format(key)) from err
 | 
					                'Key \'{}\' not found in configuration. Make sure you configure ucloud.'.format(key)
 | 
				
			||||||
 | 
					            ) from err
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            return result
 | 
					            return result
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -78,7 +78,7 @@ class Settings(object):
 | 
				
			||||||
        if config_from_etcd:
 | 
					        if config_from_etcd:
 | 
				
			||||||
            self.config_parser.read_dict(config_from_etcd.value)
 | 
					            self.config_parser.read_dict(config_from_etcd.value)
 | 
				
			||||||
        else:
 | 
					        else:
 | 
				
			||||||
            raise KeyError("Key '{}' not found in etcd".format(self.config_key))
 | 
					            raise KeyError("Key '{}' not found in etcd. Please configure ucloud.".format(self.config_key))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def __getitem__(self, key):
 | 
					    def __getitem__(self, key):
 | 
				
			||||||
        self.read_values_from_etcd()
 | 
					        self.read_values_from_etcd()
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue