import textwrap
import argparse
import getpass
+import argparse
# Third party modules
from fb_tools.common import caller_search_path
-#from .colored import ColoredFormatter, colorstr
-
-#from .obj import PpBaseObject
-
from .config import CrTplConfiguration
-#from .handler import ExpectedHandlerError, CrTplHandler
from .handler import CrTplHandler
__version__ = '0.6.4'
""" Base exception class for all exceptions in this application."""
pass
+# =============================================================================
+class NrTemplatesOptionAction(argparse.Action):
+
+ # -------------------------------------------------------------------------
+ def __init__(self, option_strings, max_val, *args, **kwargs):
+
+ self._max = max_val
+
+ super(NrTemplatesOptionAction, self).__init__(
+ option_strings=option_strings, *args, **kwargs)
+
+ # -------------------------------------------------------------------------
+ def __call__(self, parser, namespace, values, option_string=None):
+
+ if values < 1:
+ msg = "Value must be at least 1, {} was given.".format(values)
+ raise argparse.ArgumentError(self, msg)
+
+ if values >= self._max:
+ msg = "Value must be at most {m} - {v} was given.".format(
+ m=self._max - 1, v=values)
+ raise argparse.ArgumentError(self, msg)
+
+ setattr(namespace, self.dest, values)
+
+
# =============================================================================
class CrTplApplication(BaseApplication):
"""
initialized=False,
)
- #self.initialized = False
-
- #self.handler = CrTplHandler(
- # appname=self.appname, verbose=self.verbose, base_dir=self.base_dir)
-
self.initialized = True
# -------------------------------------------------------------------------
# h=self.config.vsphere_host, u=self.config.vsphere_user)
# self.config.password = getpass.getpass(prompt=prompt)
-# self.handler.config = self.config
-# if self.args.rotate:
-# self.handler.rotate_only = True
-# if self.args.abort:
-# self.handler.abort = True
+ self.handler = CrTplHandler(
+ appname=self.appname, verbose=self.verbose, base_dir=self.base_dir)
+
+ self.handler.config = self.config
+ if self.args.rotate:
+ self.handler.rotate_only = True
+ if self.args.abort:
+ self.handler.abort = True
-# self.handler.initialized = True
+ self.handler.initialized = True
self.initialized = True
# -------------------------------------------------------------------------
CrTplConfiguration.default_folder)
)
+ vmware_group.add_argument(
+ '-C', '--cluster', dest='cluster',
+ help="Host cluster in vSphere, where to create the template (Default: {!r}).".format(
+ CrTplConfiguration.default_vsphere_cluster)
+ )
+
vmware_group.add_argument(
'-M', '--vm', dest='vm',
help=(
)
vmware_group.add_argument(
- '-N', '--number', '--number-templates', dest='number',
- type=int, metavar='INT',
+ '-N', '--number', '--number-templates', dest='number', type=int, metavar='INT',
+ action=NrTemplatesOptionAction, max_val=CrTplConfiguration.limit_max_nr_templates_stay,
help=(
"Maximum number of templates to stay in templates folder ("
- "1 <= x < 100, Default: {}).".format(
- CrTplConfiguration.default_max_nr_templates_stay))
+ "1 <= x < {max_nr}, Default: {def_nr}).".format(
+ max_nr=CrTplConfiguration.limit_max_nr_templates_stay,
+ def_nr=CrTplConfiguration.default_max_nr_templates_stay))
)
vmware_group.add_argument(
pass
-# if self.args.host:
-# self.config.vsphere_host = self.args.host
-# if self.args.port:
-# self.config.vsphere_port = self.args.port
-# if self.args.user:
-# self.config.vsphere_user = self.args.user
-# if self.args.password:
-# self.config.password = self.args.password
-# if self.args.folder:
-# self.config.folder = self.args.folder
-# if self.args.vm:
-# self.config.template_vm = self.args.vm
-# if self.args.template:
-# self.config.template_name = self.args.template
-#
-# if self.args.number is not None:
-# v = self.args.number
-# if v < 1:
-# LOG.error((
-# "Wrong number {} of templates to stay in templates folder, "
-# "must be greater than zero.").format(v))
-# elif v >= 100:
-# LOG.error((
-# "Wrong number {} of templates to stay in templates folder, "
-# "must be less than 100.").format(v))
-# else:
-# self.config.max_nr_templates_stay = v
+ if self.args.host:
+ self.config.vsphere_host = self.args.host
+ if self.args.port:
+ self.config.vsphere_port = self.args.port
+ if self.args.user:
+ self.config.vsphere_user = self.args.user
+ if self.args.password:
+ self.config.password = self.args.password
+ if self.args.cluster:
+ self.config.vsphere_cluster = self.args.cluster
+ if self.args.folder:
+ self.config.folder = self.args.folder
+ if self.args.vm:
+ self.config.template_vm = self.args.vm
+ if self.args.template:
+ self.config.template_name = self.args.template
+
+ if self.args.number is not None:
+ v = self.args.number
+ if v < 1:
+ LOG.error((
+ "Wrong number {} of templates to stay in templates folder, "
+ "must be greater than zero.").format(v))
+ elif v >= 100:
+ LOG.error((
+ "Wrong number {} of templates to stay in templates folder, "
+ "must be less than 100.").format(v))
+ else:
+ self.config.max_nr_templates_stay = v
# -------------------------------------------------------------------------
def _run(self):
+++ /dev/null
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""
-@summary: additional logging formatter for colored output via console
-"""
-
-# Standard modules
-import logging
-import copy
-
-# Third party modules
-
-# Own modules
-
-__version__ = '0.1.1'
-
-# =============================================================================
-# Color coding module variables and helper functions
-
-COLOR_CODE = {
- 'ENDC': 0, # RESET COLOR
- 'BOLD': 1,
- 'UNDERLINE': 4,
- 'BLINK': 5,
- 'INVERT': 7,
- 'CONCEALD': 8,
- 'STRIKE': 9,
- 'GREY30': 90,
- 'GREY40': 2,
- 'GREY65': 37,
- 'GREY70': 97,
- 'GREY20_BG': 40,
- 'GREY33_BG': 100,
- 'GREY80_BG': 47,
- 'GREY93_BG': 107,
- 'DARK_RED': 31,
- 'RED': 91,
- 'RED_BG': 41,
- 'LIGHT_RED_BG': 101,
- 'DARK_YELLOW': 33,
- 'YELLOW': 93,
- 'YELLOW_BG': 43,
- 'LIGHT_YELLOW_BG': 103,
- 'DARK_BLUE': 34,
- 'BLUE': 94,
- 'BLUE_BG': 44,
- 'LIGHT_BLUE_BG': 104,
- 'DARK_MAGENTA': 35,
- 'PURPLE': 95,
- 'MAGENTA_BG': 45,
- 'LIGHT_PURPLE_BG': 105,
- 'DARK_CYAN': 36,
- 'AUQA': 96,
- 'AQUA': 96,
- 'CYAN_BG': 46,
- 'LIGHT_AUQA_BG': 106,
- 'LIGHT_AQUA_BG': 106,
- 'DARK_GREEN': 32,
- 'GREEN': 92,
- 'GREEN_BG': 42,
- 'LIGHT_GREEN_BG': 102,
- 'BLACK': 30,
-}
-
-
-# -----------------------------------------------------------------------------
-def termcode(num):
- """
- Output of an ANSII terminal code.
- """
-
- return('\033[%sm' % (num))
-
-
-# -----------------------------------------------------------------------------
-def colorstr(message, color):
- """
- Wrapper function to colorize the message.
-
- @param message: The message to colorize
- @type message: str
- @param color: The color to use, must be one of the keys of COLOR_CODE
- @type color: str
-
- @return: the colorized message
- @rtype: str
-
- """
-
- tcode = ''
- if isinstance(color, (list, tuple)):
- for clr in color:
- tcode += termcode(COLOR_CODE[clr])
- else:
- tcode = termcode(COLOR_CODE[color])
-
- return tcode + message + termcode(COLOR_CODE['ENDC'])
-
-
-# ----------------------------------------
-LOG = logging.getLogger(__name__)
-
-
-# =============================================================================
-class ColoredFormatter(logging.Formatter):
- """
- A variant of code found at:
- http://stackoverflow.com/questions/384076/how-can-i-make-the-python-logging-output-to-be-colored
- """
-
- LEVEL_COLOR = {
- 'DEBUG': None,
- 'INFO': 'GREEN',
- 'WARNING': 'YELLOW',
- 'ERROR': ('BOLD', 'RED'),
- 'CRITICAL': 'RED_BG',
- }
-
- # -------------------------------------------------------------------------
- def __init__(self, fmt=None, datefmt=None):
- """
- Initialize the formatter with specified format strings.
-
- Initialize the formatter either with the specified format string, or a
- default. Allow for specialized date formatting with the optional
- datefmt argument (if omitted, you get the ISO8601 format).
- """
-
- logging.Formatter.__init__(self, fmt, datefmt)
-
- # -----------------------------------------------------------
- @property
- def color_debug(self):
- """The color used to output debug messages."""
- return self.LEVEL_COLOR['DEBUG']
-
- @color_debug.setter
- def color_debug(self, value):
- self.LEVEL_COLOR['DEBUG'] = value
-
- # -----------------------------------------------------------
- @property
- def color_info(self):
- """The color used to output info messages."""
- return self.LEVEL_COLOR['INFO']
-
- @color_info.setter
- def color_info(self, value):
- self.LEVEL_COLOR['INFO'] = value
-
- # -----------------------------------------------------------
- @property
- def color_warning(self):
- """The color used to output warning messages."""
- return self.LEVEL_COLOR['WARNING']
-
- @color_warning.setter
- def color_warning(self, value):
- self.LEVEL_COLOR['WARNING'] = value
-
- # -----------------------------------------------------------
- @property
- def color_error(self):
- """The color used to output error messages."""
- return self.LEVEL_COLOR['ERROR']
-
- @color_error.setter
- def color_error(self, value):
- self.LEVEL_COLOR['ERROR'] = value
-
- # -----------------------------------------------------------
- @property
- def color_critical(self):
- """The color used to output critical messages."""
- return self.LEVEL_COLOR['CRITICAL']
-
- @color_critical.setter
- def color_critical(self, value):
- self.LEVEL_COLOR['CRITICAL'] = value
-
- # -------------------------------------------------------------------------
- def format(self, record):
- """
- Format the specified record as text.
- """
-
- record = copy.copy(record)
- levelname = record.levelname
-
- if levelname in self.LEVEL_COLOR:
-
- record.name = colorstr(record.name, 'BOLD')
- record.filename = colorstr(record.filename, 'BOLD')
- record.module = colorstr(record.module, 'BOLD')
- record.funcName = colorstr(record.funcName, 'BOLD')
- record.pathname = colorstr(record.pathname, 'BOLD')
- record.processName = colorstr(record.processName, 'BOLD')
- record.threadName = colorstr(record.threadName, 'BOLD')
-
- if self.LEVEL_COLOR[levelname] is not None:
- record.levelname = colorstr(
- levelname, self.LEVEL_COLOR[levelname])
- record.msg = colorstr(record.msg, self.LEVEL_COLOR[levelname])
-
- return logging.Formatter.format(self, record)
-
-
-# =============================================================================
-
-if __name__ == "__main__":
- pass
-
-# =============================================================================
-
-# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
default_max_nr_templates_stay = 4
min_max_wait_for_finish_install = 3 * 60
max_max_wait_for_finish_install = 24 * 60 * 60
+ limit_max_nr_templates_stay = 100
mac_address_template = "00:16:3e:53:{:02x}:{:02x}"
res['default_mac_address'] = self.default_mac_address
res['default_max_wait_for_finish_install'] = self.default_max_wait_for_finish_install
res['default_max_nr_templates_stay'] = self.default_max_nr_templates_stay
+ res['limit_max_nr_templates_stay'] = self.limit_max_nr_templates_stay
res['min_max_wait_for_finish_install'] = self.min_max_wait_for_finish_install
res['max_max_wait_for_finish_install'] = self.max_max_wait_for_finish_install
res['mac_address_template'] = self.mac_address_template
from pyVim.connect import SmartConnect, Disconnect
# Own modules
-from .common import pp, to_str
-from .errors import PpError
+from fb_tools.common import pp, to_str
-from .obj import PpBaseObject
+from fb_tools.errors import HandlerError, ExpectedHandlerError, CommandNotFoundError
+from fb_tools.errors import TerraformVmError, TerraformVmDefinitionError, NetworkNotExistingError
+from fb_tools.errors import CannotConnectVsphereError, NoDatastoreFoundError
+
+from fb_tools.handler import BaseHandler
from .config import CrTplConfiguration
-__version__ = '0.9.4'
+__version__ = '0.10.1'
LOG = logging.getLogger(__name__)
TZ = pytz.timezone('Europe/Berlin')
-# =============================================================================
-class HandlerError(PpError, RuntimeError):
- """Base error class for all exceptions happened during
- execution this handler"""
-
- pass
-
-
-# =============================================================================
-class ExpectedHandlerError(HandlerError):
- """Base class for all errors, which could be expected in application object
- and displayed without stack trace."""
-
- pass
-
# =============================================================================
class TempVmExistsError(ExpectedHandlerError):
"""Special error class for the case, if the temporary VM is already existing."""
# =============================================================================
-class NoDatastoreFoundError(ExpectedHandlerError):
- """Special error class for the case, that no SAN based data store was with
- enogh free space was found."""
-
- # -------------------------------------------------------------------------
- def __init__(self, needed_bytes):
-
- self.needed_bytes = int(needed_bytes)
-
- # -------------------------------------------------------------------------
- def __str__(self):
-
- mb = float(self.needed_bytes) / 1024.0 / 1024.0
- gb = mb / 1024.0
-
- msg = (
- "No SAN based datastore found with at least {m:0.0f} MiB == {g:0.1f} GiB "
- "available space found.").format(m=mb, g=gb)
- return msg
-
-
-# =============================================================================
-class NetworkNotExistingError(ExpectedHandlerError):
- """Special error class for the case, if the expected network is not existing."""
-
- # -------------------------------------------------------------------------
- def __init__(self, net_name):
-
- self.net_name = net_name
-
- # -------------------------------------------------------------------------
- def __str__(self):
-
- msg = "The network {!r} is not existing.".format(self.net_name)
- return msg
-
-
-# =============================================================================
-class CannotConnectError(ExpectedHandlerError):
- """Special error class for the case, it cannot connect
- to the given vSphere server."""
-
- # -------------------------------------------------------------------------
- def __init__(self, host, port, user):
-
- self.host = host
- self.port = port
- self.user = user
-
- # -------------------------------------------------------------------------
- def __str__(self):
-
- msg = "Could not connect to the vSphere host {h}:{p} as user {u!r}.".format(
- h=self.host, p=self.port, u=self.user)
- return msg
-
-
-# =============================================================================
-class CrTplHandler(PpBaseObject):
+class CrTplHandler(BaseHandler):
"""
A handler class for creating a vSphere template.
"""
sslContext=ssl_context)
if not self.service_instance:
- raise CannotConnectError(
+ raise CannotConnectVsphereError(
host=self.config.vsphere_host, port=self.config.vsphere_port,
user=self.config.vsphere_user)
+++ /dev/null
-#!/usr/bin/env python
-# -*- coding: utf-8 -*-
-"""
-@author: Frank Brehm
-@contact: frank.brehm@pixelpark.com
-@copyright: © 2018 by Frank Brehm, Publicies Pixelpark GmbH, Berlin
-"""
-from __future__ import absolute_import
-
-# Standard modules
-import sys
-import os
-import logging
-import datetime
-import traceback
-
-# Third party modules
-
-# Own modules
-from .common import pp, to_bytes
-
-from .errors import PpError
-
-__version__ = '0.2.4'
-
-LOG = logging.getLogger(__name__)
-
-
-# =============================================================================
-class PpBaseObjectError(PpError):
- """
- Base error class useable by all descendand objects.
- """
-
- pass
-
-
-# =============================================================================
-class PpBaseObject(object):
- """
- Base class for all objects.
- """
-
- # -------------------------------------------------------------------------
- def __init__(
- self, appname=None, verbose=0, version=__version__, base_dir=None,
- initialized=False):
- """
- Initialisation of the base object.
-
- Raises an exception on a uncoverable error.
- """
-
- self._appname = None
- """
- @ivar: name of the current running application
- @type: str
- """
- if appname:
- v = str(appname).strip()
- if v:
- self._appname = v
- if not self._appname:
- self._appname = os.path.basename(sys.argv[0])
-
- self._version = version
- """
- @ivar: version string of the current object or application
- @type: str
- """
-
- self._verbose = int(verbose)
- """
- @ivar: verbosity level (0 - 9)
- @type: int
- """
- if self._verbose < 0:
- msg = "Wrong verbose level {!r}, must be >= 0".format(verbose)
- raise ValueError(msg)
-
- self._initialized = False
- """
- @ivar: initialisation of this object is complete
- after __init__() of this object
- @type: bool
- """
-
- self._base_dir = base_dir
- """
- @ivar: base directory used for different purposes, must be an existent
- directory. Defaults to directory of current script daemon.py.
- @type: str
- """
- if base_dir:
- if not os.path.exists(base_dir):
- msg = "Base directory {!r} does not exists.".format(base_dir)
- self.handle_error(msg)
- self._base_dir = None
- elif not os.path.isdir(base_dir):
- msg = "Base directory {!r} is not a directory.".format(base_dir)
- self.handle_error(msg)
- self._base_dir = None
- if not self._base_dir:
- self._base_dir = os.path.dirname(os.path.abspath(sys.argv[0]))
-
- self._initialized = bool(initialized)
-
- # -----------------------------------------------------------
- @property
- def appname(self):
- """The name of the current running application."""
- if hasattr(self, '_appname'):
- return self._appname
- return os.path.basename(sys.argv[0])
-
- @appname.setter
- def appname(self, value):
- if value:
- v = str(value).strip()
- if v:
- self._appname = v
-
- # -----------------------------------------------------------
- @property
- def version(self):
- """The version string of the current object or application."""
- return getattr(self, '_version', __version__)
-
- # -----------------------------------------------------------
- @property
- def verbose(self):
- """The verbosity level."""
- return getattr(self, '_verbose', 0)
-
- @verbose.setter
- def verbose(self, value):
- v = int(value)
- if v >= 0:
- self._verbose = v
- else:
- LOG.warn("Wrong verbose level {!r}, must be >= 0".format(value))
-
- # -----------------------------------------------------------
- @property
- def initialized(self):
- """The initialisation of this object is complete."""
- return getattr(self, '_initialized', False)
-
- @initialized.setter
- def initialized(self, value):
- self._initialized = bool(value)
-
- # -----------------------------------------------------------
- @property
- def base_dir(self):
- """The base directory used for different purposes."""
- return self._base_dir
-
- @base_dir.setter
- def base_dir(self, value):
- if value.startswith('~'):
- value = os.path.expanduser(value)
- if not os.path.exists(value):
- msg = "Base directory {!r} does not exists.".format(value)
- LOG.error(msg)
- elif not os.path.isdir(value):
- msg = "Base directory {!r} is not a directory.".format(value)
- LOG.error(msg)
- else:
- self._base_dir = value
-
- # -------------------------------------------------------------------------
- def __str__(self):
- """
- Typecasting function for translating object structure
- into a string
-
- @return: structure as string
- @rtype: str
- """
-
- return pp(self.as_dict(short=True))
-
- # -------------------------------------------------------------------------
- def __repr__(self):
- """Typecasting into a string for reproduction."""
-
- out = "<%s(" % (self.__class__.__name__)
-
- fields = []
- fields.append("appname={!r}".format(self.appname))
- fields.append("verbose={!r}".format(self.verbose))
- fields.append("version={!r}".format(self.version))
- fields.append("base_dir={!r}".format(self.base_dir))
- fields.append("initialized={!r}".format(self.initialized))
-
- out += ", ".join(fields) + ")>"
- return out
-
- # -------------------------------------------------------------------------
- def as_dict(self, short=True):
- """
- Transforms the elements of the object into a dict
-
- @param short: don't include local properties in resulting dict.
- @type short: bool
-
- @return: structure as dict
- @rtype: dict
- """
-
- res = self.__dict__
- res = {}
- for key in self.__dict__:
- if short and key.startswith('_') and not key.startswith('__'):
- continue
- val = self.__dict__[key]
- if isinstance(val, PpBaseObject):
- res[key] = val.as_dict(short=short)
- else:
- res[key] = val
- res['__class_name__'] = self.__class__.__name__
- res['appname'] = self.appname
- res['version'] = self.version
- res['verbose'] = self.verbose
- res['initialized'] = self.initialized
- res['base_dir'] = self.base_dir
-
- return res
-
- # -------------------------------------------------------------------------
- def handle_error(
- self, error_message=None, exception_name=None, do_traceback=False):
- """
- Handle an error gracefully.
-
- Print a traceback and continue.
-
- @param error_message: the error message to display
- @type error_message: str
- @param exception_name: name of the exception class
- @type exception_name: str
- @param do_traceback: allways show a traceback
- @type do_traceback: bool
-
- """
-
- msg = 'Exception happened: '
- if exception_name is not None:
- exception_name = exception_name.strip()
- if exception_name:
- msg = exception_name + ': '
- else:
- msg = ''
- if error_message:
- msg += str(error_message)
- else:
- msg += 'undefined error.'
-
- root_log = logging.getLogger()
- has_handlers = False
- if root_log.handlers:
- has_handlers = True
-
- if has_handlers:
- LOG.error(msg)
- if do_traceback:
- LOG.error(traceback.format_exc())
- else:
- curdate = datetime.datetime.now()
- curdate_str = "[" + curdate.isoformat(' ') + "]: "
- msg = curdate_str + msg + "\n"
- if hasattr(sys.stderr, 'buffer'):
- sys.stderr.buffer.write(to_bytes(msg))
- else:
- sys.stderr.write(msg)
- if do_traceback:
- traceback.print_exc()
-
- return
-
- # -------------------------------------------------------------------------
- def handle_info(self, message, info_name=None):
- """
- Shows an information. This happens both to STDERR and to all
- initialized log handlers.
-
- @param message: the info message to display
- @type message: str
- @param info_name: Title of information
- @type info_name: str
-
- """
-
- msg = ''
- if info_name is not None:
- info_name = info_name.strip()
- if info_name:
- msg = info_name + ': '
- msg += str(message).strip()
-
- root_log = logging.getLogger()
- has_handlers = False
- if root_log.handlers:
- has_handlers = True
-
- if has_handlers:
- LOG.info(msg)
- else:
- curdate = datetime.datetime.now()
- curdate_str = "[" + curdate.isoformat(' ') + "]: "
- msg = curdate_str + msg + "\n"
- if hasattr(sys.stderr, 'buffer'):
- sys.stderr.buffer.write(to_bytes(msg))
- else:
- sys.stderr.write(msg)
-
- return
-
-# =============================================================================
-
-if __name__ == "__main__":
-
- pass
-
-# =============================================================================
-
-# vim: tabstop=4 expandtab shiftwidth=4 softtabstop=4
-Subproject commit 64111976cd55a439b5b63de14945acc75041b90c
+Subproject commit 98a58ece2e8cb15223d584130e71ef59986cdf26