Esempio n. 1
0
    def _version(self, args: argparse.Namespace):
        """
        Implements the --version argument.

        """
        if args.version:
            cm = ConfigManager()

            print('{0} version: {1}'.format(os.path.basename(sys.argv[0]),
                                            cm.getTortugaRelease()))
            sys.exit(0)
Esempio n. 2
0
class TortugaCli(object):
    """
    Base tortuga command line interface class.
    """
    def __init__(self, validArgCount=0):
        self._logger = logging.getLogger('tortuga.cli.%s' %
                                         (self.__class__.__name__))
        self._logger.addHandler(logging.NullHandler())

        self._parser = OptionParser(add_help_option=False)
        self._options = None
        self._args = []
        self._validArgCount = validArgCount
        self._username = None
        self._password = None
        self._optionGroupDict = {}
        self._cm = ConfigManager()

        self.__initializeLocale()

        commonGroup = _('Common Tortuga Options')
        self.addOptionGroup(commonGroup, None)

        self.addOptionToGroup(commonGroup,
                              '-h',
                              '--help',
                              action='help',
                              help=_('show this help message and exit'))

        self.addOptionToGroup(commonGroup,
                              '-?',
                              '',
                              action='help',
                              help=_('show this help message and exit'))

        self.addOptionToGroup(commonGroup,
                              '-V',
                              '',
                              action='store_true',
                              dest='cmdVersion',
                              default=False,
                              help=_('print version and exit'))

        self.addOptionToGroup(
            commonGroup,
            '-d',
            '--debug',
            dest='consoleLogLevel',
            help=_('set debug level; valid values are: critical, error,'
                   ' warning, info, debug'))

        self.addOptionToGroup(
            commonGroup,
            '--username',
            dest='username',
            help=_('Credential to use when not running as root on the'
                   ' installer.'))

        self.addOptionToGroup(
            commonGroup,
            '--password',
            dest='password',
            help=_('Credential to use when not running as root on the'
                   ' installer.'))

    def getLogger(self):
        """ Get logger for this class. """
        return self._logger

    def __initializeLocale(self):
        """Initialize the gettext domain """
        langdomain = 'tortugaStrings'

        # Locate the Internationalization stuff
        localedir = '../share/locale' \
            if os.path.exists('../share/locale') else \
            os.path.join(self._cm.getRoot(), 'share/locale')

        gettext.install(langdomain, localedir)

    def getParser(self):
        """ Get parser for this class. """
        return self._parser

    def addOption(self, *args, **kwargs):
        """ Add option. """
        self._parser.add_option(*args, **kwargs)

    def addOptionToGroup(self, groupName, *args, **kwargs):
        """
        Add option for the given group name.
        Group should be created using addOptionGroup().
        """
        group = self._optionGroupDict.get(groupName)
        group.add_option(*args, **kwargs)

    def addOptionGroup(self, groupName, desc):
        """ Add option group. """
        group = OptionGroup(self._parser, groupName, desc)
        self._parser.add_option_group(group)
        self._optionGroupDict[groupName] = group

    def parseArgs(self, usage=None):
        """
        Parse args

        Raises:
            InvalidArgument
        """

        if usage:
            self._parser.usage = usage

        try:
            self._options, self._args = self._parser.parse_args()
        except SystemExit as rc:
            sys.stdout.flush()
            sys.stderr.flush()
            sys.exit(int(str(rc)))

        if self._validArgCount < len(self._args):
            # Postitional args are not enabled and we have some
            msg = _("Invalid Argument(s):")
            for arg in self._args[self._validArgCount:]:
                msg += " " + arg

            raise InvalidArgument(msg)

        optDict = self._options.__dict__
        if optDict.get('cmdVersion'):
            print(
                _('{0} version: {1}'.format(os.path.basename(sys.argv[0]),
                                            self._cm.getTortugaRelease())))

            sys.exit(0)

        # Log level.
        consoleLogLevel = optDict.get('consoleLogLevel', None)
        if consoleLogLevel:
            # logManager.setConsoleLogLevel(consoleLogLevel)

            logger = logging.getLogger('tortuga')

            logger.setLevel(logging.DEBUG)

            # create console handler and set level to debug
            ch = logging.StreamHandler()
            ch.setLevel(logging.DEBUG)

            # create formatter
            formatter = logging.Formatter(
                '%(asctime)s - %(name)s - %(levelname)s - %(message)s')

            # add formatter to ch
            ch.setFormatter(formatter)

            # add ch to logger
            logger.addHandler(ch)

        # Promote options to attributes

        self._username = self._options.username
        self._password = self._options.password

        return self._options, self._args

    def usage(self, s=None):
        '''Print the help provided by optparse'''

        if s:
            sys.stderr.write(_('Error: {0}').format(s) + '\n')

        self._parser.print_help()

        sys.exit(1)

    def getOptions(self):
        '''Returns the command line options'''
        return self._options

    def getNArgs(self):
        '''Returns the number of command line arguments'''
        return len(self._args)

    def getArgs(self):
        '''Returns the command line argument list'''
        return self._args

    def getArg(self, i):
        '''Returns the i-th command line argument'''
        return self._args[i]

    def getUsername(self):
        """ Get user name. """
        return self._username

    def getPassword(self):
        """ Get password. """
        return self._password

    def runCommand(self):         \
            # pylint: disable=no-self-use
        """ This method must be implemented by the derived class. """

        raise AbstractMethod(
            _('runCommand() has to be overriden in the derived class.'))

    def run(self):
        """
        Invoke runCommand() in derivative class and handle exceptions.
        """
        try:
            self.runCommand()
        except TortugaException as ex:
            print('%s' % (ex.getErrorMessage()))
            raise SystemExit(ex.getErrorCode())
        except SystemExit as ex:
            raise
        except Exception as ex:
            print('%s' % (ex))
            raise SystemExit(-1)

    def getParam(self,
                 xtype,
                 options,
                 oname,
                 config,
                 section,
                 cname,
                 default=None):
        '''
        Get the value of a configurable parameter.
        First look at command line options. Return it if there.
        Then look in the configFile. Return it if there.
        Otherwise return the default.
        '''

        value = self.__getParam2(options, oname, config, section, cname,
                                 default)

        if xtype == int:
            if not value:
                value = 0
            elif type(value) != int:
                value = int(value)

        elif xtype == bool:
            if type(value) == str:
                value = value.lower() == 'true'
            elif type(value) == int:
                value = bool(value)

        return value

    def __getParam2(self, options, oname, config, section, cname, default):         \
            # pylint: disable=no-self-use

        # Command line option takes precedence

        if options and oname in options.__dict__ and \
                options.__dict__[oname] is not None:
            return options.__dict__[oname]

        # Config file is next

        if config and config.has_section(section) and \
                config.has_option(section, cname):
            return config.get(section, cname)

        # Last resort
        return default

    def _parseDiskSize(self, diskSizeParam):         \
            # pylint: disable=no-self-use
        """
        Parses diskSizeParam, returns an int value representing
        number of megabytes

        Raises:
            ValueError
        """
        if diskSizeParam.endswith('TB'):
            return int(float(diskSizeParam[:-2]) * 1000000)

        if diskSizeParam.endswith('GB'):
            return int(float(diskSizeParam[:-2]) * 1000)
        elif diskSizeParam.endswith('MB'):
            # Must be an integer
            return int(diskSizeParam[:-2])

        return int(diskSizeParam)

    def _getDiskSizeDisplayStr(self, volSize):         \
            # pylint: disable=no-self-use

        if volSize < 1000:
            result = '%s MB' % (volSize)
        elif volSize < 1000000:
            result = '%.3f GB' % (float(volSize) / 1000)
        else:
            result = '%.3f TB' % (float(volSize) / 1000000)

        return result
Esempio n. 3
0
class TortugaCli(metaclass=ABCMeta):
    """
    Base tortuga command line interface class.
    """
    def __init__(self, validArgCount=0):
        self._logger = logging.getLogger(CLI_NAMESPACE)

        self._parser = argparse.ArgumentParser()
        self._args = []
        self._validArgCount = validArgCount
        self._url = None
        self._username = None
        self._password = None
        self._verify = True
        self._optionGroupDict = {}
        self._cm = ConfigManager()

        self.__initializeLocale()

    def __initializeLocale(self):
        """Initialize the gettext domain """
        langdomain = 'tortugaStrings'

        # Locate the Internationalization stuff
        localedir = '../share/locale' \
            if os.path.exists('../share/locale') else \
            os.path.join(self._cm.getRoot(), 'share/locale')

        gettext.install(langdomain, localedir)

    def getParser(self):
        """ Get parser for this class. """
        return self._parser

    def addOption(self, *args, **kwargs):
        """ Add option. """
        self._parser.add_argument(*args, **kwargs)

    def addOptionToGroup(self, groupName, *args, **kwargs):
        """
        Add option for the given group name.
        Group should be created using addOptionGroup().
        """
        group = self._optionGroupDict.get(groupName)
        group.add_argument(*args, **kwargs)

    def addOptionGroup(self, groupName, desc):
        """ Add option group. """
        group = self._parser.add_argument_group(groupName, desc)
        self._optionGroupDict[groupName] = group
        return group

    def parseArgs(self, usage=None):
        """
        Parse args

        Raises:
            InvalidArgument
        """
        common_group = _('Common Tortuga Options')
        self.addOptionGroup(common_group, None)

        self.addOptionToGroup(common_group,
                              '-V',
                              action='store_true',
                              dest='cmdVersion',
                              default=False,
                              help=_('print version and exit'))

        self.addOptionToGroup(common_group,
                              '-d',
                              '--debug',
                              dest='consoleLogLevel',
                              default='warning',
                              help=_('set debug level; valid values are: '
                                     'critical, error, warning, info, debug'))

        self.addOptionToGroup(common_group,
                              '--url',
                              help=_('Tortuga web service URL'))

        self.addOptionToGroup(common_group,
                              '--username',
                              dest='username',
                              help=_('Tortuga web service user name'))

        self.addOptionToGroup(common_group,
                              '--password',
                              dest='password',
                              help=_('Tortuga web service password'))

        self.addOptionToGroup(common_group,
                              '--no-verify',
                              dest='verify',
                              action='store_false',
                              default=True,
                              help=_("Don't verify the API SSL certificate"))

        if usage:
            self._parser.description = usage

        try:
            self._args = self._parser.parse_args()
        except SystemExit as rc:
            sys.stdout.flush()
            sys.stderr.flush()
            sys.exit(int(str(rc)))

        if self._args.cmdVersion:
            print(
                _('{0} version: {1}'.format(os.path.basename(sys.argv[0]),
                                            self._cm.getTortugaRelease())))
            sys.exit(0)

        self._setup_logging(self._args.consoleLogLevel)

        self._url, self._username, self._password, self._verify = \
            self._get_web_service_options()

        return self._args

    def _setup_logging(self, log_level_name: str):
        """
        Setup logging for the specified log level.

        :param str log_level_name: the name of the log level to use

        """
        log_level_name = log_level_name.upper()
        if log_level_name not in [
                'CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'
        ]:
            print('Invalid debug level: {}'.format(log_level_name))
            sys.exit(0)

        log_level = getattr(logging, log_level_name)

        logger = logging.getLogger(ROOT_NAMESPACE)
        logger.setLevel(log_level)

        ch = logging.StreamHandler()
        ch.setLevel(log_level)
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        ch.setFormatter(formatter)

        logger.addHandler(ch)

    def _get_web_service_options(self):
        """
        Read Tortuga web service credentials from config file, environment,
        or command-line. Command-line overrides either config file or
        environment.

        :return: tuple of (url, username, password)
        """
        username = password = url = None

        cfg_file = os.path.join(os.path.expanduser('~'), '.local', 'tortuga',
                                'credentials')

        if os.path.exists(cfg_file):
            cfg = configparser.ConfigParser()

            cfg.read(cfg_file)

            username = cfg.get('default', 'username') \
                if cfg.has_section('default') and \
                cfg.has_option('default', 'username') else None

            password = cfg.get('default', 'password') \
                if cfg.has_section('default') and \
                cfg.has_option('default', 'password') else None

            url = cfg.get('default', 'url') \
                if cfg.has_section('default') and \
                cfg.has_option('default', 'url') else None

        # TORTUGA_WS_URL
        if self._args.url:
            # Command-line "--server" argument overrides env var and
            # setting contained within '/etc/profile.nii'
            url = self._args.url
        elif os.getenv('TORTUGA_WS_URL'):
            url = os.getenv('TORTUGA_WS_URL')

        # TORTUGA_WS_USERNAME
        if self._args.username:
            username = self._args.username
        elif os.getenv('TORTUGA_WS_USERNAME'):
            username = os.getenv('TORTUGA_WS_USERNAME')

        # TORTUGA_WS_PASSWORD
        if self._args.password:
            password = self._args.password
        elif os.getenv('TORTUGA_WS_PASSWORD'):
            password = os.getenv('TORTUGA_WS_PASSWORD')

        #
        # CLI arguments should override the environment variable
        #
        if os.getenv('TORTUGA_WS_NO_VERIFY'):
            verify = False
        else:
            verify = self._args.verify

        return url, username, password, verify

    def usage(self, s=None):
        """
        Print usage information
        """

        if s:
            sys.stderr.write(_('Error: {0}').format(s) + '\n')

        self._parser.print_help()

        sys.exit(1)

    def getArgs(self):
        '''Returns the command line argument list'''
        return self._args

    def getUrl(self):
        return self._url

    def getUsername(self):
        """ Get user name. """
        return self._username

    def getPassword(self):
        """ Get password. """
        return self._password

    @abstractmethod
    def runCommand(self):         \
            # pylint: disable=no-self-use
        """
        This method must be implemented by the derived class.
        """

    def run(self):
        """
        Invoke runCommand() in derivative class and handle exceptions.
        """
        try:
            self.runCommand()
        except TortugaException as ex:
            print(ex.getErrorMessage())
            raise SystemExit(ex.getErrorCode())
        except SystemExit:
            raise
        except Exception as ex:
            print(str(ex))
            raise SystemExit(-1)

    def _parseDiskSize(self, diskSizeParam):         \
            # pylint: disable=no-self-use
        """
        Parses diskSizeParam, returns an int value representing
        number of megabytes

        Raises:
            ValueError
        """
        if diskSizeParam.endswith('TB'):
            return int(float(diskSizeParam[:-2]) * 1000000)

        if diskSizeParam.endswith('GB'):
            return int(float(diskSizeParam[:-2]) * 1000)
        elif diskSizeParam.endswith('MB'):
            # Must be an integer
            return int(diskSizeParam[:-2])

        return int(diskSizeParam)

    def _getDiskSizeDisplayStr(self, volSize):         \
            # pylint: disable=no-self-use

        if volSize < 1000:
            result = '%s MB' % (volSize)
        elif volSize < 1000000:
            result = '%.3f GB' % (float(volSize) / 1000)
        else:
            result = '%.3f TB' % (float(volSize) / 1000000)

        return result
Esempio n. 4
0
class TortugaCli(metaclass=ABCMeta):
    """
    Base tortuga command line interface class.
    """
    def __init__(self, validArgCount=0):
        self._logger = logging.getLogger(CLI_NAMESPACE)

        self._config: TortugaScriptConfig = None
        self._parser = argparse.ArgumentParser()
        self._args = []
        self._validArgCount = validArgCount
        self._optionGroupDict = {}
        self._cm = ConfigManager()

        self.__initializeLocale()

    def __initializeLocale(self):
        """Initialize the gettext domain """
        langdomain = 'tortugaStrings'

        # Locate the Internationalization stuff
        localedir = '../share/locale' \
            if os.path.exists('../share/locale') else \
            os.path.join(self._cm.getRoot(), 'share/locale')

        gettext.install(langdomain, localedir)

    def getParser(self):
        """ Get parser for this class. """
        return self._parser

    def addOption(self, *args, **kwargs):
        """ Add option. """
        self._parser.add_argument(*args, **kwargs)

    def addOptionToGroup(self, groupName, *args, **kwargs):
        """
        Add option for the given group name.
        Group should be created using addOptionGroup().
        """
        group = self._optionGroupDict.get(groupName)
        group.add_argument(*args, **kwargs)

    def addOptionGroup(self, groupName, desc):
        """ Add option group. """
        group = self._parser.add_argument_group(groupName, desc)
        self._optionGroupDict[groupName] = group
        return group

    def parseArgs(self, usage=None):
        """
        Parse args

        Raises:
            InvalidArgument
        """
        common_group = 'Common Tortuga Options'
        self.addOptionGroup(common_group, None)

        self.addOptionToGroup(common_group,
                              '-V',
                              action='store_true',
                              dest='cmdVersion',
                              default=False,
                              help='print version and exit')

        self.addOptionToGroup(common_group,
                              '-d',
                              '--debug',
                              dest='consoleLogLevel',
                              default='warning',
                              help='set debug level; valid values are: '
                              'critical, error, warning, info, debug')

        self.addOptionToGroup(common_group,
                              '--config',
                              dest='config',
                              help='Path to config file '
                              '(defaults to ~/.tortuga/config)')

        self.addOptionToGroup(common_group,
                              '--url',
                              help='Tortuga web service URL')

        self.addOptionToGroup(common_group,
                              '--username',
                              dest='username',
                              help='Tortuga web service user name')

        self.addOptionToGroup(common_group,
                              '--password',
                              dest='password',
                              help='Tortuga web service password')

        self.addOptionToGroup(common_group,
                              '--token',
                              dest='token',
                              help='Tortuga web service token')

        self.addOptionToGroup(common_group,
                              '--no-verify',
                              dest='verify',
                              action='store_false',
                              default=True,
                              help="Don't verify the API SSL certificate")

        if usage:
            self._parser.description = usage

        try:
            self._args = self._parser.parse_args()
        except SystemExit as rc:
            sys.stdout.flush()
            sys.stderr.flush()
            sys.exit(int(str(rc)))

        if self._args.cmdVersion:
            print('{0} version: {1}'.format(os.path.basename(sys.argv[0]),
                                            self._cm.getTortugaRelease()))
            sys.exit(0)

        self._setup_logging(self._args.consoleLogLevel)

        self._load_config(self._args)

        return self._args

    def _setup_logging(self, log_level_name: str):
        """
        Setup logging for the specified log level.

        :param str log_level_name: the name of the log level to use

        """
        log_level_name = log_level_name.upper()
        if log_level_name not in [
                'CRITICAL', 'ERROR', 'WARNING', 'INFO', 'DEBUG'
        ]:
            print('Invalid debug level: {}'.format(log_level_name))
            sys.exit(0)

        log_level = getattr(logging, log_level_name)

        logger = logging.getLogger(ROOT_NAMESPACE)
        logger.setLevel(log_level)

        ch = logging.StreamHandler()
        ch.setLevel(log_level)
        formatter = logging.Formatter(
            '%(asctime)s - %(name)s - %(levelname)s - %(message)s')
        ch.setFormatter(formatter)

        logger.addHandler(ch)

    def _load_config(self, args: argparse.Namespace):
        """
        Implements the --config argument.

        """
        #
        # Load a config, filename may or may-not be provided...
        #
        try:
            self._config = TortugaScriptConfig.load(args.config)

        except ConfigException as ex:
            print(str(ex))
            sys.exit(0)

        #
        # Override the config with any provided argument values
        #
        if args.url:
            self._config.url = args.url
        if args.username:
            self._config.username = args.username
        if args.password:
            self._config.password = args.password
        if args.token:
            self._config.token = args.token
        self._config.verify = args.verify

    def usage(self, s=None):
        """
        Print usage information
        """

        if s:
            sys.stderr.write('Error: {0}'.format(s)) + '\n'

        self._parser.print_help()

        sys.exit(1)

    def getArgs(self):
        return self._args

    def configureClient(self, client_class: Generic[T]) -> T:
        auth_method = self._config.get_auth_method()

        if auth_method == self._config.AUTH_METHOD_TOKEN:
            return client_class(token=self._config.get_token(),
                                baseurl=self._config.url,
                                verify=self._config.verify)

        elif auth_method == self._config.AUTH_METHOD_PASSWORD:
            return client_class(username=self._config.username,
                                password=self._config.password,
                                baseurl=self._config.url,
                                verify=self._config.verify)

        raise Exception('Unsupported auth method: {}'.format(auth_method))

    @abstractmethod
    def runCommand(self):         \
            # pylint: disable=no-self-use
        """
        This method must be implemented by the derived class.
        """

    def run(self):
        """
        Invoke runCommand() in derivative class and handle exceptions.
        """
        try:
            self.runCommand()
        except TortugaException as ex:
            print(ex.getErrorMessage())
            raise SystemExit(ex.getErrorCode())
        except SystemExit:
            raise
        except Exception as ex:
            print(str(ex))
            raise SystemExit(-1)

    def _parseDiskSize(self, diskSizeParam):         \
            # pylint: disable=no-self-use
        """
        Parses diskSizeParam, returns an int value representing
        number of megabytes

        Raises:
            ValueError
        """
        if diskSizeParam.endswith('TB'):
            return int(float(diskSizeParam[:-2]) * 1000000)

        if diskSizeParam.endswith('GB'):
            return int(float(diskSizeParam[:-2]) * 1000)
        elif diskSizeParam.endswith('MB'):
            # Must be an integer
            return int(diskSizeParam[:-2])

        return int(diskSizeParam)

    def _getDiskSizeDisplayStr(self, volSize):         \
            # pylint: disable=no-self-use

        if volSize < 1000:
            result = '%s MB' % (volSize)
        elif volSize < 1000000:
            result = '%.3f GB' % (float(volSize) / 1000)
        else:
            result = '%.3f TB' % (float(volSize) / 1000000)

        return result