From 8685e9aa592a80a496f6962001b7cf25c726fe9e Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Mon, 7 Nov 2016 08:05:19 +0100 Subject: [PATCH 01/42] Initial version of General Configuration Validation --- config/hilbert-cli-config.py | 1055 ++++++++++++++++++++++++++++++++++ 1 file changed, 1055 insertions(+) create mode 100755 config/hilbert-cli-config.py diff --git a/config/hilbert-cli-config.py b/config/hilbert-cli-config.py new file mode 100755 index 0000000..0b1c88f --- /dev/null +++ b/config/hilbert-cli-config.py @@ -0,0 +1,1055 @@ +#! /usr/bin/env python3 +# coding: utf-8 +# encoding: utf-8 + +from sys import argv, version_info + +############################################################### +up_arrow = '↑' + +def key_error(key, value, line, col, error_message, e='K'): + print('{}[line: {}, column: {}]: {}'.format(e, line+1, col+1, error_message.format(key))) + print('{}{}: {}'.format(' '*col, key, value)) + print('{}{}'.format(' '*(col), up_arrow)) + print('---') + + +def key_note(key, line, col, key_message, e='K'): + print('{}[line: {}, column: {}]: {}'.format(e, line+1, col+1, key_message.format(key))) + print('---') + + +def value_error(key, value, line, col, error, e='E'): + val_col = col + len(key) + 2 + print('{}[line: {}, column: {}]: {}'.format(e, line+1, val_col+1, error . format(key))) + print('{}{}: {}'.format(' '*col, key, value)) + print('{}{}'.format(' '*(val_col), up_arrow)) + print('---') + +def value_warning(key, value, line, col, error): + value_error(key, value, line, col, error, e='W') + +############################################################### +import collections +import ruamel.yaml as yaml + +from ruamel.yaml.reader import Reader +from ruamel.yaml.scanner import RoundTripScanner # Scanner +from ruamel.yaml.parser import RoundTripParser # Parser, +from ruamel.yaml.composer import Composer +from ruamel.yaml.constructor import RoundTripConstructor # Constructor, SafeConstructor, +from ruamel.yaml.resolver import VersionedResolver # Resolver, +from ruamel.yaml.nodes import MappingNode + +############################################################### +class VerboseRoundTripConstructor(RoundTripConstructor): + def construct_mapping(self, node, deep=False): + + m = RoundTripConstructor.construct_mapping(self, node, deep) # the actual construction! + + # additionally go through all nodes in the mapping to detect overwrites: + + starts = {} # already processed keys + locations and values + + for key_node, value_node in node.value: + # keys can be list -> deep + key = self.construct_object(key_node, deep=True) + + # lists are not hashable, but tuples are + if not isinstance(key, collections.Hashable): + if isinstance(key, list): + key = tuple(key) + + value = self.construct_object(value_node, deep=deep) + # TODO: check the lines above in the original Constructor.construct_mapping code for any changes/updates + + if key in starts: # Duplication detection + old = starts[key] + print( "WARNING: Key re-definition within some mapping: " ) # mapping details? + key_error( key, old[1], old[0].line, old[0].column, "Previous Value: " ) + key_error( key, value, key_node.start_mark.line, key_node.start_mark.column, "New Value: ") + print('===') + + starts[key] = (key_node.start_mark, value) # in order to find all such problems! + + return m + +############################################################### +class VerboseRoundTripLoader(Reader, RoundTripScanner, RoundTripParser, Composer, + VerboseRoundTripConstructor, VersionedResolver): + def __init__(self, stream, version=None, preserve_quotes=None): + Reader.__init__(self, stream) + RoundTripScanner.__init__(self) + RoundTripParser.__init__(self) + Composer.__init__(self) + VerboseRoundTripConstructor.__init__(self, preserve_quotes=preserve_quotes) + VersionedResolver.__init__(self, version) + +############################################################### +class ConfigurationError(Exception): + def __init__(self, msg): + self._msg = msg + +############################################################### +def load_yaml(filename): + try: + with open(filename, 'r') as fh: + return yaml.load(fh, Loader = VerboseRoundTripLoader, version = (1, 2), preserve_quotes=True) + + except (IOError, yaml.YAMLError) as e: + error_name = getattr(e, '__module__', '') + '.' + e.__class__.__name__ + raise ConfigurationError(u"{}: {}".format(error_name, e)) + +############################################################### +from ruamel.yaml.compat import PY2, PY3, text_type +from abc import * + +if PY3 and (version_info[1] >= 4): + class Abstract(ABC): + """Abstract Base class for any concrete implementation of entities appearing in the general configuration file""" + @abstractmethod + def validate(self, data): + pass +elif PY2 or PY3: + class Abstract: + """Abstract Base class for any concrete implementation of entities appearing in the general configuration file""" + __metaclass__ = ABCMeta + @abstractmethod + def validate(self, data): + pass +#elif PY3: +# class Abstract(metaclass=ABCMeta): +# """Abstract Base class for any concrete implementation of entities appearing in the general configuration file""" +# @abstractmethod +# def validate(self, data): +# pass +else: + raise NotImplementedError("Unsupported Python version: '{}'".format(version_info)) + +############################################################### +class Base(Abstract): + """Actual Base Class for the Config entities""" + + __version = [None] + _data = None + _parent = None + + def __init__(self, parent): + Abstract.__init__(self) + assert self._parent is None + self._parent = parent + + def set_version(self, v): + """To be set once only!""" + assert len(self.__version) == 1 + assert self.__version[0] is None + self.__version[0] = v + + def get_version(self): + assert len(self.__version) == 1 + assert self.__version[0] is not None + return self.__version[0] + + def set_data(self, d): + assert self._data is None + self._data = d + + def get_data(self): + if self._data is None: + return self._default_data + + return self._data + + @abstractmethod + def validate(self, version, data): # version = None? + pass + + def validate(self, data): + return self.validate(self.get_version(), data) + + + @classmethod + def parse(cls, data, parent=None): + self = cls(parent) + + if self.validate(get_version(), data): + return self.get_data() + + raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data!")) + + + +############################################################### +class BaseRecord(Base): + """Aggregation of data as a record with some fixed data memebers""" + + # TODO: turn _default_type into a class-member (by moving it here)...? + + def __init__(self, parent): + Base.__init__(self, parent) + self._default_type = None # "default_base" + self._types = {} + + + def detect_type(self, data): + return self.detect_type(self.get_version(), data) + +# @abstractmethod +# def detect_type(self, version, data): +# pass + + + def detect_type(self, version, data): + """determine the type of variadic data for the format version""" + + assert not (self._default_type is None) + assert len(self._types) > 0 + + return self._default_type + + def validate(self, version, data): + _type = self.detect_type(version, data) + + assert not (_type is None) + assert _type in self._types + + _rule = self._types[_type] + + _ret = True + + c = data.lc.col + s = data.lc.line # starting line + + for k in _rule.keys(): + r = _rule[k] + if r[0] and (k not in data): + key_note(k, s, c, "Error: Missing key `{}` (type: '%s')" % (_type)) # Raise Exception? + _ret = False + + _d = {} + + for offset, k in enumerate(data): + v = data.get(k) + l = s + offset + + if k not in _rule: + key_error(k, v, l, c, "Warning: Unexpected/Unknown Key: '{}' (type: '%s')" % (_type)) # Raise Exception? + _ret = False + else: + r = _rule[k] + + _d[k] = r[1](self) + + if not _d[k].validate(version, v): # TODO: save to self! + value_error(k, v, l, c, "Error: invalid field '{}' value (type: '%s')" % (_type)) # Raise Exception? + _ret = False + + self.set_data(_d) + + return _ret + +############################################################### +class BaseScalar(Base): + """Single scalar value out of YAML scalars""" + + def __init__(self, parent): + Base.__init__(self, parent) + + +############################################################### +#import semver +import semantic_version # supports partial versions + +class SemanticVersion(BaseScalar): + def __init__(self, parent): + BaseScalar.__init__(self, parent) + + def validate(self, version, data): + """check the string data to be a valid semantic verions""" + + if version == '': # the only initial validation: may be a partial version + self._data = semantic_version.Version(data, partial=True) #!? + return True + +# try: + self.set_data( semantic_version.validate(data) ) + return True +# except: +# return False + +############################################################### +class BaseString(BaseScalar): + def __init__(self, parent): + BaseScalar.__init__(self, parent) + + def validate(self, version, data): + """check whether data is a valid string""" + ### TODO: Detect other YAML scalar types? + try: + self.set_data( text_type(data) ) + return True + except: + print( "ERROR: Cannot conver '{}' into string!" % format(data) ) + self.set_data( data ) + + +############################################################### +class BaseUIString(BaseString): # visible to user => non empty! + def __init__(self, parent): + BaseString.__init__(self, parent) + + def validate(self, version, data): + """check whether data is a valid string""" + _ret = BaseString.validate(self, version, data) + + _ret = _ret and (self.get_data()) # Non-empty + return _ret + +############################################################### +class BaseEnum(BaseString): # TODO: Generalize to not only strings... + def __init__(self, parent): + BaseString.__init__(self, parent) + self._types = [] # will depend on the version... + + def validate(self, version, data): + """check whether data is a valid string""" + _ret = BaseString.validate(self, version, data) + + _ret = _ret and (self.get_data() in self._types) # check withing a list of possible string values + return _ret + +############################################################### +class ServiceType(BaseEnum): ## Q: Is 'Service::type' mandatory? default: 'compose' + def __init__(self, parent): + BaseEnum.__init__(self, parent) + + _v = 'compose' + self._types = [_v] # NOTE: will depend on format version! + self._default_data = _v + +############################################################### +class StationOMDTag(BaseEnum): ## Q: Is 'Station::omd_tag' mandatory? default: 'standalone' + def __init__(self, parent): + BaseEnum.__init__(self, parent) + + _v = 'standalone' + self._types = ['agent', 'windows', _v] # possible values of omd_tag # will depend on format version! + self._default_data = _v + +############################################################### +class StationPowerOnMethodType(BaseEnum): # Enum: [WOL], AMTvPRO, DockerMachine + def __init__(self, parent): + BaseEnum.__init__(self, parent) + + _v = 'WOL' + self._types = ['AMTvPRO', 'DockerMachine', _v] # possible values of PowerOnMethod::type # will depend on format version! + self._default_data = _v + +############################################################### +class URI(BaseString): + def __init__(self, parent): + BaseString.__init__(self, parent) + + def validate(self, version, data): + """check whether data is a valid URI""" + _ret = BaseString.validate(self, version, data) + + # TODO: Check if file exists? + return _ret + +############################################################### +import re, tokenize + +if PY3: + def is_valid_id(id): + return id.isidentifier() +elif PY2: + def is_valid_id(id): + return re.match(tokenize.Name + '$', id) +else: + raise NotImplementedError("Unsupported Python version: '{}'".format(version_info)) + +############################################################### +class BaseID(BaseString): + def __init__(self, parent): + BaseString.__init__(self, parent) + + def validate(self, version, data): + """check whether data is a valid ID string""" + _ret = BaseString.validate(self, version, data) + _ret = _ret and is_valid_id(self.get_data()) + return _ret + +############################################################### +class ServiceID(BaseID): + def __init__(self, parent): + BaseID.__init__(self, parent) + # TODO: move uniqueness check here??? + +class ApplicationID(BaseID): + def __init__(self, parent): + BaseID.__init__(self, parent) + +############################################################### +class GroupID(BaseID): + def __init__(self, parent): + BaseID.__init__(self, parent) + # TODO: move uniqueness check here??? + +class StationID(BaseID): + def __init__(self, parent): + BaseID.__init__(self, parent) + +class ProfileID(BaseID): + def __init__(self, parent): + BaseID.__init__(self, parent) + +############################################################### +class PresetID(BaseID): + def __init__(self, parent): + BaseID.__init__(self, parent) + +############################################################### +class AutoDetectionScript(BaseString): + def __init__(self, parent): + BaseString.__init__(self, parent) + + def validate(self, version, data): + """check whether data is a valid script""" + _ret = BaseString.validate(self, version, data) + + # TODO: Check the script? + return _ret + +############################################################### +class DockerComposeServiceName(BaseString): + def __init__(self, parent): + BaseString.__init__(self, parent) + + def validate(self, version, data): + """check whether data is a valid service name in file due to DockerComposeRef""" + + _ret = BaseString.validate(self, version, data) + # TODO: Check the corresponding file for such a service -> Service! + return _ret + +############################################################### +class DockerComposeRef(URI): + def __init__(self, parent): + URI.__init__(self, parent) + self._default_data = "docker-compose.yml" + + def validate(self, version, data): + """check whether data is a valid docker-compose file name""" + _ret = URI.validate(self, version, data) + + ### TODO: call docker-compose on the referenced file! + return _ret + +############################################################### +class Icon(URI): + def __init__(self, parent): + URI.__init__(self, parent) + + def validate(self, version, data): + """check whether data is a valid icon file name""" + _ret = URI.validate(self, version, data) + + ### TODO: check the file contents (or extention) + return _ret + +############################################################### +class HostAddress(BaseString): # ! BaseString, SSH alias + def __init__(self, parent): + BaseString.__init__(self, parent) + + def validate(self, version, data): + """check whether data is a valid ssh alias?""" + + _ret = BaseString.validate(self, version, data) + + # TODO: Check for ssh alias! + return _ret + +############################################################### +class BaseBool(BaseScalar): + def __init__(self, parent): + BaseScalar.__init__(self, parent) + + def validate(self, version, data): + """check whether data is a valid string""" + ### TODO: Detect other YAML scalar types? + + if (data == True) or (data == False): + self.set_data( data ) + return True + + return False + +class StationVisibility(BaseBool): ## "hidden": True / [False] + def __init__(self, parent): + BaseBool.__init__(self, parent) + self._default_data = False + + +class AutoTurnon(BaseBool): # Bool, True + def __init__(self, parent): + BaseBool.__init__(self, parent) + self._default_data = True + +############################################################### +class VariadicRecord(BaseRecord): + """Variadic record. Type is determined by the given 'type' field.""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._type_tag = "type" + self._default_type = None + self._types = {} + + def detect_type(self, version, data): + """determine the type of variadic data for the format version""" + + assert not (self._default_type is None) + assert len(self._types) > 0 + assert self._default_type in self._types + assert self._type_tag in self._types[self._default_type] + + _rule = self._types[self._default_type][self._type_tag] + + if _rule[0] and (self._type_tag not in data): + try: + (l, c) = data.lc # start of the current mapping + except: + print ("WRONG DATA: ") + print (data) + raise ConfigurationError(u"{}: {}".format("mapping data without line/column!!!", 'some VariadicRecord')) + + + key_error(self._type_tag, l, c, "Missing mandatory key `{}`" % (_type)) # Raise Exception? + return None + + t = data.get(self._type_tag, self._default_type) + + tt = _rule[1](self) + if not tt.validate(version, t): + (l, c) = data.lc.key(self._type_tag) + value_error(self._type_tag, t, l, c, "invalid value '{}'") # Raise Exception? + return None + + self._type = tt + return tt.get_data() + +############################################################### +class StationPowerOnMethod(VariadicRecord): + """StationPowerOnMethod""" + + def __init__(self, parent): + VariadicRecord.__init__(self, parent) + + self._default_type = "WOL" # ServiceType("compose")? + + WOL_rule = { + self._type_tag: (True, StationPowerOnMethodType), # Mandatory? + "auto_turnon": (False, AutoTurnon), + "mac": (True, HostMACAddress) + } + + self._types = { self._default_type: WOL_rule } + +############################################################### +class Service(VariadicRecord): + """Service data type""" + + def __init__(self, parent): + VariadicRecord.__init__(self, parent) + + self._default_type = "compose" # ServiceType("compose")? + + self._hook_tag = "auto_detections" + self._name_tag = "name" + self._file_tag = "file" + + compose_rule = { + self._type_tag: (True, ServiceType), # Mandatory + self._hook_tag: (False, AutoDetectionScript), + self._name_tag: (True, DockerComposeServiceName), + self._file_tag: (False, DockerComposeRef) + } + + self._types = { self._default_type: compose_rule } + + def validate(self, version, data): + _ret = VariadicRecord.validate(self, version, data) + + ### TODO: call docker-compose on the referenced file with the given Service Name + return _ret + +############################################################### +class Application(Service): + """Application""" + + def __init__(self, parent): + Service.__init__(self, parent) + + self._default_type = "compose" # ServiceType("compose")? + + compose_rule = { + self._type_tag: (True, ServiceType), # Mandatory + self._hook_tag: (False, AutoDetectionScript), + self._name_tag: (True, DockerComposeServiceName), + self._file_tag: (False, DockerComposeRef), + "name": (True, BaseUIString), + "description": (True, BaseUIString), + "icon": (False, Icon), + "compatibleStations": (True, Group) + } + + self._types = { self._default_type: compose_rule } + +############################################################### +class Profile(BaseRecord): + """Profile""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._default_type = "default_profile" + + default_rule = { + "name": (True, BaseUIString), + "description": (True, BaseUIString), + "icon": (False, Icon), + "services": (True, ServiceList) + } + + self._types = { self._default_type: default_rule } + + +############################################################### +class StationSSHOptions(BaseRecord): # optional: "Station::ssh_options" # record: user, port, key, key_ref + """StationSSHOptions""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._default_type = "default_station_ssh_options" + + default_rule = { + "user": (False, BaseString), + "key": (False, BaseString), + "port": (False, BaseString), # TODO: BaseInt?? http://stackoverflow.com/questions/4187185/how-can-i-check-if-my-python-object-is-a-number + "key_ref": (False, URI), + } + + self._types = { self._default_type: default_rule } + + def validate(self, version, data): + """check whether data is a valid ssh connection options""" + + _ret = BaseRecord.validate(self, version, data) + + # TODO: Check for ssh connection: Use some Python SSH Wrapper (2/3) + return _ret + +############################################################### +class Station(BaseRecord): + """Station""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._default_type = "default_station" + + default_rule = { + "name": (True, BaseUIString), + "description": (True, BaseUIString), + "icon": (False, Icon), + "extends": (False, StationID), + "profile": (True, ProfileID), + "address": (True, HostAddress), + "poweron_settings": (False, StationPowerOnMethod), # !! variadic, PowerOnType... + "ssh_options": (False, StationSSHOptions), # !!! record: user, port, key, key_ref + "omd_tag": (True, StationOMDTag), # ! like ServiceType: e.g. agent. Q: Is this mandatory? + "hidden": (False, StationVisibility), # Q: Is this mandatory? + "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) + } + + self._types = { self._default_type: default_rule } + + +############################################################### +class BaseIDMap(Base): + """Mapping: SomeTypeID -> AnyType""" + + def __init__(self, parent): + Base.__init__(self, parent) + self._default_type = None + self._types = {} # type -> (TypeID, Type) + +# def validate_ID(self, key): # special ID type!!! +# return is_valid_id(key) + + def detect_type(self, version, data): + """determine the type of variadic data for the format version""" + + assert not (self._default_type is None) + assert len(self._types) > 0 + + return self._default_type + + def validate(self, version, data): + _type = self.detect_type(version, data) + + assert not (_type is None) + assert _type in self._types + + (_id, _rule) = self._types[_type] + + _ret = True + + c = data.lc.col + s = data.lc.line # starting line + + _d = {} + for offset, k in enumerate(data): + v = data.get(k) + l = s + offset + + id = _id(self) + + if not id.validate(version, k): + key_error(k, v, l, c, "Invalid Key ID: '{}' (type: '%s')" % (_type)) # Raise Exception? + _ret = False + else: + _d[id] = _rule(self) + + if not _d[id].validate(version, v): # TODO: save to self! + value_error(k, v, l, c, "invalid value '{}' value (type: '%s')" % (_type)) # Raise Exception? + _ret = False + + self.set_data(_d) + + return _ret + +############################################################### +class GlobalServices(BaseIDMap): + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_global_services" + self._types = { self._default_type: (ServiceID, Service) } + + # def validate(self, version, data): + # _ret = BaseID.validate(self, version, data) + # ### TODO: Any post processing? + # return _ret + + +############################################################### +class StationClientSettings(BaseIDMap): # "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_station_client_settings" + self._types = { self._default_type: (BaseID, BaseString) } + +############################################################### +class GlobalApplications(BaseIDMap): + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_global_applications" + self._types = { self._default_type: (ApplicationID, Application) } + + # def validate(self, version, data): + # _ret = BaseID.validate(self, version, data) + # ### TODO: Any post processing? + # return _ret + +############################################################### +class GlobalProfiles(BaseIDMap): + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_global_profiles" + self._types = { self._default_type: (ProfileID, Profile) } + + # def validate(self, version, data): + # _ret = BaseID.validate(self, version, data) + # ### TODO: Any post processing? + # return _ret + +############################################################### +class GlobalStations(BaseIDMap): + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_global_stations" + self._types = { self._default_type: (StationID, Station) } + + # def validate(self, version, data): + # _ret = BaseID.validate(self, version, data) + # ### TODO: Any post processing? + # return _ret + +############################################################### +import collections + +if PY2: + def issequenceforme(obj): + if isinstance(obj, basestring): + return False + return isinstance(obj, collections.Sequence) +elif PY3: + def issequenceforme(obj): +# if isinstance(obj, basestring): +# return False + # TODO: ??? + return isinstance(obj, collections.Sequence) +else: + raise NotImplementedError("Unsupported Python version: '{}'".format(version_info)) + +############################################################### +class BaseList(Base): + """List of entities of the same type""" + + def __init__(self, parent): + Base.__init__(self, parent) + + def detect_type(self, version, data): + """determine the class of items based on the version and sample data""" + + assert not (self._default_type is None) + assert len(self._types) > 0 + + return self._types[self._default_type] + + def validate(self, version, data): + _type = self.detect_type(version, data) + assert _type is not None + + lc = data.lc + + if not issequenceforme(data): + data = [data] + + _d = [] + + _ret = True + for idx, i in enumerate(data): + _v = _type(self) + if not _v.validate(version, i): + # TODO: error # show lc + print( "Error insequence at {}" . format(idx) ) + _ret = False + else: + _d.insert(idx, _v) # append? + + self.set_data(_d) + return _ret + +############################################################### +class GroupIDList(BaseList): + """List of GroupIDs or a single GroupID!""" + + def __init__(self, parent): + BaseList.__init__(self, parent) + + self._default_type = "default_GroupID_list" + self._types = { self._default_type: GroupID } + +############################################################### +class ServiceList(BaseList): + """List of ServiceIDs or a single ServiceID!""" + + def __init__(self, parent): + BaseList.__init__(self, parent) + + self._default_type = "default_ServiceID_list" + self._types = { self._default_type: ServiceID } + +############################################################### +class Group(BaseRecord): #? TODO: GroupSet & its .parent? + """Group""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._default_type = "default_group" + + self._include_tag = "include" + self._exclude_tag = "exclude" + self._intersectWith_tag = "intersectWith" + + default_rule = { + self._include_tag: (False, GroupIDList), + self._exclude_tag: (False, GroupIDList), + self._intersectWith_tag: (False, GroupIDList), + "name": (False, BaseUIString), + "description": (False, BaseUIString), + "icon": (False, Icon) + + } + + self._types = { self._default_type: default_rule } + + def validate(self, version, data): + _lc = data.lc + + ### TODO: preprocess set entries: GroupIDs from d + d = data # deep copy? + + _ret = BaseRecord.validate(self, version, d) + + return _ret + +############################################################### +class GlobalGroups(BaseIDMap): + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_global_groups" + self._types = { self._default_type: (GroupID, Group) } + + +############################################################### +class Preset(BaseRecord): + """Preset""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._default_type = "default_preset" + + # self.__tag = "Version" + default_rule = { + # self.__tag: (True , ??), # Mandatory + # self.__tag: (False, ??), # Optional + } + + self._types = { self._default_type: default_rule } + + raise NotImplementedError("Presets are not supported yet!") + +############################################################### +class GlobalPresets(BaseIDMap): # Dummy for now! + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_global_presets" + self._types = { self._default_type: (PresetID, Preset) } + + def validate(self, version, data): + print ("Warning: Presets are not supported yet!") +# raise NotImplementedError("Presets are not supported yet!") + return True + +############################################################### +class Global(BaseRecord): + """General Hilbert Configuration format""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) # This is the Main Root! + + self._default_type = "default_global" + + self._version_tag = "Version" + self._applications_tag = "Applications" + self._services_tag = "Services" + self._profiles_tag = "Profiles" + self._stations_tag = "Stations" + self._groups_tag = "Groups" + + ### explicit (optional) Type? + default_rule = { + self._version_tag: (True, SemanticVersion), # Mandatory, specifies possibly supported Types of each Configuration Entity + self._services_tag: (True, GlobalServices), + self._applications_tag: (True, GlobalApplications), + self._profiles_tag: (True, GlobalProfiles), + self._stations_tag: (True, GlobalStations), + self._groups_tag: (False, GlobalGroups), # Optional + "Presets": (False, GlobalPresets), # Optional. May be removed! default? + } + + self._types = { self._default_type: default_rule } + + @classmethod + def parse(cls, data, parent=None): + self = cls(parent) + + if self._version_tag not in data: + print( "ERROR: Missing '{}' field!" . format(self._version_tag) ) + + # TODO: see VariadicRecord :: detect_type to avoid assumptions! + + v = SemanticVersion(None) + + if not v.validate('', data.get(self._version_tag)): + print( "Wrong Global '{}' specification!" . format(self._version_tag) ) + + _version = v.get_data() # there may be some default verion... + + print( "File Format is of version: '{}'" . format(_version) ) + self.set_version(_version) + + _ret = self.validate(_version, data) ## TODO: FIXME: should not need version...!? + + print( "\nValidation result: '{}'" . format(_ret) ) + + return self + + def validate(self, version, data): + _ret = BaseRecord.validate(self, version, data) + + for offset, k in enumerate(data): + if k == self._version_tag: + if offset != 0: + print("Note: '{}' specified correctly but not ahead of everything else (offset: {})!".format(self._version_tag, offset)) + _ret = False + break + + #! checks uniqueness of keys among (Services/Applications): + + _services = data.get(self._services_tag) # Rely on the above and use get_data? + _applications = data.get(self._applications_tag) + + for p, k in enumerate(_services): + (sline, scol) = _services.lc.key(k) + + if k in _applications: + print( "Error: '{}' is both a ServiceID and an ApplicationID:" . format(k) ) + key_error(k, _services[k], sline, scol, "Service key: {}") + + (aline, acol) = _applications.lc.key(k) + + key_error(k, _applications[k], aline, acol, "Application key: {}") + + #! TODO: check Uniqueness of keys among (Profiles/Stations/Groups) !!!! + # TODO: check for GroupID <-> StationID <-> ProfileID + return _ret + +############################################################### + +print( "Python Version: '{}'".format( version_info ) ) +print( "ruamel.yaml Version: '{}'".format(yaml.__version__) ) + + +if __name__ == "__main__": + usage = "{} " . format( argv[0] ) + + if len(argv[1:]) > 0: + for arg in argv[1:]: + print( "Parsing config file: '{}'".format(arg) ) + + data = load_yaml(arg) # TODO: check that this is a dictionary! + + print( "Input YAML file: " ) + print( yaml.round_trip_dump(data) ) + + + print( "\nValidation starts:\n") + hilbert_configuration = Global.parse(data) + + print( hilbert_configuration.get_data() ) + + else: + print(usage) + +else: + raise NotImplementedError("Sorry Library usage is not supported yet!") +# assert False From 7360603cdd7b660c80819365142cbac2074aa5d2 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Mon, 7 Nov 2016 18:27:20 +0100 Subject: [PATCH 02/42] Fixing first issues and extending FIX: many fixes CHG/ADD: changes and additions to the class hierarchie, e.g.: * DockerMachie variant for PowerOnMethod * expect default values for optional fields! --- config/hilbert-cli-config.py | 193 ++++++++++++++++++++++++----------- 1 file changed, 134 insertions(+), 59 deletions(-) diff --git a/config/hilbert-cli-config.py b/config/hilbert-cli-config.py index 0b1c88f..b80649b 100755 --- a/config/hilbert-cli-config.py +++ b/config/hilbert-cli-config.py @@ -206,8 +206,13 @@ def detect_type(self, version, data): assert len(self._types) > 0 return self._default_type + + def detect_extra_rule(self, version, key, value): # Any extra unlisted keys in the mapping? + return None def validate(self, version, data): + #! TODO: assert that data is a mapping with lc! + _type = self.detect_type(version, data) assert not (_type is None) @@ -217,25 +222,25 @@ def validate(self, version, data): _ret = True - c = data.lc.col - s = data.lc.line # starting line + _lc = data.lc # starting location of the mapping...? + (s, c) = (_lc.line, _lc.col) + _d = {} + for k in _rule.keys(): r = _rule[k] if r[0] and (k not in data): key_note(k, s, c, "Error: Missing key `{}` (type: '%s')" % (_type)) # Raise Exception? _ret = False + elif not r[0]: # Optional Values should have some default values! + _d[k] = r[1](self) + - _d = {} - for offset, k in enumerate(data): v = data.get(k) - l = s + offset + l = s + offset #?? - if k not in _rule: - key_error(k, v, l, c, "Warning: Unexpected/Unknown Key: '{}' (type: '%s')" % (_type)) # Raise Exception? - _ret = False - else: + if k in _rule: r = _rule[k] _d[k] = r[1](self) @@ -243,19 +248,46 @@ def validate(self, version, data): if not _d[k].validate(version, v): # TODO: save to self! value_error(k, v, l, c, "Error: invalid field '{}' value (type: '%s')" % (_type)) # Raise Exception? _ret = False + else: + _key_rule = self.detect_extra_rule(version, k, v) + + if _key_rule is None: + key_error(k, v, l, c, "Error: Unhandled Key: '{}' (type: '%s')" % (_type)) # Raise Exception? + _ret = False + else: + _d[k] = _key_rule(self) + if not _d[k].validate(version, v): # TODO: save to self! + value_error(k, v, l, c, "Error: invalid field '{}' value (type: '%s')" % (_type)) # Raise Exception? + _ret = False + self.set_data(_d) return _ret ############################################################### class BaseScalar(Base): - """Single scalar value out of YAML scalars""" + """Single scalar value out of YAML scalars: strings, numbert etc.""" def __init__(self, parent): Base.__init__(self, parent) - + def validate(self, version, data): + """check that data is a scalar: not a sequence of mapping""" + + _ret = True +# #! NOTE: test that data is non-iterable! TODO: BUG: strings are iterable :( +# try: +# for x in data: +# break +# _ret = False +# except: +# _ret = True + + self.set_data( data ) + + return _ret + ############################################################### #import semver import semantic_version # supports partial versions @@ -379,6 +411,22 @@ def validate(self, version, data): _ret = BaseString.validate(self, version, data) _ret = _ret and is_valid_id(self.get_data()) return _ret + + +############################################################### +class ClientVariable(BaseID): # + def __init__(self, parent): + BaseID.__init__(self, parent) + + def validate(self, version, data): + """check whether data is a valid ID string""" + _ret = BaseID.validate(self, version, data) + + v = self.get_data() + + _ret = _ret and ( v == v.lower() or v == v.upper() ) #! Variables are all lower or upper case! + _ret = _ret and (re.match("^hilbert(_[a-z0-9]+)+$", v.lower())) # starting with hilbert_ or HILBERT_ with letters, digits and '_' + return _ret ############################################################### class ServiceID(BaseID): @@ -459,7 +507,23 @@ def validate(self, version, data): return _ret ############################################################### -class HostAddress(BaseString): # ! BaseString, SSH alias +class HostAddress(BaseString): + """SSH alias""" + + def __init__(self, parent): + BaseString.__init__(self, parent) + + def validate(self, version, data): + """check whether data is a valid ssh alias?""" + + _ret = BaseString.validate(self, version, data) + + #! TODO: Check for ssh alias! + return _ret + +class HostMACAddress(BaseString): + """MAC Address of the station""" + def __init__(self, parent): BaseString.__init__(self, parent) @@ -468,7 +532,13 @@ def validate(self, version, data): _ret = BaseString.validate(self, version, data) - # TODO: Check for ssh alias! + v = self.get_data() + + #! TODO: Check for MAC Address? + if not re.match("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", v.lower()): + print ( "Wrong MAC Address: [{}]" . format(data) ) + _ret = False + return _ret ############################################################### @@ -492,13 +562,13 @@ def __init__(self, parent): self._default_data = False -class AutoTurnon(BaseBool): # Bool, True +class AutoTurnon(BaseBool): # Bool, False def __init__(self, parent): BaseBool.__init__(self, parent) - self._default_data = True + self._default_data = False # no powering on by default!? ############################################################### -class VariadicRecord(BaseRecord): +class VariadicRecord(BaseRecord): # will need BaseRecord.validate! """Variadic record. Type is determined by the given 'type' field.""" def __init__(self, parent): @@ -518,23 +588,20 @@ def detect_type(self, version, data): _rule = self._types[self._default_type][self._type_tag] - if _rule[0] and (self._type_tag not in data): - try: - (l, c) = data.lc # start of the current mapping - except: - print ("WRONG DATA: ") - print (data) - raise ConfigurationError(u"{}: {}".format("mapping data without line/column!!!", 'some VariadicRecord')) - + if _rule[0] and (self._type_tag not in data): + _lc = data.lc # start of the current mapping + (l, c) = (_lc.line, _lc.col) - key_error(self._type_tag, l, c, "Missing mandatory key `{}`" % (_type)) # Raise Exception? + key_note(self._type_tag, l, c, "Error: Missing mandatory key `{}`") # Raise Exception? return None t = data.get(self._type_tag, self._default_type) tt = _rule[1](self) if not tt.validate(version, t): - (l, c) = data.lc.key(self._type_tag) + _lc = data.lc.key(self._type_tag) + (l, c) = _lc # (_lc.line, _lc.col) + value_error(self._type_tag, t, l, c, "invalid value '{}'") # Raise Exception? return None @@ -551,12 +618,19 @@ def __init__(self, parent): self._default_type = "WOL" # ServiceType("compose")? WOL_rule = { - self._type_tag: (True, StationPowerOnMethodType), # Mandatory? + self._type_tag: (True, StationPowerOnMethodType), # Mandatory! "auto_turnon": (False, AutoTurnon), "mac": (True, HostMACAddress) } - self._types = { self._default_type: WOL_rule } + DM_rule = { + self._type_tag: (True, StationPowerOnMethodType), # Mandatory! + "auto_turnon": (False, AutoTurnon), + "vm_name": (True, BaseString), + "vm_host_address": (True, HostAddress) + } + + self._types = { self._default_type: WOL_rule, "DockerMachine": DM_rule } #! NOTE: AMT - maybe later... ############################################################### class Service(VariadicRecord): @@ -709,8 +783,8 @@ def validate(self, version, data): _ret = True - c = data.lc.col - s = data.lc.line # starting line + _lc = data.lc # starting position? + (s, c) = (_lc.line, _lc.col) _d = {} for offset, k in enumerate(data): @@ -746,12 +820,13 @@ def __init__(self, parent): # return _ret + ############################################################### class StationClientSettings(BaseIDMap): # "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) def __init__(self, parent): BaseIDMap.__init__(self, parent) self._default_type = "default_station_client_settings" - self._types = { self._default_type: (BaseID, BaseString) } + self._types = { self._default_type: (ClientVariable, BaseScalar) } #! TODO: only strings for now! More scalar types?! ############################################################### class GlobalApplications(BaseIDMap): @@ -825,7 +900,7 @@ def validate(self, version, data): _type = self.detect_type(version, data) assert _type is not None - lc = data.lc + _lc = data.lc if not issequenceforme(data): data = [data] @@ -836,7 +911,7 @@ def validate(self, version, data): for idx, i in enumerate(data): _v = _type(self) if not _v.validate(version, i): - # TODO: error # show lc + # TODO: error # show _lc print( "Error insequence at {}" . format(idx) ) _ret = False else: @@ -845,15 +920,6 @@ def validate(self, version, data): self.set_data(_d) return _ret -############################################################### -class GroupIDList(BaseList): - """List of GroupIDs or a single GroupID!""" - - def __init__(self, parent): - BaseList.__init__(self, parent) - - self._default_type = "default_GroupID_list" - self._types = { self._default_type: GroupID } ############################################################### class ServiceList(BaseList): @@ -865,6 +931,16 @@ def __init__(self, parent): self._default_type = "default_ServiceID_list" self._types = { self._default_type: ServiceID } +############################################################### +class GroupIDList(BaseList): + """List of GroupIDs or a single GroupID!""" + + def __init__(self, parent): + BaseList.__init__(self, parent) + + self._default_type = "default_GroupID_list" + self._types = { self._default_type: GroupID } + ############################################################### class Group(BaseRecord): #? TODO: GroupSet & its .parent? """Group""" @@ -874,9 +950,9 @@ def __init__(self, parent): self._default_type = "default_group" - self._include_tag = "include" - self._exclude_tag = "exclude" - self._intersectWith_tag = "intersectWith" + self._include_tag = "include" + self._exclude_tag = "exclude" + self._intersectWith_tag = "intersectWith" default_rule = { self._include_tag: (False, GroupIDList), @@ -885,19 +961,18 @@ def __init__(self, parent): "name": (False, BaseUIString), "description": (False, BaseUIString), "icon": (False, Icon) - } self._types = { self._default_type: default_rule } - def validate(self, version, data): - _lc = data.lc - - ### TODO: preprocess set entries: GroupIDs from d - d = data # deep copy? - - _ret = BaseRecord.validate(self, version, d) + def detect_extra_rule(self, version, key, value): # Any extra unlisted keys in the mapping? + if value is None: # Set item! + return GroupID + return None + def validate(self, version, data): + _ret = BaseRecord.validate(self, version, data) + # Add extra keys into include? return _ret ############################################################### @@ -1009,13 +1084,15 @@ def validate(self, version, data): _applications = data.get(self._applications_tag) for p, k in enumerate(_services): - (sline, scol) = _services.lc.key(k) + _lc = _services.lc.key(k) + (sline, scol) = _lc # (_lc.line, _lc.col) if k in _applications: print( "Error: '{}' is both a ServiceID and an ApplicationID:" . format(k) ) key_error(k, _services[k], sline, scol, "Service key: {}") - (aline, acol) = _applications.lc.key(k) + _alc = _applications.lc.key(k) + (aline, acol) = _alc # (_alc.line, _alc.col) key_error(k, _applications[k], aline, acol, "Application key: {}") @@ -1028,7 +1105,6 @@ def validate(self, version, data): print( "Python Version: '{}'".format( version_info ) ) print( "ruamel.yaml Version: '{}'".format(yaml.__version__) ) - if __name__ == "__main__": usage = "{} " . format( argv[0] ) @@ -1041,7 +1117,6 @@ def validate(self, version, data): print( "Input YAML file: " ) print( yaml.round_trip_dump(data) ) - print( "\nValidation starts:\n") hilbert_configuration = Global.parse(data) @@ -1050,6 +1125,6 @@ def validate(self, version, data): else: print(usage) -else: - raise NotImplementedError("Sorry Library usage is not supported yet!") +#else: +# raise NotImplementedError("Sorry Library usage is not supported yet!") # assert False From 711b1000a5ce44c70be8af5eb22677c3b83c7166 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Mon, 7 Nov 2016 18:54:25 +0100 Subject: [PATCH 03/42] Added `supported_types` field to `Profile` NOTE: due to @porst17's comment https://github.com/hilbert/hilbert-cli/issues/32#issuecomment-258899081 ADD: minor comments (TODOs for later) --- config/hilbert-cli-config.py | 29 ++++++++++++++++++++++------- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/config/hilbert-cli-config.py b/config/hilbert-cli-config.py index b80649b..0ffebb2 100755 --- a/config/hilbert-cli-config.py +++ b/config/hilbert-cli-config.py @@ -7,9 +7,10 @@ ############################################################### up_arrow = '↑' + def key_error(key, value, line, col, error_message, e='K'): print('{}[line: {}, column: {}]: {}'.format(e, line+1, col+1, error_message.format(key))) - print('{}{}: {}'.format(' '*col, key, value)) + print('{}{}: {}'.format(' '*col, key, value)) #! TODO: try to get access to original ruamel.yaml buffered lines...? print('{}{}'.format(' '*(col), up_arrow)) print('---') @@ -22,7 +23,7 @@ def key_note(key, line, col, key_message, e='K'): def value_error(key, value, line, col, error, e='E'): val_col = col + len(key) + 2 print('{}[line: {}, column: {}]: {}'.format(e, line+1, val_col+1, error . format(key))) - print('{}{}: {}'.format(' '*col, key, value)) + print('{}{}: {}'.format(' '*col, key, value)) #! TODO: try to get access to original ruamel.yaml buffered lines...? print('{}{}'.format(' '*(val_col), up_arrow)) print('---') @@ -669,7 +670,7 @@ def __init__(self, parent): self._default_type = "compose" # ServiceType("compose")? - compose_rule = { + compose_rule = { #! NOTE: duplicates the definition of a Service! TODO: Extension? self._type_tag: (True, ServiceType), # Mandatory self._hook_tag: (False, AutoDetectionScript), self._name_tag: (True, DockerComposeServiceName), @@ -695,7 +696,8 @@ def __init__(self, parent): "name": (True, BaseUIString), "description": (True, BaseUIString), "icon": (False, Icon), - "services": (True, ServiceList) + "services": (True, ServiceList), + "supported_types": (False, ServiceTypeList) } self._types = { self._default_type: default_rule } @@ -902,13 +904,15 @@ def validate(self, version, data): _lc = data.lc - if not issequenceforme(data): - data = [data] +# #! TODO: FIXME: BUG: String is a sequence! +# if not issequenceforme(data): #! Check for alist or dictionary? +# data = [data] # NOTE: will have no lc! +# data.lc = _lc #??? _d = [] _ret = True - for idx, i in enumerate(data): + for idx, i in enumerate(data): # What about a string? _v = _type(self) if not _v.validate(version, i): # TODO: error # show _lc @@ -940,6 +944,17 @@ def __init__(self, parent): self._default_type = "default_GroupID_list" self._types = { self._default_type: GroupID } + +############################################################### +class ServiceTypeList(BaseList): + """List of ServiceType's or a single ServiceType!""" + + def __init__(self, parent): + BaseList.__init__(self, parent) + + self._default_type = "default_ServiceType_list" + self._types = { self._default_type: ServiceType } + ############################################################### class Group(BaseRecord): #? TODO: GroupSet & its .parent? From f9559e6842e8de3fc1fb913835b8b668e30b739d Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Tue, 8 Nov 2016 01:54:43 +0100 Subject: [PATCH 04/42] Improved detection of parsed YAML data types, e.g. in GroupList, BaseScalar and BaseString CHG: only keep the processed data is there was no error TODO: check that every validator follows this! REN: Abstract -> AbstractValidator --- config/hilbert-cli-config.py | 160 +++++++++++++++++++---------------- 1 file changed, 86 insertions(+), 74 deletions(-) diff --git a/config/hilbert-cli-config.py b/config/hilbert-cli-config.py index 0ffebb2..63f8b53 100755 --- a/config/hilbert-cli-config.py +++ b/config/hilbert-cli-config.py @@ -102,24 +102,24 @@ def load_yaml(filename): raise ConfigurationError(u"{}: {}".format(error_name, e)) ############################################################### -from ruamel.yaml.compat import PY2, PY3, text_type +from ruamel.yaml.compat import PY2, PY3, text_type, string_types from abc import * if PY3 and (version_info[1] >= 4): - class Abstract(ABC): + class AbstractValidator(ABC): """Abstract Base class for any concrete implementation of entities appearing in the general configuration file""" @abstractmethod def validate(self, data): pass elif PY2 or PY3: - class Abstract: + class AbstractValidator: """Abstract Base class for any concrete implementation of entities appearing in the general configuration file""" __metaclass__ = ABCMeta @abstractmethod def validate(self, data): pass #elif PY3: -# class Abstract(metaclass=ABCMeta): +# class AbstractValidator(metaclass=ABCMeta): # """Abstract Base class for any concrete implementation of entities appearing in the general configuration file""" # @abstractmethod # def validate(self, data): @@ -128,15 +128,15 @@ def validate(self, data): raise NotImplementedError("Unsupported Python version: '{}'".format(version_info)) ############################################################### -class Base(Abstract): - """Actual Base Class for the Config entities""" +class Base(AbstractValidator): + """Abstract Base Class for the Config entities""" __version = [None] _data = None _parent = None def __init__(self, parent): - Abstract.__init__(self) + AbstractValidator.__init__(self) assert self._parent is None self._parent = parent @@ -250,19 +250,27 @@ def validate(self, version, data): value_error(k, v, l, c, "Error: invalid field '{}' value (type: '%s')" % (_type)) # Raise Exception? _ret = False else: - _key_rule = self.detect_extra_rule(version, k, v) + _extra_rule = self.detect_extra_rule(version, k, v) # (KeyValidator, ValueValidator) - if _key_rule is None: + if _extra_rule is None: key_error(k, v, l, c, "Error: Unhandled Key: '{}' (type: '%s')" % (_type)) # Raise Exception? _ret = False - else: - _d[k] = _key_rule(self) + else: + _k = _extra_rule[0](self) - if not _d[k].validate(version, v): # TODO: save to self! - value_error(k, v, l, c, "Error: invalid field '{}' value (type: '%s')" % (_type)) # Raise Exception? - _ret = False - - self.set_data(_d) + if not _k.validate(version, k): + key_error(k, v, l, c, "Error: invalid key '{}' value (type: '%s')" % (_type)) # Raise Exception? + _ret = False + else: + _v = _extra_rule[1](self) + if not _v.validate(version, v): #! TODO: FIXME: wrong col (it was for key - not value)! + value_error(k, v, l, c, "Error: invalid field value '{}' value (type: '%s')" % (_type)) # Raise Exception? + _ret = False + else: + _d[_k] = _v + + if _ret: + self.set_data(_d) return _ret @@ -275,56 +283,51 @@ def __init__(self, parent): def validate(self, version, data): """check that data is a scalar: not a sequence of mapping""" - - _ret = True -# #! NOTE: test that data is non-iterable! TODO: BUG: strings are iterable :( -# try: -# for x in data: -# break -# _ret = False -# except: -# _ret = True - + + _ret = not isinstance(data, (list, dict, tuple, set)) #! Check if data is not a container? + self.set_data( data ) return _ret ############################################################### -#import semver -import semantic_version # supports partial versions - -class SemanticVersion(BaseScalar): +class BaseString(BaseScalar): def __init__(self, parent): BaseScalar.__init__(self, parent) def validate(self, version, data): - """check the string data to be a valid semantic verions""" - - if version == '': # the only initial validation: may be a partial version - self._data = semantic_version.Version(data, partial=True) #!? + """check whether data is a valid string""" + ### TODO: Detect other YAML scalar types? + + if isinstance(data, string_types): + self.set_data( text_type(data) ) return True + + return False -# try: - self.set_data( semantic_version.validate(data) ) - return True -# except: -# return False ############################################################### -class BaseString(BaseScalar): +#import semver +import semantic_version # supports partial versions + +class SemanticVersion(BaseString): def __init__(self, parent): - BaseScalar.__init__(self, parent) + BaseString.__init__(self, parent) def validate(self, version, data): - """check whether data is a valid string""" - ### TODO: Detect other YAML scalar types? + """check the string data to be a valid semantic verions""" + try: - self.set_data( text_type(data) ) + _v = None + if version == '': # the only initial validation: may be a partial version + _v = semantic_version.Version(data, partial=True) + else: + _v = semantic_version.validate(data) + + self.set_data( _v ) return True - except: - print( "ERROR: Cannot conver '{}' into string!" % format(data) ) - self.set_data( data ) - + except: + return False ############################################################### class BaseUIString(BaseString): # visible to user => non empty! @@ -893,7 +896,7 @@ def __init__(self, parent): def detect_type(self, version, data): """determine the class of items based on the version and sample data""" - assert not (self._default_type is None) + assert self._default_type is not None assert len(self._types) > 0 return self._types[self._default_type] @@ -902,48 +905,55 @@ def validate(self, version, data): _type = self.detect_type(version, data) assert _type is not None - _lc = data.lc - -# #! TODO: FIXME: BUG: String is a sequence! -# if not issequenceforme(data): #! Check for alist or dictionary? -# data = [data] # NOTE: will have no lc! -# data.lc = _lc #??? - + _ret = True + _d = [] - _ret = True - for idx, i in enumerate(data): # What about a string? + if not isinstance(data, (list, tuple, dict, set)): #! data is Scalar? _v = _type(self) - if not _v.validate(version, i): - # TODO: error # show _lc - print( "Error insequence at {}" . format(idx) ) + + if not _v.validate(version, data): + print( "Error: Wrong entity: {}" . format(data) ) # use _lc!? _ret = False else: - _d.insert(idx, _v) # append? + _d.append(_v) + else: # list!? + _lc = data.lc + + for idx, i in enumerate(data): # What about a string? + _v = _type(self) + if not _v.validate(version, i): + # TODO: error # show _lc + print( "Error insequence at {}" . format(idx) ) + _ret = False + else: + _d.insert(idx, _v) # append? + + if _ret: + self.set_data(_d) - self.set_data(_d) return _ret - ############################################################### -class ServiceList(BaseList): - """List of ServiceIDs or a single ServiceID!""" +class GroupIDList(BaseList): + """List of GroupIDs or a single GroupID!""" def __init__(self, parent): BaseList.__init__(self, parent) - self._default_type = "default_ServiceID_list" - self._types = { self._default_type: ServiceID } + self._default_type = "default_GroupID_list" + self._types = { self._default_type: GroupID } ############################################################### -class GroupIDList(BaseList): - """List of GroupIDs or a single GroupID!""" +class ServiceList(BaseList): + """List of ServiceIDs or a single ServiceID!""" def __init__(self, parent): BaseList.__init__(self, parent) - self._default_type = "default_GroupID_list" - self._types = { self._default_type: GroupID } + self._default_type = "default_ServiceID_list" + self._types = { self._default_type: ServiceID } + ############################################################### class ServiceTypeList(BaseList): @@ -982,7 +992,7 @@ def __init__(self, parent): def detect_extra_rule(self, version, key, value): # Any extra unlisted keys in the mapping? if value is None: # Set item! - return GroupID + return (GroupID, BaseScalar) return None def validate(self, version, data): @@ -1058,6 +1068,8 @@ def __init__(self, parent): self._types = { self._default_type: default_rule } + self._default_data = None + @classmethod def parse(cls, data, parent=None): self = cls(parent) @@ -1080,7 +1092,6 @@ def parse(cls, data, parent=None): _ret = self.validate(_version, data) ## TODO: FIXME: should not need version...!? print( "\nValidation result: '{}'" . format(_ret) ) - return self def validate(self, version, data): @@ -1135,6 +1146,7 @@ def validate(self, version, data): print( "\nValidation starts:\n") hilbert_configuration = Global.parse(data) + print( hilbert_configuration.get_data() ) else: From 2b5c8ed8b90713cf93af8a6a1e543d6acc46945d Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Tue, 8 Nov 2016 03:46:53 +0100 Subject: [PATCH 05/42] Updated the ConfigurationDD due to feedback --- docs/ConfigurationDD.png | Bin 116550 -> 121394 bytes docs/ConfigurationDD.xml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ConfigurationDD.png b/docs/ConfigurationDD.png index f03b0b7c80a04292d9448244c273e9a5d91f9763..f2e840ab80e40565dbcc461707a5af08c28e8cdd 100644 GIT binary patch literal 121394 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%0D$|s#y6I@$9Ub`Fm@>J@H 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 L%=IgD9b^6v7$KVl literal 116550 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 diff --git a/docs/ConfigurationDD.xml b/docs/ConfigurationDD.xml index d63a7a9..d2a13bd 100644 --- a/docs/ConfigurationDD.xml +++ b/docs/ConfigurationDD.xml @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file From 07f6af3054e7f94cc3da8ec0eb3fce0c58eb79bf Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Tue, 15 Nov 2016 03:53:59 +0100 Subject: [PATCH 06/42] Accamulated update of config/hilbert-cli-config.py + infrastructure Changed API: version is implicitly globally available, use of classmethod: `Validator.parse(input, parent=...)` Filled in Validators with actual checks (URI verification, ssh alias, docker-compose config etc) Added CLI with subcommands to hilbert-cli-config.py (arghandler & argparse) Added pickling with `dill/pickle` NOTE: all validators can be tested separately now! Infrastructure: Added unit-tests using py.test Added `Makefile check` to run unit-tests Added doxygen/epydoc/pylint/pep8 execution to the Makefile --- Doxyfile | 240 +++++ Makefile | 32 + config/__init__.py | 6 + config/hilbert-cli-config.py | 1955 +++++++++++++++++++++++----------- config/hilbert_cli_config.py | 1 + config/tests/__init__.py | 14 + config/tests/test_version.py | 38 + tox.ini | 14 + 8 files changed, 1649 insertions(+), 651 deletions(-) create mode 100644 Doxyfile create mode 100644 Makefile create mode 100644 config/__init__.py create mode 120000 config/hilbert_cli_config.py create mode 100644 config/tests/__init__.py create mode 100644 config/tests/test_version.py create mode 100644 tox.ini diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 0000000..d414da4 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,240 @@ +USE_MDFILE_AS_MAINPAGE = +DOXYFILE_ENCODING = UTF-8 +PROJECT_NAME = hilbert-cli-config +PROJECT_NUMBER = 0.0.1 +PROJECT_BRIEF = "Hilbert CLI Config" +PROJECT_LOGO = +OUTPUT_DIRECTORY = doxydoc +CREATE_SUBDIRS = NO +OUTPUT_LANGUAGE = English +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ABBREVIATE_BRIEF = +ALWAYS_DETAILED_SEC = NO +INLINE_INHERITED_MEMB = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = +STRIP_FROM_INC_PATH = +SHORT_NAMES = NO +JAVADOC_AUTOBRIEF = YES +QT_AUTOBRIEF = NO +MULTILINE_CPP_IS_BRIEF = YES +INHERIT_DOCS = YES +SEPARATE_MEMBER_PAGES = NO +TAB_SIZE = 4 +ALIASES = +TCL_SUBST = +OPTIMIZE_OUTPUT_FOR_C = NO +OPTIMIZE_OUTPUT_JAVA = YES +OPTIMIZE_FOR_FORTRAN = NO +OPTIMIZE_OUTPUT_VHDL = NO +EXTENSION_MAPPING = +MARKDOWN_SUPPORT = YES +BUILTIN_STL_SUPPORT = NO +CPP_CLI_SUPPORT = NO +SIP_SUPPORT = NO +IDL_PROPERTY_SUPPORT = YES +DISTRIBUTE_GROUP_DOC = NO +SUBGROUPING = YES +INLINE_GROUPED_CLASSES = NO +INLINE_SIMPLE_STRUCTS = NO +TYPEDEF_HIDES_STRUCT = NO +SYMBOL_CACHE_SIZE = 0 +LOOKUP_CACHE_SIZE = 0 +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_PACKAGE = NO +EXTRACT_STATIC = YES +EXTRACT_LOCAL_CLASSES = NO +EXTRACT_LOCAL_METHODS = NO +EXTRACT_ANON_NSPACES = NO +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +HIDE_FRIEND_COMPOUNDS = NO +HIDE_IN_BODY_DOCS = NO +INTERNAL_DOCS = NO +CASE_SENSE_NAMES = NO +HIDE_SCOPE_NAMES = NO +SHOW_INCLUDE_FILES = YES +FORCE_LOCAL_INCLUDES = NO +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +SORT_BRIEF_DOCS = NO +SORT_MEMBERS_CTORS_1ST = NO +SORT_GROUP_NAMES = NO +SORT_BY_SCOPE_NAME = NO +STRICT_PROTO_MATCHING = NO +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +GENERATE_DEPRECATEDLIST= YES +ENABLED_SECTIONS = +MAX_INITIALIZER_LINES = 30 +SHOW_USED_FILES = YES +SHOW_FILES = YES +SHOW_NAMESPACES = YES +FILE_VERSION_FILTER = +LAYOUT_FILE = +CITE_BIB_FILES = +QUIET = NO +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_IF_DOC_ERROR = YES +WARN_NO_PARAMDOC = NO +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = +INPUT = config +INPUT_ENCODING = UTF-8 +FILE_PATTERNS = "*.py" "*.md" +RECURSIVE = YES +EXCLUDE = +EXCLUDE_SYMLINKS = NO +EXCLUDE_PATTERNS = +EXCLUDE_SYMBOLS = +EXAMPLE_PATH = scripts +EXAMPLE_PATTERNS = +EXAMPLE_RECURSIVE = NO +IMAGE_PATH = +INPUT_FILTER = doxypy +FILTER_PATTERNS = +FILTER_SOURCE_FILES = YES +FILTER_SOURCE_PATTERNS = +SOURCE_BROWSER = NO +INLINE_SOURCES = NO +STRIP_CODE_COMMENTS = YES +REFERENCED_BY_RELATION = NO +REFERENCES_RELATION = NO +REFERENCES_LINK_SOURCE = YES +USE_HTAGS = NO +VERBATIM_HEADERS = YES +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 5 +IGNORE_PREFIX = +GENERATE_HTML = YES +HTML_OUTPUT = html +HTML_FILE_EXTENSION = .html +HTML_HEADER = +HTML_FOOTER = +HTML_STYLESHEET = +HTML_EXTRA_FILES = +HTML_COLORSTYLE_HUE = 220 +HTML_COLORSTYLE_SAT = 100 +HTML_COLORSTYLE_GAMMA = 80 +HTML_TIMESTAMP = YES +HTML_DYNAMIC_SECTIONS = NO +HTML_INDEX_NUM_ENTRIES = 100 +GENERATE_DOCSET = NO +DOCSET_FEEDNAME = "Doxygen generated docs" +DOCSET_BUNDLE_ID = org.doxygen.Project +DOCSET_PUBLISHER_ID = org.doxygen.Publisher +DOCSET_PUBLISHER_NAME = Publisher +GENERATE_HTMLHELP = NO +CHM_FILE = +HHC_LOCATION = +GENERATE_CHI = NO +CHM_INDEX_ENCODING = +BINARY_TOC = NO +TOC_EXPAND = NO +GENERATE_QHP = NO +QCH_FILE = +QHP_NAMESPACE = org.doxygen.Project +QHP_VIRTUAL_FOLDER = doc +QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = +QHG_LOCATION = +GENERATE_ECLIPSEHELP = NO +ECLIPSE_DOC_ID = org.doxygen.Project +DISABLE_INDEX = NO +GENERATE_TREEVIEW = YES +ENUM_VALUES_PER_LINE = 4 +TREEVIEW_WIDTH = 250 +EXT_LINKS_IN_WINDOW = NO +FORMULA_FONTSIZE = 10 +FORMULA_TRANSPARENT = YES +USE_MATHJAX = NO +MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest +MATHJAX_EXTENSIONS = +SEARCHENGINE = YES +SERVER_BASED_SEARCH = NO +GENERATE_LATEX = NO +LATEX_OUTPUT = latex +LATEX_CMD_NAME = latex +MAKEINDEX_CMD_NAME = makeindex +COMPACT_LATEX = NO +PAPER_TYPE = a4 +EXTRA_PACKAGES = +LATEX_HEADER = +LATEX_FOOTER = +PDF_HYPERLINKS = YES +USE_PDFLATEX = YES +LATEX_BATCHMODE = NO +LATEX_HIDE_INDICES = NO +LATEX_SOURCE_CODE = NO +LATEX_BIB_STYLE = plain +GENERATE_RTF = NO +RTF_OUTPUT = rtf +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +RTF_EXTENSIONS_FILE = +GENERATE_MAN = NO +MAN_OUTPUT = man +MAN_EXTENSION = .3 +MAN_LINKS = NO +GENERATE_XML = NO +XML_OUTPUT = xml +XML_SCHEMA = +XML_DTD = +XML_PROGRAMLISTING = YES +GENERATE_AUTOGEN_DEF = NO +GENERATE_PERLMOD = NO +PERLMOD_LATEX = NO +PERLMOD_PRETTY = YES +PERLMOD_MAKEVAR_PREFIX = +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = NO +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +SKIP_FUNCTION_MACROS = YES +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +EXTERNAL_GROUPS = YES +PERL_PATH = /usr/bin/perl +CLASS_DIAGRAMS = YES +MSCGEN_PATH = +HIDE_UNDOC_RELATIONS = NO +HAVE_DOT = YES +DOT_NUM_THREADS = 0 +DOT_FONTNAME = Helvetica +DOT_FONTSIZE = 10 +DOT_FONTPATH = +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +GROUP_GRAPHS = YES +UML_LOOK = NO +UML_LIMIT_NUM_FIELDS = 10 +TEMPLATE_RELATIONS = NO +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +CALL_GRAPH = YES +CALLER_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DIRECTORY_GRAPH = YES +DOT_IMAGE_FORMAT = png +INTERACTIVE_SVG = NO +DOT_PATH = dot +DOTFILE_DIRS = +MSCFILE_DIRS = +DOT_GRAPH_MAX_NODES = 50 +MAX_DOT_GRAPH_DEPTH = 0 +DOT_TRANSPARENT = NO +DOT_MULTI_TARGETS = NO +GENERATE_LEGEND = YES +DOT_CLEANUP = YES + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..464cc94 --- /dev/null +++ b/Makefile @@ -0,0 +1,32 @@ +## ---------------------------------------------- [ Makefile for Python Checks ] + +# Simple Makefile used during development to check compliance with +# pep8 and to generate documentation + +SRC=config/hilbert-cli-config.py +NAME=hilbert-cli-config + +.PHONY: usage pep8 apidocs clean pylint install build + +usage: # Print Targets + @grep '^[^#[:space:]].*:' Makefile + +check: # Run the tests + /bin/bash -c 'cd config/tests/ && py.test -v test_*.py' + /bin/bash -c 'cd config/tests/ && py.test-3 -v test_*.py' + +pep8: ${SRC} # Check for PEP8 compliance + pep8 --first --show-source --show-pep8 ${SRC} + +pylint: # Analyse Source + pylint -f html --files-output=y ${SRC} + +apidocs: ${SRC} # Build API Documentation with doxygen + doxygen Doxyfile + +epydoc: ${SRC} # Build API Documentation with epydoc + epydoc --html --inheritance=listed --graph=all ${SRC} + +clean: # Clean Project + rm -rf doxydoc *~ +# python3 distribute_setup.py clean diff --git a/config/__init__.py b/config/__init__.py new file mode 100644 index 0000000..77541cd --- /dev/null +++ b/config/__init__.py @@ -0,0 +1,6 @@ +from __future__ import absolute_import +from __future__ import unicode_literals + +__version__ = '0.2.0-dev' + +from .hilbert_cli_config import * diff --git a/config/hilbert-cli-config.py b/config/hilbert-cli-config.py index 63f8b53..5270f95 100755 --- a/config/hilbert-cli-config.py +++ b/config/hilbert-cli-config.py @@ -1,61 +1,111 @@ -#! /usr/bin/env python3 -# coding: utf-8 +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- # encoding: utf-8 +# coding: utf-8 -from sys import argv, version_info +from __future__ import absolute_import, print_function, unicode_literals + +PEDANTIC = False # NOTE: to treat invalid values/keys as errors? +INPUT_DIRNAME = './' +OUTPUT_DIRNAME = INPUT_DIRNAME ############################################################### up_arrow = '↑' -def key_error(key, value, line, col, error_message, e='K'): - print('{}[line: {}, column: {}]: {}'.format(e, line+1, col+1, error_message.format(key))) - print('{}{}: {}'.format(' '*col, key, value)) #! TODO: try to get access to original ruamel.yaml buffered lines...? - print('{}{}'.format(' '*(col), up_arrow)) +def _get_line_col(lc): + + if isinstance(lc, (list, tuple)): + l = lc[0] + c = lc[1] + else: + try: + l = lc.line + except: + print("Unexpected error: ", sys.exc_info()[0]) + print("Cannot get line out of: ", lc) + raise + + try: + c = lc.col + except: + try: + c = lc.column + except: + print("Unexpected error: ", sys.exc_info()[0]) + print("Cannot get col/column out of: ", lc) + raise + + return l, c + +def key_error(key, value, lc, error_message, e='K'): + (line, col) = _get_line_col(lc) + + if key is None: + key = '*' + + print('{}[line: {}, column: {}]: {}'.format(e, line + 1, col + 1, error_message.format(key))) + print('{}{}: {}'.format(' ' * col, key, value)) #! + # ! TODO: try to get access to original ruamel.yaml buffered lines...? + print('{}{}'.format(' ' * col, up_arrow)) print('---') -def key_note(key, line, col, key_message, e='K'): - print('{}[line: {}, column: {}]: {}'.format(e, line+1, col+1, key_message.format(key))) +def key_note(key, lc, key_message, e='K'): + (line, col) = _get_line_col(lc) + + if key is None: + key = '*' + + print('{}[line: {}, column: {}]: {}'.format(e, line + 1, col + 1, key_message.format(key))) print('---') - - -def value_error(key, value, line, col, error, e='E'): + + +def value_error(key, value, lc, error, e='E'): + (line, col) = _get_line_col(lc) + + if key is None: + key = '*' + val_col = col + len(key) + 2 - print('{}[line: {}, column: {}]: {}'.format(e, line+1, val_col+1, error . format(key))) - print('{}{}: {}'.format(' '*col, key, value)) #! TODO: try to get access to original ruamel.yaml buffered lines...? - print('{}{}'.format(' '*(val_col), up_arrow)) + print('{}[line: {}, column: {}]: {}'.format(e, line + 1, val_col + 1, error.format(key))) + print('{}{}: {}'.format(' ' * col, key, value)) #! + # ! TODO: try to get access to original ruamel.yaml buffered lines...? + print('{}{}'.format(' ' * val_col, up_arrow)) print('---') -def value_warning(key, value, line, col, error): - value_error(key, value, line, col, error, e='W') - +# Unused??? +# def value_warning(key, value, lc, error): +# value_error(key, value, lc, error, e='W') + + ############################################################### import collections import ruamel.yaml as yaml from ruamel.yaml.reader import Reader -from ruamel.yaml.scanner import RoundTripScanner # Scanner -from ruamel.yaml.parser import RoundTripParser # Parser, +from ruamel.yaml.scanner import RoundTripScanner # Scanner +from ruamel.yaml.parser import RoundTripParser # Parser, from ruamel.yaml.composer import Composer -from ruamel.yaml.constructor import RoundTripConstructor # Constructor, SafeConstructor, -from ruamel.yaml.resolver import VersionedResolver # Resolver, -from ruamel.yaml.nodes import MappingNode +from ruamel.yaml.constructor import RoundTripConstructor # Constructor, SafeConstructor, +from ruamel.yaml.resolver import VersionedResolver # Resolver, +# from ruamel.yaml.nodes import MappingNode + ############################################################### class VerboseRoundTripConstructor(RoundTripConstructor): - def construct_mapping(self, node, deep=False): - - m = RoundTripConstructor.construct_mapping(self, node, deep) # the actual construction! + def construct_mapping(self, node, maptyp, deep=False): + + m = RoundTripConstructor.construct_mapping(self, node, maptyp, deep=deep) # the actual construction! # additionally go through all nodes in the mapping to detect overwrites: - - starts = {} # already processed keys + locations and values - + + starts = {} # already processed keys + locations and values + for key_node, value_node in node.value: # keys can be list -> deep key = self.construct_object(key_node, deep=True) - + # lists are not hashable, but tuples are if not isinstance(key, collections.Hashable): if isinstance(key, list): @@ -63,21 +113,23 @@ def construct_mapping(self, node, deep=False): value = self.construct_object(value_node, deep=deep) # TODO: check the lines above in the original Constructor.construct_mapping code for any changes/updates - - if key in starts: # Duplication detection + + if key in starts: # Duplication detection old = starts[key] - print( "WARNING: Key re-definition within some mapping: " ) # mapping details? - key_error( key, old[1], old[0].line, old[0].column, "Previous Value: " ) - key_error( key, value, key_node.start_mark.line, key_node.start_mark.column, "New Value: ") + + print("WARNING: Key re-definition within some mapping: ") # mapping details? + key_error(key, old[1], old[0], "Previous Value: ") + key_error(key, value, key_node.start_mark, "New Value: ") print('===') - - starts[key] = (key_node.start_mark, value) # in order to find all such problems! - + + starts[key] = (key_node.start_mark, value) # in order to find all such problems! + return m + ############################################################### class VerboseRoundTripLoader(Reader, RoundTripScanner, RoundTripParser, Composer, - VerboseRoundTripConstructor, VersionedResolver): + VerboseRoundTripConstructor, VersionedResolver): def __init__(self, stream, version=None, preserve_quotes=None): Reader.__init__(self, stream) RoundTripScanner.__init__(self) @@ -86,1072 +138,1673 @@ def __init__(self, stream, version=None, preserve_quotes=None): VerboseRoundTripConstructor.__init__(self, preserve_quotes=preserve_quotes) VersionedResolver.__init__(self, version) + ############################################################### class ConfigurationError(Exception): def __init__(self, msg): self._msg = msg - + ############################################################### -def load_yaml(filename): +def load_yaml(f, Loader=VerboseRoundTripLoader, version=(1, 2), preserve_quotes=True): try: - with open(filename, 'r') as fh: - return yaml.load(fh, Loader = VerboseRoundTripLoader, version = (1, 2), preserve_quotes=True) - + return yaml.load(f, Loader=Loader, version=version, preserve_quotes=preserve_quotes) except (IOError, yaml.YAMLError) as e: error_name = getattr(e, '__module__', '') + '.' + e.__class__.__name__ raise ConfigurationError(u"{}: {}".format(error_name, e)) - + + +def load_yaml_file(filename): + with open(filename, 'r') as fh: + return load_yaml(fh) + + ############################################################### from ruamel.yaml.compat import PY2, PY3, text_type, string_types from abc import * +import sys -if PY3 and (version_info[1] >= 4): +if PY3 and (sys.version_info[1] >= 4): class AbstractValidator(ABC): - """Abstract Base class for any concrete implementation of entities appearing in the general configuration file""" + """AbstractValidator is the root Base class for any concrete implementation of entities + appearing in the general configuration file""" + @abstractmethod - def validate(self, data): + def validate(self, d): # TODO: FIXME: change API: return parsed value, throw exception if input is invalid! pass elif PY2 or PY3: class AbstractValidator: - """Abstract Base class for any concrete implementation of entities appearing in the general configuration file""" + """AbstractValidator is the root Base class for any concrete implementation of entities + appearing in the general configuration file""" __metaclass__ = ABCMeta + @abstractmethod - def validate(self, data): + def validate(self, d): pass -#elif PY3: +# elif PY3: # class AbstractValidator(metaclass=ABCMeta): -# """Abstract Base class for any concrete implementation of entities appearing in the general configuration file""" +# """AbstractValidator is the root Base class for any concrete implementation of entities +# appearing in the general configuration file""" # @abstractmethod -# def validate(self, data): +# def validate(self, d): # pass else: - raise NotImplementedError("Unsupported Python version: '{}'".format(version_info)) - + raise NotImplementedError("Unsupported Python version: '{}'".format(sys.version_info)) + + ############################################################### class Base(AbstractValidator): """Abstract Base Class for the Config entities""" __version = [None] - _data = None + _parent = None - def __init__(self, parent): + _data = None + _default_data = None + + def __init__(self, parent): # TODO: add tag? here or in some child? AbstractValidator.__init__(self) assert self._parent is None self._parent = parent - - def set_version(self, v): - """To be set once only!""" - assert len(self.__version) == 1 - assert self.__version[0] is None - self.__version[0] = v - - def get_version(self): - assert len(self.__version) == 1 - assert self.__version[0] is not None - return self.__version[0] - + + @classmethod + def set_version(cls, v): + """To be set once only for any Validator class!""" + assert len(cls.__version) == 1 + assert cls.__version[0] is None + cls.__version[0] = v + + @classmethod + def get_version(cls, default=None): + assert len(cls.__version) == 1 + + if cls.__version[0] is not None: + return cls.__version[0] + + return default + def set_data(self, d): - assert self._data is None - self._data = d + # assert self._data is None + # assert d is not None + self._data = d def get_data(self): if self._data is None: return self._default_data - - return self._data - - @abstractmethod - def validate(self, version, data): # version = None? - pass - - def validate(self, data): - return self.validate(self.get_version(), data) + return self._data @classmethod - def parse(cls, data, parent=None): + def parse(cls, d, parent=None): self = cls(parent) - - if self.validate(get_version(), data): + +# print(cls) +# print(parent) +# print(self) +# print(d) + + if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! return self.get_data() - raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data!")) - - - + # NOTE: .parse should! + raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) + + ############################################################### class BaseRecord(Base): """Aggregation of data as a record with some fixed data memebers""" - + # TODO: turn _default_type into a class-member (by moving it here)...? - + def __init__(self, parent): - Base.__init__(self, parent) - self._default_type = None # "default_base" + Base.__init__(self, parent) + self._default_type = None # "default_base" self._types = {} + self._create_optional = False - def detect_type(self, data): - return self.detect_type(self.get_version(), data) - -# @abstractmethod -# def detect_type(self, version, data): -# pass - - - def detect_type(self, version, data): + def detect_type(self, d): """determine the type of variadic data for the format version""" - + assert not (self._default_type is None) - assert len(self._types) > 0 - + assert len(self._types) > 0 + return self._default_type - - def detect_extra_rule(self, version, key, value): # Any extra unlisted keys in the mapping? + + def detect_extra_rule(self, key, value): # Any extra unlisted keys in the mapping? return None - def validate(self, version, data): - #! TODO: assert that data is a mapping with lc! - - _type = self.detect_type(version, data) - + def validate(self, d): + # ! TODO: assert that d is a mapping with lc! + + _type = self.detect_type(d) + assert not (_type is None) assert _type in self._types - - _rule = self._types[_type] + + _rule = self._types[_type] _ret = True - _lc = data.lc # starting location of the mapping...? + _lc = d.lc # starting location of the mapping...? (s, c) = (_lc.line, _lc.col) _d = {} - + for k in _rule.keys(): r = _rule[k] - if r[0] and (k not in data): - key_note(k, s, c, "Error: Missing key `{}` (type: '%s')" % (_type)) # Raise Exception? + if r[0] and (k not in d): + key_note(k, _lc, "ERROR: Missing mandatory key `{}` (type: '%s')" % (_type)) # Raise Exception? _ret = False - elif not r[0]: # Optional Values should have some default values! - _d[k] = r[1](self) - + # NOTE: the following will add all the missing default values + elif (not r[0]) and self._create_optional: # Optional Values should have some default values! + _d[k] = r[1](self).get_data() # NOTE: default value - no validation + + for offset, k in enumerate(d): + v = d.get(k) + l = s + offset # ?? + lc = (l, c) - for offset, k in enumerate(data): - v = data.get(k) - l = s + offset #?? - if k in _rule: - r = _rule[k] - - _d[k] = r[1](self) - - if not _d[k].validate(version, v): # TODO: save to self! - value_error(k, v, l, c, "Error: invalid field '{}' value (type: '%s')" % (_type)) # Raise Exception? + r = _rule[k][1](self) + + if not r.validate(v): # TODO: save to self! + value_error(k, v, lc, "Error: invalid field '{}' value (type: '%s')" % _type) _ret = False + + _d[k] = r.get_data() else: - _extra_rule = self.detect_extra_rule(version, k, v) # (KeyValidator, ValueValidator) + _extra_rule = self.detect_extra_rule(k, v) # (KeyValidator, ValueValidator) if _extra_rule is None: - key_error(k, v, l, c, "Error: Unhandled Key: '{}' (type: '%s')" % (_type)) # Raise Exception? + key_error(k, v, lc, "WARNING: Unhandled extra Key: '{}' (type: '%s')" % _type) _ret = False else: _k = _extra_rule[0](self) - - if not _k.validate(version, k): - key_error(k, v, l, c, "Error: invalid key '{}' value (type: '%s')" % (_type)) # Raise Exception? - _ret = False + + if not _k.validate(k): + key_error(k, v, lc, "Error: invalid key '{}' (type: '%s')" % _type) + _ret = False else: _v = _extra_rule[1](self) - if not _v.validate(version, v): #! TODO: FIXME: wrong col (it was for key - not value)! - value_error(k, v, l, c, "Error: invalid field value '{}' value (type: '%s')" % (_type)) # Raise Exception? + if not _v.validate(v): # TODO: FIXME: wrong col (it was for key - not value)! + value_error(k, v, lc, "Error: invalid field value '{}' value (type: '%s')" % _type) _ret = False else: - _d[_k] = _v + _d[_k.get_data()] = _v.get_data() if _ret: self.set_data(_d) - return _ret - -############################################################### + return _ret + + ############################################################### + + class BaseScalar(Base): """Single scalar value out of YAML scalars: strings, numbert etc.""" - + def __init__(self, parent): Base.__init__(self, parent) - def validate(self, version, data): - """check that data is a scalar: not a sequence of mapping""" - - _ret = not isinstance(data, (list, dict, tuple, set)) #! Check if data is not a container? - - self.set_data( data ) - - return _ret - + def validate(self, d): + """check that data is a scalar: not a sequence or mapping or set""" + + if isinstance(d, (list, dict, tuple, set)): # ! Check if data is not a container? + print("ERROR: value: '{}' is not a scalar value!!" . format(d)) + return False + + self.set_data(d) + return True + + ############################################################### class BaseString(BaseScalar): + """YAML String""" def __init__(self, parent): BaseScalar.__init__(self, parent) - - def validate(self, version, data): - """check whether data is a valid string""" - ### TODO: Detect other YAML scalar types? - if isinstance(data, string_types): - self.set_data( text_type(data) ) - return True - - return False + def validate(self, d): + """check whether data is a valid string. Note: should not care about format version""" + + s = BaseScalar.parse(d, parent=self) + + if not isinstance(s, string_types): + print("ERROR: value: '{}' is not a string!!" . format(d)) + return False + + self.set_data(text_type(d)) + return True ############################################################### -#import semver -import semantic_version # supports partial versions - +# import semver +import semantic_version # supports partial versions + + class SemanticVersion(BaseString): def __init__(self, parent): BaseString.__init__(self, parent) - - def validate(self, version, data): + + def validate(self, d): """check the string data to be a valid semantic verions""" - + + _t = BaseString.parse(d, parent=self) + + _v = self.get_version(None) try: - _v = None - if version == '': # the only initial validation: may be a partial version - _v = semantic_version.Version(data, partial=True) - else: - _v = semantic_version.validate(data) - - self.set_data( _v ) - return True - except: +# if _v is None: # NOTE: the only initial validation: may be a partial version +# _v = semantic_version.Version(_t, partial=True) # TODO: check this! +# else: + _v = semantic_version.Version.parse(_t, partial=True, coerce=True) + except: + print("ERROR: wrong version data: '{0}' (see: '{1}')" . format(d, sys.exc_info())) return False + self.set_data(_v) + return True + + ############################################################### -class BaseUIString(BaseString): # visible to user => non empty! +class BaseUIString(BaseString): # visible to user => non empty! def __init__(self, parent): BaseString.__init__(self, parent) - - def validate(self, version, data): + + def validate(self, d): """check whether data is a valid string""" - _ret = BaseString.validate(self, version, data) - - _ret = _ret and (self.get_data()) # Non-empty - return _ret - + t = BaseString.parse(d, parent=self) + + if bool(t): # Non-empty + self.set_data(t) + return True + + return False + + ############################################################### -class BaseEnum(BaseString): # TODO: Generalize to not only strings... +class BaseEnum(BaseString): # TODO: Generalize to not only strings...? + """Enumeration/collection of several fixed strings""" + def __init__(self, parent): BaseString.__init__(self, parent) - self._types = [] # will depend on the version... - - def validate(self, version, data): - """check whether data is a valid string""" - _ret = BaseString.validate(self, version, data) - - _ret = _ret and (self.get_data() in self._types) # check withing a list of possible string values - return _ret - + self._enum_list = [] # NOTE: will depend on the version... + + def validate(self, d): + """check whether data is in the list of fixed strings (see ._enum_list)""" + + t = BaseString.parse(d, parent=self) + + if not (t in self._enum_list): # check withing a list of possible string values + print("ERROR: string value: '{}' is not among known enum items!!".format(d)) + return False + + self.set_data(t) + return True + + ############################################################### -class ServiceType(BaseEnum): ## Q: Is 'Service::type' mandatory? default: 'compose' +class ServiceType(BaseEnum): ## Q: Is 'Service::type' mandatory? default: 'compose' def __init__(self, parent): BaseEnum.__init__(self, parent) - - _v = 'compose' - self._types = [_v] # NOTE: will depend on format version! - self._default_data = _v - + + compose = 'compose' + self._enum_list = [compose] # NOTE: 'docker' and others may be possible later on + self._default_data = compose + + ############################################################### -class StationOMDTag(BaseEnum): ## Q: Is 'Station::omd_tag' mandatory? default: 'standalone' +class StationOMDTag(BaseEnum): ## Q: Is 'Station::omd_tag' mandatory? default: 'standalone' def __init__(self, parent): BaseEnum.__init__(self, parent) - + _v = 'standalone' - self._types = ['agent', 'windows', _v] # possible values of omd_tag # will depend on format version! + self._enum_list = ['agent', 'windows', _v] # possible values of omd_tag # will depend on format version! self._default_data = _v - + + ############################################################### -class StationPowerOnMethodType(BaseEnum): # Enum: [WOL], AMTvPRO, DockerMachine +class StationPowerOnMethodType(BaseEnum): # Enum: [WOL], AMTvPRO, DockerMachine def __init__(self, parent): BaseEnum.__init__(self, parent) - - _v = 'WOL' - self._types = ['AMTvPRO', 'DockerMachine', _v] # possible values of PowerOnMethod::type # will depend on format version! - self._default_data = _v - + + wol = 'WOL' + # NOTE: the list of possible values of PowerOnMethod::type (will depend on format version) + self._enum_list = [wol, 'DockerMachine'] # NOTE: 'AMTvPRO' and others may be possible later on + self._default_data = wol + + ############################################################### +import os + +if PY3: + from urllib.parse import urlparse + from urllib.request import urlopen +elif PY2: + from urlparse import urlparse + from urllib2 import urlopen + + class URI(BaseString): + """Location of external file, either URL or local absolute or local relative to the input config file""" + def __init__(self, parent): BaseString.__init__(self, parent) - - def validate(self, version, data): + self._type = None + + def validate(self, d): """check whether data is a valid URI""" - _ret = BaseString.validate(self, version, data) - - # TODO: Check if file exists? + + v = BaseString.parse(d, parent=self) + + _ret = True + + if urlparse(v).scheme != "": + self._type = "url" + try: + urlopen(v).close() + except: + print("WARNING: URL: '{}' is not accessible!".format(v)) + _ret = not PEDANTIC + + # TODO: FIXME: base location should be the input file's dirname??? +# elif not os.path.isabs(v): +# v = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), v)) + + elif os.path.isfile(v): # Check whether file exists + self._type = "file" + + elif os.path.isdir(v): # Check whether directory exists + self._type = "dir" + + if not _ret: + print("WARNING: missing/unsupported resource location: {}".format(v)) + _ret = (not PEDANTIC) + + if _ret: + self.set_data(v) + return _ret ############################################################### import re, tokenize if PY3: - def is_valid_id(id): - return id.isidentifier() + def is_valid_id(k): + return k.isidentifier() elif PY2: - def is_valid_id(id): - return re.match(tokenize.Name + '$', id) + def is_valid_id(k): + return re.match(tokenize.Name + '$', k) else: - raise NotImplementedError("Unsupported Python version: '{}'".format(version_info)) - + raise NotImplementedError("Unsupported Python version: '{}'".format(sys.version_info)) + ############################################################### class BaseID(BaseString): def __init__(self, parent): BaseString.__init__(self, parent) - - def validate(self, version, data): + + def validate(self, d): """check whether data is a valid ID string""" - _ret = BaseString.validate(self, version, data) - _ret = _ret and is_valid_id(self.get_data()) - return _ret + v = BaseString.parse(d, parent=self) + + if not is_valid_id(v): + print("ERROR: not a valid variable identifier! Input: '{}'" . format(d)) + return False + + self.set_data(v) + return True ############################################################### -class ClientVariable(BaseID): # +class ClientVariable(BaseID): # def __init__(self, parent): BaseID.__init__(self, parent) - def validate(self, version, data): + def validate(self, d): """check whether data is a valid ID string""" - _ret = BaseID.validate(self, version, data) - v = self.get_data() - - _ret = _ret and ( v == v.lower() or v == v.upper() ) #! Variables are all lower or upper case! - _ret = _ret and (re.match("^hilbert(_[a-z0-9]+)+$", v.lower())) # starting with hilbert_ or HILBERT_ with letters, digits and '_' + v = BaseID.parse(d, parent=self) + + _ret = True + + if not (v == v.lower() or v == v.upper()): # ! Variables are all lower or upper case! + print("ERROR: a variable must be either in lower or upper case! Input: '{}'" . format(d)) + _ret = False + + # NOTE: starting with hilbert_ or HILBERT_ with letters, digits and '_'?? + if not re.match("^hilbert(_[a-z0-9]+)+$", v.lower()): + print("ERROR: variable must start with HILBERT/hilbert and contain words separated by underscores!" + " Input: '{}" .format(d)) + _ret = False + + if _ret: + self.set_data(v) + return _ret - + + ############################################################### class ServiceID(BaseID): def __init__(self, parent): BaseID.__init__(self, parent) - # TODO: move uniqueness check here??? - + + +############################################################### class ApplicationID(BaseID): def __init__(self, parent): BaseID.__init__(self, parent) + ############################################################### class GroupID(BaseID): def __init__(self, parent): BaseID.__init__(self, parent) - # TODO: move uniqueness check here??? - + + +############################################################### class StationID(BaseID): def __init__(self, parent): BaseID.__init__(self, parent) + +############################################################### class ProfileID(BaseID): def __init__(self, parent): BaseID.__init__(self, parent) + ############################################################### class PresetID(BaseID): def __init__(self, parent): BaseID.__init__(self, parent) - + + ############################################################### +import tempfile + class AutoDetectionScript(BaseString): def __init__(self, parent): BaseString.__init__(self, parent) - - def validate(self, version, data): + self._default_data = '' + + def validate(self, d): """check whether data is a valid script""" - _ret = BaseString.validate(self, version, data) - - # TODO: Check the script? - return _ret + script = BaseString.parse(d, parent=self) + + # NOTE: trying to check the BASH script: shellcheck & bash -n 'string': + fd, path = tempfile.mkstemp() + try: + with os.fdopen(fd, 'w') as tmp: +# print(script) + tmp.write(script) + + _cmd = ["bash", "-n", path] + try: + # NOTE: Check for valid bash script + subprocess.check_call(_cmd) # stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) + _ret = True + except: + print("WARNING: error running 'bash -n' to check '{0}' (exit code: {1})!" . format(text_type(script), sys.exc_info())) + _ret = not PEDANTIC # TODO: add a special switch? + + # NOTE: additionall tool: shellcheck (haskell!) + _cmd = ["shellcheck", "-s", "bash", path] + try: + # NOTE: Check for valid bash script + subprocess.check_call(_cmd) # stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) + _ret = True + except: + print("WARNING: error running 'shellcheck' to check '{0}' (exit code: {1})!".format(text_type(script), sys.exc_info())) + _ret = not PEDANTIC # TODO: add a special switch? + + finally: + os.remove(path) + + if _ret: + self.set_data(script) + + return True + ############################################################### class DockerComposeServiceName(BaseString): def __init__(self, parent): - BaseString.__init__(self, parent) - - def validate(self, version, data): + BaseString.__init__(self, parent) + + def validate(self, d): """check whether data is a valid service name in file due to DockerComposeRef""" - - _ret = BaseString.validate(self, version, data) - # TODO: Check the corresponding file for such a service -> Service! - return _ret + + n = BaseString.parse(d, parent=self) + + self.set_data(n) + return True ############################################################### class DockerComposeRef(URI): def __init__(self, parent): URI.__init__(self, parent) self._default_data = "docker-compose.yml" - - def validate(self, version, data): + + def validate(self, d): """check whether data is a valid docker-compose file name""" - _ret = URI.validate(self, version, data) - - ### TODO: call docker-compose on the referenced file! - return _ret + ref = URI.parse(d, parent=self) + self.set_data(ref) + return True + + # TODO: call docker-compose on the referenced file! in DockerService! + ############################################################### class Icon(URI): def __init__(self, parent): URI.__init__(self, parent) - - def validate(self, version, data): + + def validate(self, d): """check whether data is a valid icon file name""" - _ret = URI.validate(self, version, data) - - ### TODO: check the file contents (or extention) - return _ret - + ref = URI.parse(d, parent=self) + + # TODO: check the file contents (or extention) + + self.set_data(ref) + return True + + ############################################################### +import subprocess # , shlex + class HostAddress(BaseString): """SSH alias""" - + def __init__(self, parent): - BaseString.__init__(self, parent) - - def validate(self, version, data): + BaseString.__init__(self, parent) + + def validate(self, d): """check whether data is a valid ssh alias?""" - - _ret = BaseString.validate(self, version, data) - - #! TODO: Check for ssh alias! + + _h = BaseString.parse(d, parent=self) + + _cmd = ["ssh", "-o", "ConnectTimeout=2", _h, "exit 0"] + try: + # NOTE: Check for ssh alias! + subprocess.check_call(_cmd, stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) + _ret = True + except subprocess.CalledProcessError as err: + print("WARNING: non-functional ssh alias: '{0}' => exit code: {1}!" . format(text_type(_h), err.returncode)) + _ret = not PEDANTIC # TODO: add a special switch? + except: # Any other exception is wrong... + print("WARNING: non-functional ssh alias: '{0}'. Moreover: Unexpected error: {1}" . format(text_type(_h), sys.exc_info())) + _ret = not PEDANTIC # TODO: add a special switch? + + if _ret: + self.set_data(_h) + return _ret +############################################################### class HostMACAddress(BaseString): """MAC Address of the station""" - + def __init__(self, parent): - BaseString.__init__(self, parent) - - def validate(self, version, data): + BaseString.__init__(self, parent) + + def validate(self, d): """check whether data is a valid ssh alias?""" - - _ret = BaseString.validate(self, version, data) - - v = self.get_data() - - #! TODO: Check for MAC Address? + + v = BaseString.parse(d, parent=self) + if not re.match("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", v.lower()): - print ( "Wrong MAC Address: [{}]" . format(data) ) - _ret = False - - return _ret + value_error(None, d, d.lc, "ERROR: Wrong MAC Address: [{}]") + return False + + # TODO: verify the existence of that MAC address? + self.set_data(v) + + return True ############################################################### class BaseBool(BaseScalar): def __init__(self, parent): BaseScalar.__init__(self, parent) - - def validate(self, version, data): + + def validate(self, d): """check whether data is a valid string""" ### TODO: Detect other YAML scalar types? - if (data == True) or (data == False): - self.set_data( data ) - return True - - return False + if not isinstance(d, bool): + print("ERROR: not a boolean value: '{}'" . format(d)) + return False -class StationVisibility(BaseBool): ## "hidden": True / [False] + self.set_data(d) + return True + + +class StationVisibility(BaseBool): ## "hidden": True / [False] def __init__(self, parent): BaseBool.__init__(self, parent) self._default_data = False -class AutoTurnon(BaseBool): # Bool, False +class AutoTurnon(BaseBool): # Bool, False def __init__(self, parent): BaseBool.__init__(self, parent) - self._default_data = False # no powering on by default!? - + self._default_data = False # no powering on by default!? + + ############################################################### -class VariadicRecord(BaseRecord): # will need BaseRecord.validate! - """Variadic record. Type is determined by the given 'type' field.""" +class VariadicRecordWrapper(Base): + """VariadicRecordWrapper record. Type is determined by the given 'type' field.""" def __init__(self, parent): - BaseRecord.__init__(self, parent) - - self._type_tag = "type" - self._default_type = None - self._types = {} + Base.__init__(self, parent) + + self._type_tag = "type" + self._type_cls = None - def detect_type(self, version, data): + self._default_type = None + self._types = {} + + def validate(self, d): """determine the type of variadic data for the format version""" - assert not (self._default_type is None) - assert len(self._types) > 0 + _ret = True + + assert self._default_type is not None assert self._default_type in self._types - assert self._type_tag in self._types[self._default_type] - - _rule = self._types[self._default_type][self._type_tag] - - if _rule[0] and (self._type_tag not in data): - _lc = data.lc # start of the current mapping - (l, c) = (_lc.line, _lc.col) - - key_note(self._type_tag, l, c, "Error: Missing mandatory key `{}`") # Raise Exception? - return None - - t = data.get(self._type_tag, self._default_type) - - tt = _rule[1](self) - if not tt.validate(version, t): - _lc = data.lc.key(self._type_tag) - (l, c) = _lc # (_lc.line, _lc.col) - - value_error(self._type_tag, t, l, c, "invalid value '{}'") # Raise Exception? - return None - - self._type = tt - return tt.get_data() -############################################################### -class StationPowerOnMethod(VariadicRecord): - """StationPowerOnMethod""" - - def __init__(self, parent): - VariadicRecord.__init__(self, parent) + _rule = self._types[self._default_type] # Version dependent! + assert _rule is not None - self._default_type = "WOL" # ServiceType("compose")? - - WOL_rule = { - self._type_tag: (True, StationPowerOnMethodType), # Mandatory! - "auto_turnon": (False, AutoTurnon), - "mac": (True, HostMACAddress) - } + assert self._type_cls is not None + + if self._type_tag not in d: + _lc = d.lc # start of the current mapping + key_error(self._type_tag, d, _lc, "ERROR: Missing mandatory key `{}`") + return False + + t = self._type_cls.parse(d[self._type_tag], parent=self) + + if t not in _rule: + _lc = d.lc # start of the current mapping + key_error(self._type_tag, t, _lc, "ERROR: unsupported/wrong variadic type: '{}'") + return False + + tt = _rule[t](self) + + if not tt.validate(d): + _lc = d.lc.key(self._type_tag) + value_error('*', d, _lc, "ERROR: invalid mapping value '{}' for type '%s'" % t) + return False + + self.set_data(tt.get_data()) + return True + + +############################################################### +class StationPowerOnMethodWrapper(VariadicRecordWrapper): + """StationPowerOnMethod :: Wrapper""" + + def __init__(self, parent): + VariadicRecordWrapper.__init__(self, parent) + + T = StationPowerOnMethodType + self._type_cls = T + _wol = {T.parse("WOL"): WOL, T.parse("DockerMachine"): DockerMachine} + + self._default_type = "default_WOL_poweron_method_wrapper" + self._types[self._default_type] = _wol + + +############################################################### +class ServiceWrapper(VariadicRecordWrapper): + """Service :: Wrapper""" + + def __init__(self, parent): + VariadicRecordWrapper.__init__(self, parent) + + T = ServiceType + self._type_cls = T + _dc = {T.parse("compose"): DockerComposeService} + + self._default_type = "default_docker_compose_service_wrapper" + self._types[self._default_type] = _dc + + +############################################################### +class ApplicationWrapper(ServiceWrapper): + """Application :: Wrapper""" + + def __init__(self, parent): + ServiceWrapper.__init__(self, parent) + + T = ServiceType # same for docker-compose Services and Applications! + self._type_cls = T + _dc = {T.parse("compose"): DockerComposeApplication} + + self._default_type = "default_docker_compose_application_wrapper" + self._types[self._default_type] = _dc + + + + +############################################################### +class DockerMachine(BaseRecord): + """DockerMachine :: StationPowerOnMethod""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._type_tag = "type" + + self._default_type = "DockerMachine" DM_rule = { - self._type_tag: (True, StationPowerOnMethodType), # Mandatory! - "auto_turnon": (False, AutoTurnon), - "vm_name": (True, BaseString), - "vm_host_address": (True, HostAddress) + self._type_tag: (True, StationPowerOnMethodType), # Mandatory! + "auto_turnon": (False, AutoTurnon), + "vm_name": (True, BaseString), + "vm_host_address": (True, HostAddress) + } + + self._types = {self._default_type: DM_rule} # ! NOTE: AMT - maybe later... + +class WOL(BaseRecord): + """WOL :: StationPowerOnMethod""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._type_tag = "type" + self._default_type = "WOL" + + WOL_rule = { + self._type_tag: (True, StationPowerOnMethodType), # Mandatory! + "auto_turnon": (False, AutoTurnon), + "mac": (True, HostMACAddress) } - - self._types = { self._default_type: WOL_rule, "DockerMachine": DM_rule } #! NOTE: AMT - maybe later... - + + self._types = {self._default_type: WOL_rule} + + ############################################################### -class Service(VariadicRecord): - """Service data type""" - +class DockerComposeService(BaseRecord): + """DockerCompose :: Service data type""" + def __init__(self, parent): - VariadicRecord.__init__(self, parent) + BaseRecord.__init__(self, parent) - self._default_type = "compose" # ServiceType("compose")? + self._type_tag = "type" + self._hook_tag = "auto_detections" + self._name_tag = "id" + self._file_tag = "file" - self._hook_tag = "auto_detections" - self._name_tag = "name" - self._file_tag = "file" - - compose_rule = { - self._type_tag: (True, ServiceType), # Mandatory + _compose_rule = { + self._type_tag: (True, ServiceType), # Mandatory self._hook_tag: (False, AutoDetectionScript), - self._name_tag: (True, DockerComposeServiceName), - self._file_tag: (False, DockerComposeRef) + self._name_tag: (True, DockerComposeServiceName), + self._file_tag: (False, DockerComposeRef) } - self._types = { self._default_type: compose_rule } - - def validate(self, version, data): - _ret = VariadicRecord.validate(self, version, data) - - ### TODO: call docker-compose on the referenced file with the given Service Name + self._default_type = "default_dc_service" + self._types = {self._default_type: _compose_rule} + self._create_optional = True + + def validate(self, d): + if not BaseRecord.validate(self, d): + assert self.get_data() is None + return False + + _d = self.get_data() + + _f = _d[self._file_tag] + + assert os.path.exists(_f) + + _n = _d[self._name_tag] + # TODO: Check the corresponding file for such a service -> Service in DockerService! + + DC = "docker-compose" + + fd, path = tempfile.mkstemp() + try: + with os.fdopen(fd, 'w') as tmp: + _cmd = [DC, "-f", _f, "config"] # TODO: use '--services'? + try: + subprocess.check_call(_cmd, stdout=tmp, stderr=open("/dev/null", 'w')) + _ret = True + except: + print("WARNING: error running '{}' to check '{}' (exit code: {})!".format(DC, _f, sys.exc_info())) + _ret = not PEDANTIC # TODO: add a special switch? + + with open(path, 'r') as tmp: + dc = load_yaml(tmp) + ss = None + for k in dc['services']: + if k == _n: + ss = dc['services'][k] + break + + if ss is None: + print("ERROR: missing service/application '{}' in file '{}' !".format(_n, _f)) + _ret = False + finally: +# print(path) + os.remove(path) + return _ret + ############################################################### -class Application(Service): - """Application""" - +class DockerComposeApplication(DockerComposeService): + """DockerCompose :: Application""" + def __init__(self, parent): - Service.__init__(self, parent) - - self._default_type = "compose" # ServiceType("compose")? - - compose_rule = { #! NOTE: duplicates the definition of a Service! TODO: Extension? - self._type_tag: (True, ServiceType), # Mandatory - self._hook_tag: (False, AutoDetectionScript), - self._name_tag: (True, DockerComposeServiceName), - self._file_tag: (False, DockerComposeRef), - "name": (True, BaseUIString), - "description": (True, BaseUIString), - "icon": (False, Icon), + DockerComposeService.__init__(self, parent) + + _compose_rule = (self._types[self._default_type]).copy() + + _compose_rule.update({ + "name": (True, BaseUIString), # NOTE: name for UI! + "description": (True, BaseUIString), + "icon": (False, Icon), "compatibleStations": (True, Group) - } - - self._types = { self._default_type: compose_rule } + }) + + self._types[self._default_type] = _compose_rule + ############################################################### class Profile(BaseRecord): """Profile""" - + def __init__(self, parent): BaseRecord.__init__(self, parent) - + self._default_type = "default_profile" - + default_rule = { - "name": (True, BaseUIString), - "description": (True, BaseUIString), - "icon": (False, Icon), - "services": (True, ServiceList), + "name": (True, BaseUIString), + "description": (True, BaseUIString), + "icon": (False, Icon), + "services": (True, ServiceList), "supported_types": (False, ServiceTypeList) } - - self._types = { self._default_type: default_rule } + + self._types = {self._default_type: default_rule} ############################################################### -class StationSSHOptions(BaseRecord): # optional: "Station::ssh_options" # record: user, port, key, key_ref +class StationSSHOptions(BaseRecord): # optional: "Station::ssh_options" # record: user, port, key, key_ref """StationSSHOptions""" - + def __init__(self, parent): BaseRecord.__init__(self, parent) - + self._default_type = "default_station_ssh_options" - + default_rule = { - "user": (False, BaseString), - "key": (False, BaseString), - "port": (False, BaseString), # TODO: BaseInt?? http://stackoverflow.com/questions/4187185/how-can-i-check-if-my-python-object-is-a-number - "key_ref": (False, URI), + "user": (False, BaseString), + "key": (False, BaseString), + "port": (False, BaseString), + # TODO: BaseInt?? http://stackoverflow.com/questions/4187185/how-can-i-check-if-my-python-object-is-a-number + "key_ref": (False, URI), } - - self._types = { self._default_type: default_rule } - - def validate(self, version, data): + + self._types = {self._default_type: default_rule} + + def validate(self, data): """check whether data is a valid ssh connection options""" - - _ret = BaseRecord.validate(self, version, data) - + + _ret = BaseRecord.validate(self, data) + # TODO: Check for ssh connection: Use some Python SSH Wrapper (2/3) return _ret - + + ############################################################### class Station(BaseRecord): """Station""" - + def __init__(self, parent): BaseRecord.__init__(self, parent) - + self._default_type = "default_station" - + default_rule = { - "name": (True, BaseUIString), - "description": (True, BaseUIString), - "icon": (False, Icon), - "extends": (False, StationID), - "profile": (True, ProfileID), - "address": (True, HostAddress), - "poweron_settings": (False, StationPowerOnMethod), # !! variadic, PowerOnType... - "ssh_options": (False, StationSSHOptions), # !!! record: user, port, key, key_ref - "omd_tag": (True, StationOMDTag), # ! like ServiceType: e.g. agent. Q: Is this mandatory? - "hidden": (False, StationVisibility), # Q: Is this mandatory? - "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) + "name": (True, BaseUIString), + "description": (True, BaseUIString), + "icon": (False, Icon), + "extends": (False, StationID), + "profile": (True, ProfileID), + "address": (True, HostAddress), + "poweron_settings": (False, StationPowerOnMethodWrapper), # !! variadic, PowerOnType... + "ssh_options": (False, StationSSHOptions), # !!! record: user, port, key, key_ref + "omd_tag": (True, StationOMDTag), # ! like ServiceType: e.g. agent. Q: Is this mandatory? + "hidden": (False, StationVisibility), # Q: Is this mandatory? + "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) } - - self._types = { self._default_type: default_rule } - - + + self._types = {self._default_type: default_rule} + + ############################################################### class BaseIDMap(Base): - """Mapping: SomeTypeID -> AnyType""" + """Mapping: SomeTypeID -> AnyType""" def __init__(self, parent): Base.__init__(self, parent) self._default_type = None - self._types = {} # type -> (TypeID, Type) - -# def validate_ID(self, key): # special ID type!!! -# return is_valid_id(key) - - def detect_type(self, version, data): + self._types = {} # type -> (TypeID, Type) + + def detect_type(self, d): """determine the type of variadic data for the format version""" - + assert not (self._default_type is None) assert len(self._types) > 0 - + return self._default_type - - def validate(self, version, data): - _type = self.detect_type(version, data) - + + def validate(self, data): + _type = self.detect_type(data) + assert not (_type is None) assert _type in self._types - - (_id, _rule) = self._types[_type] + + (_id, _rule) = self._types[_type] _ret = True - _lc = data.lc # starting position? - (s, c) = (_lc.line, _lc.col) + _lc = data.lc # starting position? + (s, c) = (_lc.line, _lc.col) _d = {} for offset, k in enumerate(data): - v = data.get(k) + v = data.get(k) # TODO: data[offset]??? l = s + offset + _lc = (l, c) id = _id(self) - - if not id.validate(version, k): - key_error(k, v, l, c, "Invalid Key ID: '{}' (type: '%s')" % (_type)) # Raise Exception? + + if not id.validate(k): + key_error(k, v, _lc, "Invalid Key ID: '{}' (type: '%s')" % (_type)) # Raise Exception? _ret = False else: - _d[id] = _rule(self) - - if not _d[id].validate(version, v): # TODO: save to self! - value_error(k, v, l, c, "invalid value '{}' value (type: '%s')" % (_type)) # Raise Exception? + vv = _rule(self) + + if not vv.validate(v): + value_error(k, v, _lc, "invalid value '{}' value (type: '%s')" % (_type)) # Raise Exception? _ret = False - - self.set_data(_d) + elif _ret: + _d[id.get_data()] = vv.get_data() + + if _ret: + self.set_data(_d) return _ret - + + ############################################################### class GlobalServices(BaseIDMap): def __init__(self, parent): BaseIDMap.__init__(self, parent) self._default_type = "default_global_services" - self._types = { self._default_type: (ServiceID, Service) } - - # def validate(self, version, data): - # _ret = BaseID.validate(self, version, data) - # ### TODO: Any post processing? - # return _ret + self._types = {self._default_type: (ServiceID, ServiceWrapper)} + # def validate(self, data): + # _ret = BaseID.validate(self, data) + # ### TODO: Any post processing? + # return _ret ############################################################### -class StationClientSettings(BaseIDMap): # "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) +class StationClientSettings( + BaseIDMap): # "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) def __init__(self, parent): BaseIDMap.__init__(self, parent) self._default_type = "default_station_client_settings" - self._types = { self._default_type: (ClientVariable, BaseScalar) } #! TODO: only strings for now! More scalar types?! - + self._types = { + self._default_type: (ClientVariable, BaseScalar)} # ! TODO: only strings for now! More scalar types?! + + ############################################################### class GlobalApplications(BaseIDMap): def __init__(self, parent): BaseIDMap.__init__(self, parent) self._default_type = "default_global_applications" - self._types = { self._default_type: (ApplicationID, Application) } - - # def validate(self, version, data): - # _ret = BaseID.validate(self, version, data) - # ### TODO: Any post processing? - # return _ret + self._types = {self._default_type: (ApplicationID, ApplicationWrapper)} ############################################################### class GlobalProfiles(BaseIDMap): def __init__(self, parent): BaseIDMap.__init__(self, parent) self._default_type = "default_global_profiles" - self._types = { self._default_type: (ProfileID, Profile) } - - # def validate(self, version, data): - # _ret = BaseID.validate(self, version, data) - # ### TODO: Any post processing? - # return _ret + self._types = {self._default_type: (ProfileID, Profile)} + + # def validate(self, data): + # _ret = BaseID.validate(self, data) + # ### TODO: Any post processing? + # return _ret + +def extend_dict(base, delta, _ext): + new = {} + + for k in base: + if k == _ext: + continue + + if k in delta: + v = delta.get(k, None) + + if v is None: + new[k] = base[k] + continue + + if k == 'client_settings': + t = base.get(k, {}).copy() + + assert isinstance(t, dict) + assert isinstance(v, dict) + + t.update(v) + new[k] = t + else: + new[k] = v # overwrite the rest + else: + new[k] = base[k] + + + for k in delta: + if not ((k == _ext) or (k in new)): + new[k] = delta[k] + + return new ############################################################### class GlobalStations(BaseIDMap): def __init__(self, parent): BaseIDMap.__init__(self, parent) self._default_type = "default_global_stations" - self._types = { self._default_type: (StationID, Station) } + self._types = {self._default_type: (StationID, Station)} - # def validate(self, version, data): - # _ret = BaseID.validate(self, version, data) - # ### TODO: Any post processing? - # return _ret + def validate(self, d): + """Extension mechanism on top of the usual ID Mapping parsing""" -############################################################### -import collections - -if PY2: - def issequenceforme(obj): - if isinstance(obj, basestring): + if not BaseIDMap.validate(self, d): return False - return isinstance(obj, collections.Sequence) -elif PY3: - def issequenceforme(obj): -# if isinstance(obj, basestring): -# return False - # TODO: ??? - return isinstance(obj, collections.Sequence) -else: - raise NotImplementedError("Unsupported Python version: '{}'".format(version_info)) + + _ext = 'extends' + + sts = self.get_data() + self.set_data(None) + + _ret = True + + _processed = {} + _todo = {} + for k in sts: + v = sts[k] + if v.get(_ext, None) is None: + _processed[k] = v + else: + _todo[k] = v + + _chg = True + while bool(_todo) and _chg: + _chg = False + _rest = {} + while bool(_todo): + k, v = _todo.popitem() + assert _ext in v + base = v[_ext] + if base in _processed: + _processed[k] = extend_dict(_processed[base], v, _ext) + _chg = True + else: + _rest[k] = v + _todo = _rest + + if bool(_todo): + print('ERROR: Cyclic dependencies between stations: {}!?' .format(_todo)) + _ret = False + + if _ret: + self.set_data(_processed) + + return _ret + ############################################################### class BaseList(Base): """List of entities of the same type""" - + def __init__(self, parent): Base.__init__(self, parent) - - def detect_type(self, version, data): - """determine the class of items based on the version and sample data""" - + + def validate(self, d): assert self._default_type is not None assert len(self._types) > 0 - - return self._types[self._default_type] - def validate(self, version, data): - _type = self.detect_type(version, data) + # NOTE: determine the class of items based on the version and sample data + _type = self._types[self._default_type] assert _type is not None - _ret = True - + if (not isinstance(d, (list, dict, tuple, set))) and isinstance(d, string_types): + try: + _d = _type.parse(BaseString.parse(d, parent=self), parent=self) + self.get_data(_d) + return True + except: + pass # Not a single string entry... + + # list!? _d = [] - - if not isinstance(data, (list, tuple, dict, set)): #! data is Scalar? + _ret = True + + for idx, i in enumerate(d): # What about a string? _v = _type(self) - - if not _v.validate(version, data): - print( "Error: Wrong entity: {}" . format(data) ) # use _lc!? + if not _v.validate(i): + _lc = d.lc + value_error("[%d]" % idx, d, _lc, "Wrong item in the given sequence!") _ret = False else: - _d.append(_v) - else: # list!? - _lc = data.lc - - for idx, i in enumerate(data): # What about a string? - _v = _type(self) - if not _v.validate(version, i): - # TODO: error # show _lc - print( "Error insequence at {}" . format(idx) ) - _ret = False - else: - _d.insert(idx, _v) # append? + _d.insert(idx, _v.get_data()) # append? if _ret: self.set_data(_d) - + return _ret - + + ############################################################### class GroupIDList(BaseList): """List of GroupIDs or a single GroupID!""" - + def __init__(self, parent): BaseList.__init__(self, parent) self._default_type = "default_GroupID_list" - self._types = { self._default_type: GroupID } + self._types = {self._default_type: GroupID} + ############################################################### class ServiceList(BaseList): """List of ServiceIDs or a single ServiceID!""" - + def __init__(self, parent): BaseList.__init__(self, parent) self._default_type = "default_ServiceID_list" - self._types = { self._default_type: ServiceID } + self._types = {self._default_type: ServiceID} + + ############################################################### -############################################################### class ServiceTypeList(BaseList): """List of ServiceType's or a single ServiceType!""" - + def __init__(self, parent): BaseList.__init__(self, parent) self._default_type = "default_ServiceType_list" - self._types = { self._default_type: ServiceType } + self._types = {self._default_type: ServiceType} + - ############################################################### -class Group(BaseRecord): #? TODO: GroupSet & its .parent? +class Group(BaseRecord): # ? TODO: GroupSet & its .parent? """Group""" - + def __init__(self, parent): BaseRecord.__init__(self, parent) self._default_type = "default_group" - - self._include_tag = "include" - self._exclude_tag = "exclude" + + self._include_tag = "include" + self._exclude_tag = "exclude" self._intersectWith_tag = "intersectWith" - + default_rule = { - self._include_tag: (False, GroupIDList), - self._exclude_tag: (False, GroupIDList), - self._intersectWith_tag: (False, GroupIDList), - "name": (False, BaseUIString), - "description": (False, BaseUIString), - "icon": (False, Icon) + self._include_tag: (False, GroupIDList), + self._exclude_tag: (False, GroupIDList), + self._intersectWith_tag: (False, GroupIDList), + "name": (False, BaseUIString), + "description": (False, BaseUIString), + "icon": (False, Icon) } - self._types = { self._default_type: default_rule } + self._types = {self._default_type: default_rule} - def detect_extra_rule(self, version, key, value): # Any extra unlisted keys in the mapping? - if value is None: # Set item! + def detect_extra_rule(self, key, value): # Any extra unlisted keys in the mapping? + if value is None: # Set item! return (GroupID, BaseScalar) return None - - def validate(self, version, data): - _ret = BaseRecord.validate(self, version, data) + + def validate(self, data): + _ret = BaseRecord.validate(self, data) # Add extra keys into include? - return _ret + return _ret + + ############################################################### + -############################################################### class GlobalGroups(BaseIDMap): def __init__(self, parent): BaseIDMap.__init__(self, parent) self._default_type = "default_global_groups" - self._types = { self._default_type: (GroupID, Group) } - + self._types = {self._default_type: (GroupID, Group)} + ############################################################### class Preset(BaseRecord): """Preset""" - + def __init__(self, parent): BaseRecord.__init__(self, parent) self._default_type = "default_preset" - - # self.__tag = "Version" + + # self.__tag = "Version" default_rule = { - # self.__tag: (True , ??), # Mandatory - # self.__tag: (False, ??), # Optional + # self.__tag: (True , ??), # Mandatory + # self.__tag: (False, ??), # Optional } - self._types = { self._default_type: default_rule } - + self._types = {self._default_type: default_rule} + raise NotImplementedError("Presets are not supported yet!") - + + ############################################################### -class GlobalPresets(BaseIDMap): # Dummy for now! +class GlobalPresets(BaseIDMap): # Dummy for now! def __init__(self, parent): BaseIDMap.__init__(self, parent) self._default_type = "default_global_presets" - self._types = { self._default_type: (PresetID, Preset) } - - def validate(self, version, data): - print ("Warning: Presets are not supported yet!") -# raise NotImplementedError("Presets are not supported yet!") + self._types = {self._default_type: (PresetID, Preset)} + + def validate(self, data): + print("WARNING: Presets are not supported yet!") + # raise NotImplementedError("Presets are not supported yet!") return True - + + ############################################################### class Global(BaseRecord): """General Hilbert Configuration format""" - + def __init__(self, parent): - BaseRecord.__init__(self, parent) # This is the Main Root! + BaseRecord.__init__(self, parent) # This is the Main Root! self._default_type = "default_global" - self._version_tag = "Version" + self._version_tag = "Version" self._applications_tag = "Applications" - self._services_tag = "Services" - self._profiles_tag = "Profiles" - self._stations_tag = "Stations" - self._groups_tag = "Groups" - + self._services_tag = "Services" + self._profiles_tag = "Profiles" + self._stations_tag = "Stations" + self._groups_tag = "Groups" + ### explicit (optional) Type? default_rule = { - self._version_tag: (True, SemanticVersion), # Mandatory, specifies possibly supported Types of each Configuration Entity - self._services_tag: (True, GlobalServices), - self._applications_tag: (True, GlobalApplications), - self._profiles_tag: (True, GlobalProfiles), - self._stations_tag: (True, GlobalStations), - self._groups_tag: (False, GlobalGroups), # Optional - "Presets": (False, GlobalPresets), # Optional. May be removed! default? + self._version_tag: (True, SemanticVersion), # Mandatory, specifies supported Types of Config's Entity + self._services_tag: (True, GlobalServices), + self._applications_tag: (True, GlobalApplications), + self._profiles_tag: (True, GlobalProfiles), + self._stations_tag: (True, GlobalStations), + self._groups_tag: (False, GlobalGroups), # Optional + "Presets": (False, GlobalPresets), # Optional. May be removed! default? } - self._types = { self._default_type: default_rule } + self._types = {self._default_type: default_rule} self._default_data = None @classmethod - def parse(cls, data, parent=None): + def parse(cls, d, parent=None): self = cls(parent) - - if self._version_tag not in data: - print( "ERROR: Missing '{}' field!" . format(self._version_tag) ) - - # TODO: see VariadicRecord :: detect_type to avoid assumptions! - - v = SemanticVersion(None) - - if not v.validate('', data.get(self._version_tag)): - print( "Wrong Global '{}' specification!" . format(self._version_tag) ) - - _version = v.get_data() # there may be some default verion... - - print( "File Format is of version: '{}'" . format(_version) ) - self.set_version(_version) - - _ret = self.validate(_version, data) ## TODO: FIXME: should not need version...!? - - print( "\nValidation result: '{}'" . format(_ret) ) - return self - - def validate(self, version, data): - _ret = BaseRecord.validate(self, version, data) - + + if self._version_tag not in d: + key_note(self._version_tag, d.lc, "ERROR: Missing mandatory '{}' key field!") + raise ConfigurationError(u"{}: {}".format("ERROR:", "Missing version tag '{0}' in the input: '{1}'!".format(self._version_tag, d))) + + try: + _v = SemanticVersion.parse(d[self._version_tag], parent=self) + except: + value_error(self._version_tag, d, d.lc, "Wrong value of global '{}' specification!") + raise + + self.set_version(_v) # NOTE: globally available now! + + if self.validate(d): + return self.get_data() + + return None + + def validate(self, data): + _ret = BaseRecord.validate(self, data) + for offset, k in enumerate(data): if k == self._version_tag: if offset != 0: - print("Note: '{}' specified correctly but not ahead of everything else (offset: {})!".format(self._version_tag, offset)) + print("Note: '{}' specified correctly but not ahead of everything else (offset: {})!".format( + self._version_tag, offset)) _ret = False break - #! checks uniqueness of keys among (Services/Applications): - - _services = data.get(self._services_tag) # Rely on the above and use get_data? + # NOTE: check uniqueness of keys among (Services/Applications): + _services = data.get(self._services_tag) # Rely on the above and use get_data? _applications = data.get(self._applications_tag) for p, k in enumerate(_services): _lc = _services.lc.key(k) - (sline, scol) = _lc # (_lc.line, _lc.col) - - if k in _applications: - print( "Error: '{}' is both a ServiceID and an ApplicationID:" . format(k) ) - key_error(k, _services[k], sline, scol, "Service key: {}") - + + if k in _applications: + print("Error: '{}' is both a ServiceID and an ApplicationID:".format(k)) + key_error(k, _services[k], _lc, "Service key: {}") + _alc = _applications.lc.key(k) - (aline, acol) = _alc # (_alc.line, _alc.col) - - key_error(k, _applications[k], aline, acol, "Application key: {}") + key_error(k, _applications[k], _alc, "Application key: {}") - #! TODO: check Uniqueness of keys among (Profiles/Stations/Groups) !!!! - # TODO: check for GroupID <-> StationID <-> ProfileID + # ! TODO: check Uniqueness of keys among (Profiles/Stations/Groups) !!!! + # ! TODO: check for GroupID <-> StationID <-> ProfileID return _ret - + + ############################################################### +# import pickle +# import cPickle as pickle +import dill as pickle + +from arghandler import * +import argparse + +import logging +import pprint + +def _version(): + print("## Python Version: '{}'".format(sys.version_info)) + print("## ruamel.yaml Version: '{}'".format(yaml.__version__)) + # pickle.HIGHEST_PROTOCOL ? + # arghandler + +def _load(f): + print("## YAML Validation: ") + return load_yaml_file(f) # TODO: check that this is a dictionary! + + +def _yaml_dump(d, stream=None): + print(yaml.round_trip_dump(d, stream=stream)) + + +def _pprint(cfg): + print("## Validated/Parsed pretty Result: ") + pp = pprint.PrettyPrinter(indent=2) + pp.pprint(cfg) + + +def _pickle_dump(f, d): + # f = '{}.pickle' . format(fn) + with open(f, 'wb') as p: + # Pickle the 'data' dictionary using the highest protocol available. + pickle.dump(d, p, pickle.HIGHEST_PROTOCOL) + + +def _parse(d, parent=None): + return Global.parse(d, parent=parent) + + + +@subcmd('test', help='Validate/parse/dump given general Hilbert configuration (YAML) file') +def cmd_test(parser, context, args): + global PEDANTIC + global INPUT_DIRNAME + global OUTPUT_DIRNAME + + # usage = "{} ".format(basename) + args = parser.parse_args(args) +# print('cmd_validate(parser, context, args): %s%s%s' % ('"', args, '"')) + + ctx = vars(context) -print( "Python Version: '{}'".format( version_info ) ) -print( "ruamel.yaml Version: '{}'".format(yaml.__version__) ) + if 'pedantic' in ctx: + PEDANTIC = True -if __name__ == "__main__": - usage = "{} " . format( argv[0] ) - - if len(argv[1:]) > 0: - for arg in argv[1:]: - print( "Parsing config file: '{}'".format(arg) ) - - data = load_yaml(arg) # TODO: check that this is a dictionary! - print( "Input YAML file: " ) - print( yaml.round_trip_dump(data) ) + fn = ctx['infile'] + assert fn is not None - print( "\nValidation starts:\n") - hilbert_configuration = Global.parse(data) + f = URI(None) + if f.validate(fn): + fn = f.get_data() + print("## Input file: '{}'".format(fn)) + else: + print("ERROR: wrong file specification: '{}'" . format(fn)) + exit(1) + + INPUT_DIRNAME = os.path.abspath(os.path.dirname(fn)) + + if 'outdir' in ctx: + out = args.outdir + else: + out = INPUT_DIRNAME + + assert out is not None + + if f.validate(out): + out = f.get_data() + print("## Output dir: '{}'".format(out)) + else: + print("ERROR: wrong directory specification: '{}'" . format(out)) + exit(1) + + OUTPUT_DIRNAME = os.path.abspath(out) + + + # Get the parsed result: + fd, path = tempfile.mkstemp() + old_stdout = sys.stdout + try: + with os.fdopen(fd, 'w') as tmp: +# sys.stdout = tmp + yml = _load(fn) +# sys.stdout = old_stdout + finally: + sys.stdout = old_stdout + os.remove(path) + + + + print("## RT_Dump of YAML: ") + _yaml_dump(yml) + + _pickle_dump('{}.pickle'.format(fn), yml) + + os.chdir(INPUT_DIRNAME) + print("## Data Validation/Parsing: ") + cfg = _parse(yml) + os.chdir(OUTPUT_DIRNAME) + + print("## File Format is of Version: '{}'".format(Global.get_version())) + + if cfg is None: + print("ERROR: no parsed result!") + exit(1) + else: + _pprint(cfg) + _pickle_dump('{}.data.pickle'.format(fn), cfg) + + +@subcmd('verify', help='Check correctness of a given general Hilbert configuration (YAML) file as far as possible...') +def cmd_verify(parser, context, args): + global PEDANTIC + global INPUT_DIRNAME + global OUTPUT_DIRNAME + + args = vars(parser.parse_args(args)) +# vars(args) + + ctx = vars(context) + + if 'pedantic' in ctx: + PEDANTIC = True + + + fn = ctx['infile'] + assert fn is not None + + f = URI(None) + if f.validate(fn): + fn = f.get_data() + print("## Input file: '{}'".format(fn)) + else: + print("ERROR: wrong file specification: '{}'" . format(fn)) + exit(1) - - print( hilbert_configuration.get_data() ) + INPUT_DIRNAME = os.path.abspath(os.path.dirname(fn)) + if 'outdir' in ctx: + out = args.outdir else: - print(usage) + out = INPUT_DIRNAME + + assert out is not None + + if f.validate(out): + out = f.get_data() + print("## Output dir: '{}'".format(out)) + else: + print("ERROR: wrong directory specification: '{}'" . format(out)) + exit(1) + + OUTPUT_DIRNAME = os.path.abspath(out) + + print("## Loading '{}'..." . format(fn)) + try: + yml = _load(fn) + print("## Input file is a valid YAML!") + except: + print("ERROR: wrong input file: '{}'!" . format(fn)) + raise + + os.chdir(INPUT_DIRNAME) + print("## Data Validation/Parsing: ") + cfg = _parse(yml) + + if cfg is None: + print("ERROR: semantically wrong input!") + exit(1) + else: + print("## Input file is a good Hilbert configuration!") + +# return cfg + + +@subcmd('dump', help='Verify the given general Hilbert configuration (YAML) file as far as possible and dump it to output dir') +def cmd_dump(parser, context, args): + global PEDANTIC + global INPUT_DIRNAME + global OUTPUT_DIRNAME + + parser.add_argument('-o', '--outfile', required=False, default=argparse.SUPPRESS, + help="specify output file (default: same as the input config file with '.pickle' suffix)") + + args = vars(parser.parse_args(args)) + + ctx = vars(context) + + if 'pedantic' in ctx: + PEDANTIC = True + + fn = ctx['infile'] + assert fn is not None + + f = URI(None) + if f.validate(fn): + fn = f.get_data() + print("## Input file: '{}'".format(fn)) + else: + print("ERROR: wrong file specification: '{}'" . format(fn)) + exit(1) + + INPUT_DIRNAME = os.path.abspath(os.path.dirname(fn)) + outfile = None + + if 'outfile' in args: + outfile = args['outfile'] + assert outfile is not None + + f = URI(None) + if not f.validate(outfile): + if not PEDANTIC: + print("## WARNING: Output file: '{}' already exists!".format(fn)) + else: + print("## ERROR: Output file: '{}' already exists!".format(fn)) + exit(1) + else: + outfile = '{}.pickle' . format(os.path.basename(fn)) + + + if 'outdir' in ctx: + out = args.outdir + else: + out = INPUT_DIRNAME + + assert out is not None + + if f.validate(out): + out = f.get_data() + print("## Output dir: '{}'".format(out)) + else: + print("ERROR: wrong directory specification: '{}'" . format(out)) + exit(1) + + OUTPUT_DIRNAME = os.path.abspath(out) + + print("## Loading '{}'..." . format(fn)) + try: + yml = _load(fn) + print("## Input file is a valid YAML!") + except: + print("ERROR: wrong input file: '{}'!" . format(fn)) + raise + + os.chdir(INPUT_DIRNAME) + print("## Data Validation/Parsing: ") + cfg = _parse(yml) + + if cfg is None: + print("ERROR: semantically wrong input!") + exit(1) + else: + print("## Input file is a good Hilbert configuration!") + + outfile = os.path.join(OUTPUT_DIRNAME, outfile) + print("## Writing the configuration into '{}'..." . format(outfile)) + _pickle_dump(outfile, cfg) + print("## Pickled configuration is now in '{}'!" . format(outfile)) + + +# return cfg + + + +def main(): + handler = ArgumentHandler(use_subcommand_help=True, enable_autocompletion=True, description="Validate/Parse Hilbert Configuration") + + # add_argument, set_logging_level, set_subcommands, + handler.add_argument('-q', '--quiet', nargs='?', help='decrease verbosity', default=argparse.SUPPRESS) + handler.add_argument('-v', '--verbose', nargs='?', help='increase verbosity', default=argparse.SUPPRESS) +# handler.set_logging_argument('-l', '--log_level', default_level=logging.INFO) + handler.add_argument('-p', '--pedantic', required=False, nargs='?', + help="turn on pedantic mode", default=argparse.SUPPRESS) + + handler.add_argument('-f', '--infile', required=False, default='Hilbert.yml', + help="specify intput file (default: 'Hilbert.yml')") + handler.add_argument('-O', '--outdir', required=False, default=argparse.SUPPRESS, + help="specify output directory (default: alongside with the input config file)") + + _argv = sys.argv + _argv = _argv[1:] + + if len(_argv) == 0: + _argv = ['-h'] + + handler.run(_argv) -#else: -# raise NotImplementedError("Sorry Library usage is not supported yet!") -# assert False +if __name__ == "__main__": + main() diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py new file mode 120000 index 0000000..d235693 --- /dev/null +++ b/config/hilbert_cli_config.py @@ -0,0 +1 @@ +hilbert-cli-config.py \ No newline at end of file diff --git a/config/tests/__init__.py b/config/tests/__init__.py new file mode 100644 index 0000000..1ac1b21 --- /dev/null +++ b/config/tests/__init__.py @@ -0,0 +1,14 @@ +from __future__ import absolute_import +from __future__ import unicode_literals + +import sys + +if sys.version_info >= (2, 7): + import unittest # NOQA +else: + import unittest2 as unittest # NOQA + +try: + from unittest import mock +except ImportError: + import mock # NOQA diff --git a/config/tests/test_version.py b/config/tests/test_version.py new file mode 100644 index 0000000..a4751d3 --- /dev/null +++ b/config/tests/test_version.py @@ -0,0 +1,38 @@ +# -*- coding: utf-8 -*- +# encoding: utf-8 +# coding: utf-8 + +from __future__ import absolute_import, print_function, unicode_literals # NOQA + +from ..hilbert_cli_config import load_yaml, SemanticVersion + +import pytest # NOQA + + +def load(s): + return load_yaml(s) + +from semantic_version import Version # supports partial versions + +class TestVersions: + def test_1(self): + v = '0.0' + assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v)), parent=self) + + v = '0.1' + assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v)), parent=self) + + v = '1.2' + assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v)), parent=self) + + + v = '0.0.1' + assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v)), parent=self) + + v = '0.1.2' + assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v)), parent=self) + + v = '1.2.3' + assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v)), parent=self) + + \ No newline at end of file diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..0e53be8 --- /dev/null +++ b/tox.ini @@ -0,0 +1,14 @@ +[tox] +# envlist = pep8,py35,py27,py34,py33,py26,pypy,jython +#envlist = py35,py27,py34,py33,py26,pypy,jython +envlist = pep8,py35,py27,pypy + +[testenv] +commands = + /bin/bash -c 'py.test config/tests/test_*.py' +deps = + pytest + +[pytest] +norecursedirs = config/tests/data + From 0e2cad658d482d9a1f86f14a4b91a7a7daf994cc Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Tue, 15 Nov 2016 04:05:31 +0100 Subject: [PATCH 07/42] Added another unittest for checking warnings due to shaddowed mapping keys --- config/tests/test_loadwarnings.py | 60 +++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 config/tests/test_loadwarnings.py diff --git a/config/tests/test_loadwarnings.py b/config/tests/test_loadwarnings.py new file mode 100644 index 0000000..7eda196 --- /dev/null +++ b/config/tests/test_loadwarnings.py @@ -0,0 +1,60 @@ +# -*- coding: utf-8 -*- +# encoding: utf-8 +# coding: utf-8 + +from __future__ import absolute_import, print_function, unicode_literals # NOQA + +from ..hilbert_cli_config import load_yaml + +import pytest # NOQA + +def load(s): + return load_yaml(s) + +class TestLoad: + def test_1(self, capsys): + out, err = capsys.readouterr() + load('{a, b, a}') + out, err = capsys.readouterr() + +# with capsys.disabled(): + assert err == '' + assert out == """\ +WARNING: Key re-definition within some mapping: +K[line: 1, column: 2]: Previous Value: + a: None + ↑ +--- +K[line: 1, column: 8]: New Value: + a: None + ↑ +--- +=== +""" + + + + def test_2(self, capsys): + out, err = capsys.readouterr() + load("""{ ? a, ? b, ? a }""") + out, err = capsys.readouterr() + + assert err == '' + assert out == """\ +WARNING: Key re-definition within some mapping: +K[line: 1, column: 5]: Previous Value: + a: None + ↑ +--- +K[line: 1, column: 15]: New Value: + a: None + ↑ +--- +=== +""" + + + + + + From a6e0f042d50fddf4f58d825210985436f7a48b66 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Tue, 15 Nov 2016 12:41:54 +0100 Subject: [PATCH 08/42] Renamed `name` -> `ref` in `DockerComposeService` to avoid conflict with `Application::name` --- config/hilbert-cli-config.py | 2 +- docs/ConfigurationDD.png | Bin 121394 -> 119944 bytes docs/ConfigurationDD.xml | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/config/hilbert-cli-config.py b/config/hilbert-cli-config.py index 5270f95..0ed29db 100755 --- a/config/hilbert-cli-config.py +++ b/config/hilbert-cli-config.py @@ -932,7 +932,7 @@ def __init__(self, parent): self._type_tag = "type" self._hook_tag = "auto_detections" - self._name_tag = "id" + self._name_tag = "ref" self._file_tag = "file" _compose_rule = { diff --git a/docs/ConfigurationDD.png b/docs/ConfigurationDD.png index f2e840ab80e40565dbcc461707a5af08c28e8cdd..74c5617f450c4e99e8fe60eb0c1c8f8c9063b67e 100644 GIT binary patch literal 119944 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%0D$|s#y6I@$9Ub`Fm@>J@H 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 L%=IgD9b^6v7$KVl diff --git a/docs/ConfigurationDD.xml b/docs/ConfigurationDD.xml index d2a13bd..5bcfdb3 100644 --- a/docs/ConfigurationDD.xml +++ b/docs/ConfigurationDD.xml @@ -1 +1 @@ -7V1pj6M4Gv41Je2ulAib+2MnfY1Utd3q6tXsfCoRcBK2CWSBdHXNrx8bbALGEEiASmqcbpUSx+Hy896H79Tl7ten2NlvHyIPBXdQ8X7dqe/vILShjf+SgZd8QFeUfGAT+14+BI4Dj/6fiA6yaQffQ0llYhpFQervq4NuFIbITStjThxHz9Vp6yionnXvbFBt4NF1gvro776XbvNRCxrH8c/I32zZmYFBb3jluD82cXQI6fnuoLrOXvnXO4cdi95osnW86Lk0pH64U5dxFKX5u92vJQrIo2WPLf/dx4Zvi+uOUZh2+QHUzPwnP53ggNg1Z1eWvrCngTz8cOjHKE630SYKneDDcXSR3TEixwT4kxvtfBe/V/D7bboL6HBxr2Qchd47slD44yqI3B/50Ec/COiE/6E0faHIcA5phIeO576Poj07ahpHP9AyCqI4u1pVUZZLRSm+YetH5q7x4Usz1zr5l5+Znskkn3756X/JVcx1+umP4qLT+KX0Ffn4Bz12/cnTxUiiQ+wyXBn0cadOvEFsnmXlg+Q5l35KV+wTinYInwhPoOQ1U+YmsOmRYhQ4qf+zClyH4n9T/LY43NfIxxd4nBKt1wm+kgpI2Bx6PlWlaGXUbKnV0+S3SH/VciDN1qsHYvTODpQ/ltqBMFKcl9K0PZmQCG6KnscwqhdsAKX9BvXL5uvGifmwdT5+k98h+1Ra9ONQRrkNZA+tyai4jQZun8K7UTHUb5CKoWrPjdLL1CqY1HRjrpZf5nk0DpXW06iWOrdaTjMQB9CU66JQfAYpZ6eTs5BJrJui0Jp4VI05tHQTaPnfc6WuWT2sZhij0Jxu/r2kLmQkLGl6EppW7FukaWjPSyTMDONCk9ZE314rhZt/N73anE6vlhSOH7cmoHDd7kfhylwzDW0yAjeUKu0BVT+PiA2tCmYbjkPD3Gmg1k5jhn7ZfKC3zzdVvW3+5VJaQMFGgMG1WOE3mzQDZz5wYAOPKP7pY1TScXyKAz8Xj5V+z7GE5NnfBU6IqhS+jsKUMQpCL+7WD7x75yU6EKgnqeP+YJ8W2yj2/8TznYI94OVPKRlCo4Vaj798JEek54pRgn/7ldEfKIbunSRl1xMFgbNP/FV2hWTKDkPODxdRmkY7Oond2kfu9LmTk+d1FabGfnrvh+iugT3lNmMbw/iJ4hT96sIIAAdcZhI+Hz26hZ2wLXtz2aCIUZRw2Q471RAAb0FnvLsjkqsjDH97T4hgvw98FzOzKCSfuwKTniJuhCp+likniCprEkYZjMtoo0NO4G9C/DFAa3IEsi74AoN3dDglMmiR7B3XDzf32Zz32nHkG33eZOh566foEY+Ta3qOHfLDCB9vHWTY2fqeh8IMW6mTOquCgCirw/ehL/B//ESXRPTo+L6W+DM4fsb/yfQ4XUYhvj/Hz0CFMPafUZIK4QY7w43hy+gGL2gMgC69CV3pyx71xNd38pNzWZ3Ez1D40eGU+FHq+MEPIYMQ0SefPJQil3CbJEcTvmv81LNnIxEwEgKYtTEFAoClN3CQJOcKT1jxTfFjztffcHbkmYarZF/iDH4ja6kxH8prHtlBW6RVAw/yJQ8aHYFA0aaEoH2Gbl5ShKR+/pb0c9WcUj8HNhCAj/C/0NkV6hAm9LBAUVkOHlFWmSI5U0fOdKT9q9SvgS1iTQQdHkrc2N+X2Y8EyfWAZEolGjAPnUiJ9l0MkAwMh9iXavO4qz6p4myLIvmLJhU5p3z2a+P/B5LZt/AiN5nhZ4Hi0AlmJNtx5ihA1xACM2StrJmnO3DmrVQ4M60V8NY2/loxjgfg1Z0yg3Gj3R7rR3i5sIaRm3BNnEg83KzwN6tln7Bise/jmZLkMBo5TKvFi+zIU2hZYohGye042CnUXll3r2jrnCJf192d2KW3A6xhFHbIh2cFGrstgJnVoq/Tk31DbuqEG/x0SilclZNBBXQ6GY9pJ8i4bIoW5IElNWj3iyZpDWohBgs6invJ3LoyN70zBputgC4oOIezNcj53ECs6PlyucdaboE+P9Zym9NlaDbnUFQdMkQksTwQipBsrJQIUsoU8XxnF5HCk1KuSJ6xXc7fODtzhLw+fiy+ackcQcDTUZYrwjJCisTxP4q7bpRHlYwQUcoX02ROJoScm/3BBJBVlUCFU2DoagUuA0LVDA63F2YxNbtZRdZAsw9/Gfh4sS5w4be6QaROd1qnG0CJ0zglTtPqSlzhiq24XY0h3K6WwGdyynrOAYMXfoXv8inJjdonD62dQ5A+OcKAwMUG7ZkJF1IV6KgKDOH/FeJ0EKMWiMoiz4IpkbEZH2oDp7KKokCCZzzwCPTI8cADG0JLF4AHc7uAKBUtEGJaiETQKAgS+JhHQxDUBCobiyx8/u1+8eHb96d/ycScyRZf5FEdb/WZolVa/fl8Ltd3xPVVOyrBg6yvyNFwMlczlSkvl5pYoIuJNWrKC+RKJGHdp13UQJVhpyn2ELgTVTP1TElPpUU0Etcq2MJFFpEIPYMwLVAXSkwlGS7ybVsztILOTPMsNFuvLaChleEZltst8o2hhUiMJ7P3+0S8e3sH+tOBVNDGJAWRfTcWKRhNgaF9HB3jgKcx9DWfLnnpNQBIZN6Nx0vV2lIOHFli74/xlqbq3Pao0zGm1BJ4opiqVigPFHUyXAut1sU3LVEnz0HW2m2FQ6WdABNo5dgSmzhwaKlvREjl6+z1MrxOTp8B0DofcO0CuPkXB5yspiwJx/Owip90ZZCfoyR9R38iWeSrs0ihE2QsHglEFY7MBbaPnlEchdUSpS4Sl/zuS/iAMOfxpOZ2HagSuV5GQ5Xa4lhNku1TtC/VPHY2Ax4fP3/Z85m2kk+9FqL0Ke1ipSHYI+uIrhQdLANhGinW5HKTdUTXDBKoTGgOGrBZJskyogkXXZ1Qv4VAYCQN7k/1zJlKnKor6Ngz3TQsw/QAWDurbv5UunJ9fakN3CzLcdHfS3b2CoGCKXVs0CTzop33lDqbnsr1l4f3352NVKyvAEbWhIp1YRfWYORmaci9jf88e7k7jk53NOmbBy2RORYyVTChUg/1uhNB5ueMu77qhPo48xFNWffTVinT1BlWVO/zupGXLgVLdTiIej3f1UIzYJzQTD04AqoNm1n5ddGlpvrtmT3Zgd7WFhoAY348Bf47ziYJxT4WRYFTe6tWvv6393waOR8qzsS6XI+5yckJchygRG9Ikl1aHxadSvQKkr10KxRGHtWm7HAUWr0U3+qJduI8XvvO1060RuY3Jek937Sb6ad+9zZ3N6xZel9epZKW2gCYhmYqumVBtg9FIZuNef6FqkNbY5rYCV51DrmbktwvldCXkjvbjK9E7cZEgplv9g867lB0sVTsKeR6Tqf0Mlixrygc1TETTSaXj12/uwkckv5CecmUvc/vePNJ3FpxiBpfyOrZL8gzl7mR41XHdAfTa3Q2V5rcfjKefpXgmLTjot5Qli3D6VeNkSn7M4qET5HhddiTW0XeE9kmgUYOAj8h+lm07iSYztkzQYbtxwTXtN0Om2o/aNf8pJn7iHDWEDtfVcDCIvUEMzMPuVGcl4LmaSFY4YwDomHWIvql7WOkvjQpIgUpreMhEoq07VNs7N+5JX4rBt+t9Wpqdah0t+L4wg7dsGvAsgS4amuQT092Kw03gWinmpPwfh+5P1D84GAEhteLcu3GUT5QRzJ+x0BV4K0AomYMbX1lO7NPQbONXKL/3D3JTp/nd/pUOsOg2Fiy26oPY0g2uajwqm+jJH0ql6qdbBUna9SuBkV6R94xDIpEzvZxQlRye+AjGi7aHnimzA2N9dcqCmApO7g0d4TfyrZ6gA67CVuaMldLr+oBbWtulF5su+S+AV2Tiw4ABVYPNNRWw3xj2xOxsZoi0HP+a281DASJgaelBxso9rdrqlKt7bZ3dQrtTZlt5Z+Oq9BOqc9CXVh8X2wL26tEWu4MO45WM0Tv2/G0GhM26MbZxrDpIQ6Z81F2rR153QXBtfHW3TgndeT3L/dXK46kfyUXR5wXEQi27SncIGVUDdLwvbFb1s5x+zSCeXi3lHb2WJzJ6B3jEHlrRBgahjNptbW8qX5ZdBeWKfplddylhV5CI3ep2t10Dc+zu8fN8Ta4qAXDSqPNyM/vaTIObDEaooSWU+zwI36geyK5rlXw3pQdOF74zuAylg2BIfjWw3emyBw96VB/+P7z67cvV4tvqVgKFUuhuSJSCvQhFEuzKYRzSFBMtCLSJ45su5K9c5LkOYo9qRN21gkLyr1OndASdZngPKldivizHKkL9jTzpZQ909s6kJSFfJKMIjBvYU8x23038NbsK0EW3wqvySZ7LjM3f3zEBo43q38omS1MuBUkKY30vfLPemYf63PeRRYOXiJXj97dfmyymx0kqnWFHa0gClZlriiMTZ4bbOwRToR8BSkveTvXgKr2nBV4kkpQZpEXlanq3C7ViHJV8cPVgALbGg3h0hXQgQT0OgkUoviVXQG8IFBp24RG4uDmayfaGfAFqNz8i50BUGl2BtDmb+OIk5pW1CpfulXPyLSX4qKbBSdvM+ywph90J0bmtb0oH0aZY7lmTiaRDKC3JLgAXZtb5a+7lXifzgwZK8OF9ya+cgYKZPtE9XK3/Gd1CNPDY4gNz2v1uNyUrTOeR5HP3DKY/lm2dRSRyW2dJOZbcSkeH1u3/cxb3Iz7/W87Z9MjxaW9aiuW5PG65KGpPHnUXQEiwL4hhzvU4Fi62ADd626+f04nxaxARkUxs69jbyG+vY3es2FN3/maZXKQvlDFYQ+3l4rzCSP8drSbm+1vM2VPG71zU5shHL1Qb8pj6t7UJgOhbGkzQkPZgidcZ08brRE7oRscPNTcIOAgdPoQzjN7pleZJ+IGXt2v04K3RIJrRHBN2RMHak277aFfYnCJt5eQSLtFpE3ZWQdqjX3dyP4jCbaQfvfJVUi8vVm8TdpsBwq3gDjZoeklSdHufC1L+mom8dXoHXw1bzw5Egp3h5OBtJHqx4vB84LXx/pxE0wYMNMVZQ5sRTMN+rfqvjGgOoeqpdg6/Vu9hs75HRyB6HyiyEABM43beto44U1SOW9S3/n6iRbufEyfm3+5t6o5pE8kilAHesWQfn5NI2eSnUXht8K/AmeFgkWxgpyQbwz411SGThwNXJSNUyQAqKYKJ+NnkPc/d0xJ650NZHPneW1OYIjs9G6NzKQue926bE1KCXRZUdn2W9JlDZFzYCQJ8gbkxIW5yAU3uSldVgPa3NZKL6PKck17ruil15m6LLRbz0JSmUsvexRFV7XetKKLP8YR0TiP02Nnv32IPERm/AU= \ No newline at end of file +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 \ No newline at end of file From 3b778ee7c2d500718de3d6e57cbe6965ae8cd6ba Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Tue, 15 Nov 2016 13:39:23 +0100 Subject: [PATCH 09/42] Added complete configuration with docker-compose resources --- config/tests/data/Hilbert.yml | 113 +++++ config/tests/data/dc.yml | 7 + config/tests/data/docker-compose.yml | 595 +++++++++++++++++++++++++++ 3 files changed, 715 insertions(+) create mode 100644 config/tests/data/Hilbert.yml create mode 100644 config/tests/data/dc.yml create mode 100644 config/tests/data/docker-compose.yml diff --git a/config/tests/data/Hilbert.yml b/config/tests/data/Hilbert.yml new file mode 100644 index 0000000..9d6d4a5 --- /dev/null +++ b/config/tests/data/Hilbert.yml @@ -0,0 +1,113 @@ +--- +########## +# AA: 1 # unknown!!! +########## +Version: 0.5.9 # 0.MAJOR.MINOR, later: MAJOR.MINOR +########## +# BB: 'a' # unknown!!! + +Services: +# omd: + omd_agent: { type: compose, file: docker-compose.yml, ref: omd_agent, auto_detections: 'export HB_URL=${HILBERT_HEARTBEAT_URL}' } + # ptmx, registry, mng qr_handler + omd: { type: compose, file: dc.yml, ref: omd, auto_detections: 'export OMD=${HILBERT_OMD_PATH}' } + +Applications: + hb_test: + type: compose +# file: docker-compose.yml # default - may be omitted + ref: hb_test + auto_detections: 'export HB_URL=${HILBERT_HEARTBEAT_URL}' + description: Random HB testing + compatibleStations: + ? server + include: [vb_hb_tes_a] + intersectWith: [simple] + name: HB Testing + +Profiles: + standalone: + services: [] + description: Generic Networking, without SSH & Docker & OMD agent. + name: standalone + supported_types: [] + + server: + services: [ ptmx, omd_agent, omd, registry, mng ] + description: Only for Server Station + name: server + supported_types: [ compose ] + + simple: + services: [ ptmx, omd_agent ] + description: Any Linux station without QR Scanner + name: simple + supported_types: [ compose ] + + qr: + services: [ ptmx, omd_agent, qr_handler ] + description: Linux stations with QR Scanner + name: Tracking + supported_types: [ compose ] + +Stations: + station_defaults: # fake station: only used to share default settings + name: hidden default station + description: Not a real station - Just hidden default settings + profile: standalone + omd_tag: standalone + address: Problematic.SSH.Alias + hidden: true # hide on Dashboard + client_settings: + hilbert_autostart: true # Station starts Hilbert upon booting + hilbert_autostart_delay: 20 # … with this delay in [sec] + HILBERT_PREFERRED_LANGUAGE: de + HILBERT_HEARTBEAT_URL: http://127.0.0.1:8888 + HILBERT_CUPS_SERVER: printer1.public.supernova:631 + HILBERT_HIDE_MOUSE_CURSOR: 1 + HILBERT_ALSA_CARD: 1 + HILBERT_CUSTOMIZATIONS: nv,alsa + + testhost1: + profile: standalone + omd_tag: standalone + hidden: false + description: Some STANDALONE Station + name: Test 1 + address: test1.host.dns.name + poweron_settings: { type: WOL, mac: '11:22:33:44:55:66', auto_turnon: true } + + supernova: + extends: station_defaults + hidden: true # + description: 'Server Station: Supernova' + name: Supernova Server + address: supernova.mfo.de + profile: server + omd_tag: agent + client_settings: + hilbert_autostart_delay: 0 # no delay before starting Hilbert here + HILBERT_SERVER_CONFIG_PATH: '${HOME}/.config/hilbert-server/' # where to keep sync'ed content + HILBERT_OMD_PATH: '${HOME}/.config/hilbert-omd/' # persistent storage for OMD + HILBERT_REGISTRY_DATA_PATH: '${HOME}/.config/hilbert-registry-data/' # persistent storage for docker registry + + vb_hb_test_a: + extends: station_defaults + hidden: false + address: 192.168.99.109 # No static DNS host name for VMs + description: 'Testing Virtual Station: A' + name: 'Virtual Station: Test A' + omd_tag: agent + profile: simple + poweron_settings: { type: DockerMachine, auto_turnon: true, vm_host_address: supernova.mfo.de, vm_name: vb-hb-test-a } + client_settings: + hilbert_autostart_delay: 10 # 10 sec. delay before starting here Hilbert-CLI-Station + hilbert_station_default_application: hb_test_a + +Groups: + mygroup: { simple, exclude: [qr] } + +Presets: # just an idea + default: {} # no changes + testb: { vb_hb_test_a: { hilbert_station_default_application: hb_test_b, HILBERT_HEARTBEAT_URL: 'http://127.0.0.1:7777'} } + diff --git a/config/tests/data/dc.yml b/config/tests/data/dc.yml new file mode 100644 index 0000000..33bfe94 --- /dev/null +++ b/config/tests/data/dc.yml @@ -0,0 +1,7 @@ +version: '2' +services: + omd: + image: malex984/dockapp:base + environment: + - HV + diff --git a/config/tests/data/docker-compose.yml b/config/tests/data/docker-compose.yml new file mode 100644 index 0000000..1c2e222 --- /dev/null +++ b/config/tests/data/docker-compose.yml @@ -0,0 +1,595 @@ +version: '2' +services: + base: + image: malex984/dockapp:base + volumes: + - /tmp:/tmp:rw + - ${PWD}:/DOCKAPP + - /etc/localtime:/etc/localtime:ro + labels: + - "is_top_app=0" + - "description=Base for dockapp services" + working_dir: /DOCKAPP + privileged: false + network_mode: "host" + environment: + - CFG_DIR=/DOCKAPP + - CUPS_SERVER + - ALSA_CARD + - LANGUAGE + - MOUSE_CURSOR + - CUSTOMIZATION + entrypoint: + - /bin/sh + + ddd: + extends: + service: base + image: ${DOCKER_COMPOSE_IMAGE} + labels: + - "is_top_app=0" + - "description=Docker CLI + Compose" + volumes: + - ${NO_PROXY}:${NO_PROXY} + environment: + - NO_PROXY + entrypoint: + - /bin/sh + + admin: + extends: + service: ddd + volumes: + - /dev:/dev:rw + - /run/udev:/run/udev + - /sys/fs/cgroup:/sys/fs/cgroup:ro + - /run/systemd:/run/systemd + - /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket + labels: + - "is_top_app=0" + cap_add: + - SYS_ADMIN + - NET_ADMIN + - ALL + + consul_base: + extends: + service: admin + image: progrium/consul + ports: + - "8400:8400" + - "8500:8500" + - "8600:53/udp" + labels: + - "is_top_app=0" + stdin_open: false + tty: false + restart: "on-failure:5" + entrypoint: + - /bin/start + + consul_agent: + extends: + service: consul_base + command: + - "-advertise" + - "{station_public_ip}" + - "-join" + - "${management_server_ip}" + + consul: + extends: + service: consul_base + volumes: + - "${PWD}/KV:/data" + command: + - "-server" + - "-bootstrap" + - "-advertise" + - "{station_public_ip}" + - "-ui-dir" + - "/ui" + + registrator: + extends: + service: admin + image: gliderlabs/registrator:latest + entrypoint: + - "/bin/registrator" + command: + - "consul://${management_server_ip}:8500" + + x11: + extends: + service: admin + image: malex984/dockapp:dummy + privileged: true + stdin_open: false + tty: false + restart: "on-failure:5" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + command: + - startXephyr.sh + + xephyr: + extends: + service: x11 + environment: + - XCMD=Xephyr + + xvfb: + extends: + service: x11 + environment: + - XCMD=Xvfb + command: + - startXephyr.sh + - "-screen" + - "0" + - "1024x768x16" + + omd_agent: + extends: + service: ddd + image: imaginary.mfo.de:5000/malex984/omd_agent + environment: + - HB_PORT + - HB_HOST + - HB_URL + ports: + - "6556" + - "${HB_PORT}" + stdin_open: false + tty: false + restart: "on-failure:5" + labels: + - "is_top_app=0" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + command: + - omd_agent_entrypoint.sh + + hb_test: + extends: + service: base + privileged: false + image: malex984/dockapp:omd_agent + environment: + - HB_PORT + - HB_HOST + - HB_URL + - HB_INIT_TIMEOUT + - APP_ID=hb_test + stdin_open: false + tty: false + restart: "on-failure:5" + labels: + - "is_top_app=1" + - "description=HB test in python" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + command: + - python2.7 + - /usr/local/bin/heartbeat2.py + + + hb_test_a: + extends: + service: base + image: imaginary.mfo.de:5000/malex984/appa + environment: + - APP_ID=hb_test_a + - HB_PORT + - HB_HOST + - HB_URL + - HB_INIT_TIMEOUT + stdin_open: false + tty: false + restart: "on-failure:5" + labels: + - "description=HB test in bash: A" + - "is_top_app=1" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - /usr/local/bin/A.sh + command: + - AHB_HelloA + + hb_test_b: + extends: + service: hb_test_a + environment: + - APP_ID=hb_test_b + labels: + - "description=HB test in bash: B" + command: + - BHB_HelloB + + hb_test_c: + extends: + service: hb_test_a + environment: + - APP_ID=hb_test_c + labels: + - "description=HB test in bash: C" + command: + - CHB_HelloC + + busybox: + extends: + service: admin + labels: + - "is_top_app=0" + image: busybox + entrypoint: + - /bin/sh + + ptmx: + extends: + service: busybox + stdin_open: false + tty: false + restart: "on-failure:5" + command: + - "./ptmx.sh" + + reboot: + extends: + service: busybox + stdin_open: false + tty: false + command: + - reboot + + omd_anew: + extends: + service: base + image: malex984/dockapp:omd + ports: + - "80" + - "514" + - "5667" + - "5000" + labels: + - "is_top_app=0" + stdin_open: false + tty: false + restart: "on-failure:5" + volumes: + - "omd_data:/OMD" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + command: + - omd_entrypoint.sh + + omd_persistent: + extends: + service: omd_anew + volumes: + - "omd_data:/omd/sites" + + pa: + extends: + service: admin + labels: + - "is_top_app=0" + volumes: + - ${PULSE_SOCKET}:/run/pulse/native + - ${PULSE_COOKIE}:/run/pulse/cookie + environment: + - PULSE_SERVER=/run/pulse/native + - PULSE_COOKIE=/run/pulse/cookie + + gui: + extends: + service: pa + labels: + - "is_top_app=0" + environment: + - QT_X11_NO_MITSHM=1 + - XLIB_SKIP_ARGB_VISUALS=1 + - XAUTHORITY="${XAUTH}" + - DISPLAY + stdin_open: false + tty: false + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + + qrhandler: + extends: + service: gui + labels: + - "is_top_app=0" + image: malex984/dockapp:qrhandler + restart: "on-failure:5" + volumes: + - supernova:/supernova + environment: + - QR_DEVICE_ID + - qrs_screenshot_message + - qr_uploadlocs + command: + - qrhandler.sh + + x11vnc: + extends: + service: gui + labels: + - "is_top_app=0" + image: malex984/dockapp:x11vnc + restart: "on-failure:5" + ports: + - "127.0.0.1:5900-5910:5900-5910" + environment: + - VNC_PASSWD + command: + - x11vnc.sh + + + xeyes: + extends: + service: gui + image: malex984/dockapp:xeyes + restart: "on-failure:5" + labels: + - "is_top_app=1" + command: + - xeyes + + kiosk: + extends: + service: gui + image: malex984/dockapp:kiosk + restart: "on-failure:5" + labels: + - "is_top_app=1" + - "description=Kiosk Web Browser GUI app." + environment: + - HB_PORT + - HB_HOST + - HB_URL + - HB_INIT_TIMEOUT=9 + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - hb_wrapper.sh + - launch.sh + - browser.sh + - -l + command: + - "${WEBGL_APPS}/" + + IB_kiosk: + extends: + service: kiosk + labels: + - "description=Image Blend under Kiosk" + environment: + - APP_ID=light_pollution + command: + - "${WEBGL_APPS}/WebGL_ImageBlend_New/fade_08_new_05b_hb.html?HB_APP_ID=light_pollution&HB_URL=${HB_URL}" + + + HZ_kiosk: + extends: + service: kiosk + labels: + - "description=Habitable Zone under Kiosk" + environment: + - APP_ID=habitable_zones + command: + - "${WEBGL_APPS}/WebGL_Habitable_New_HB/gravity_habitable_new_05_hb2.html?HB_APP_ID=habitable_zones&HB_URL=${HB_URL}" + + chrome: + extends: + service: gui + image: malex984/dockapp:chrome + labels: + - "is_top_app=1" + - "description=Google Chrome Web Browser GUI app." + restart: "on-failure:5" + environment: + - HB_PORT + - HB_HOST + - HB_URL + - HB_INIT_TIMEOUT=9 + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - hb_wrapper.sh + - launch.sh + - browser.sh + command: + - "${WEBGL_APPS}/" + + IB_chrome: + extends: + service: chrome + labels: + - "description=Image Blend under Chrome" + environment: + - APP_ID=IB_chrome + command: + - "${WEBGL_APPS}/WebGL_ImageBlend_New/fade_08_new_05b_hb.html?HB_URL=${HB_URL}&HB_APP_ID=IB_chrome" + + HZ_chrome: + extends: + service: chrome + labels: + - "description=Habitable Zone under Chrome" + environment: + - APP_ID=HZ_chrome + command: + - "${WEBGL_APPS}/WebGL_Habitable_New_HB/gravity_habitable_new_05_hb2.html?HB_URL=${HB_URL}&HB_APP_ID=HZ_chrome" + + opera: + extends: + service: chrome + labels: + - "description=Opera Web Browser GUI app." + environment: + - GOOGLE_CHROME=opera + + chromium: + extends: + service: chrome + labels: + - "description=Chromium Web Browser GUI app." + environment: + - GOOGLE_CHROME=chromium-browser + + kivy: + extends: + service: gui + image: malex984/dockapp:kivy + labels: + - "is_top_app=1" + restart: "on-failure:5" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - launch.sh + command: + - /usr/local/src/Deflectouch/run.sh + + main: + extends: + service: gui + image: malex984/dockapp:main + labels: + - "is_top_app=1" + restart: "on-failure:5" + environment: + - MENU_TRY="gui" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - /usr/local/bin/main.sh + + demo: + extends: + service: gui + image: malex984/dockapp:demo + labels: + - "is_top_app=1" + - "description=Choose demo app" + restart: "on-failure:5" + environment: + - MENU_TRY="gui" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - /usr/local/bin/demo.sh + + x11vnc: + extends: + service: gui + image: malex984/dockapp:x11vnc + labels: + - "is_top_app=0" + restart: "on-failure:5" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - /usr/local/bin/x11vnc.sh + + + registry: + image: registry:2 + labels: + - "is_top_app=0" + - "description=Docker Private Registry" + ports: + - "8055:5000" + restart: "on-failure:5" + volumes: + - "${PWD}/REG/DATA:/var/lib/registry" + + registry_tls: + extends: + service: registry + volumes: + - "${PWD}/REG/CERT:/certs" + labels: + - "description=Docker Private Registry (with TLS)" + environment: + - "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt" + - "REGISTRY_HTTP_TLS_KEY=/certs/domain.key" + + + dockapp: + extends: + service: gui + volumes: + - .:/DOCKAPP + working_dir: /DOCKAPP/ + labels: + - "is_top_app=1" + + register: + extends: + service: dockapp + image: imaginary.mfo.de:5000/malex984/alpine + devices: + - "/dev/bus/usb:/dev/bus/usb:rwm" + - "/dev/nvidia0:/dev/nvidia0" + - "/dev/nvidiactl:/dev/nvidiactl" + - "/dev/dri:/dev/dri" + - "/dev/snd:/dev/snd" + - "/dev/shm:/dev/shm" + - "/dev/input:/dev/input" + network_mode: "host" + ipc: host + pid: "host" + + x11_xclock: + extends: + service: admin + image: alpine:3.4 + stdin_open: false + tty: false + restart: "on-failure:5" + labels: + - "is_top_app=1" + entrypoint: + - /bin/sh + - -c + command: + - 'apk update && apk add xorg-server xf86-video-vesa xf86-input-evdev xf86-input-mouse xf86-input-keyboard udev && echo "exec xclock">>~/.xinitrc && apk add xclock --update-cache --repository "http://dl-cdn.alpinelinux.org/alpine/edge/testing" && startx' + +volumes: + supernova: + driver: local + omd_data: + driver: local From e23485abc3dbb1df3dee45d84e4a098a1e27d71b Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Tue, 15 Nov 2016 14:09:29 +0100 Subject: [PATCH 10/42] `Station::client_settings` is optional due to standalone stations --- docs/ConfigurationDD.png | Bin 119944 -> 120088 bytes docs/ConfigurationDD.xml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ConfigurationDD.png b/docs/ConfigurationDD.png index 74c5617f450c4e99e8fe60eb0c1c8f8c9063b67e..ae89089b252836a5c8dd8b91144ca48d68010114 100644 GIT binary patch delta 60979 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 KXI^1kNdE((kGb^# delta 60876 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 diff --git a/docs/ConfigurationDD.xml b/docs/ConfigurationDD.xml index 5bcfdb3..3d85d10 100644 --- a/docs/ConfigurationDD.xml +++ b/docs/ConfigurationDD.xml @@ -1 +1 @@ -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 \ No newline at end of file +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 \ No newline at end of file From ab3922da1fe15213d79a3eef600ce9e9cb9d9456 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Wed, 16 Nov 2016 05:34:07 +0100 Subject: [PATCH 11/42] Added unit test for parsing the result NOTE: the resulting .data.pickle should be generated under python2 (to be understood also by python3) --- config/tests/data/Hilbert.yml.data.pickle | Bin 0 -> 3210 bytes config/tests/test_validate.py | 53 ++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 config/tests/data/Hilbert.yml.data.pickle create mode 100644 config/tests/test_validate.py diff --git a/config/tests/data/Hilbert.yml.data.pickle b/config/tests/data/Hilbert.yml.data.pickle new file mode 100644 index 0000000000000000000000000000000000000000..36c5dfe85b9b521e5412f344457504de01f4ae9d GIT binary patch literal 3210 zcma)833t@i6?QP-4KSNS*@99inI>3f3>Z8uO@uwz#`cUEjX)%ss2b^cq@t1LYB8Qt zHIS6nG;OnXPr9TVrES(OX|uLXy8Wu&_oNw16PHu_93LOO_wN1f{qFa@cWqq=T^XrY z^i|(Vv+SS$NMV}O%EUJO!d(a)i`i#`maGgcdBCtX3k9OI*YB@H6jnbfI znZ))LkNCc6*F5M6p*JJ%!F|&+b7%6Uva(RhpUsy_`AKC?C`?JhR37@Ibvl85c_^`M zIxm#UXYxW>kxFwgAPpJ5-^h)OWJgc(NAWkCJB2^6N#312G&7l3=8KY;S0<#ASS-Qj z*}LRjxWh25Dsg>94SWad!vAz)sZH22yHnn_);bKX$ag0~Pe@|9I6w2SP@X9kMA$0z z*h@!L%Tr++3(zW0m=gtMLMTnbc1*n^6=6YC#C+*Oz63j@{SDW&ed1>MMo_g(jrW2E zacyTw&5a$)!p=ZiZ>x0zLkxvs>N>Hxm~Y7KUElJNcJjqV-y_ru1Etq@ifuxY z3p}6e#MGjEe<1ha!FD}xPY4Gx#s+yK{Yu;=;sR&jVBDKA`iy>Kz}RF^nvz3O%1_OR z<54@Pik&}4YBy9TDN#lQ!Ul?d~9N^U&KEaIUhJa(M7f(MhkFIK8#5Z zU7aq@=fe?RbL>U4HWClRuuEzthG-7!s;`c~p&Rh2>u@-P`>Mv4*)C&n#n@_WOW}&> zQznXqvoli>u8eU|K5&O5QN<(h=^JqWb$B3zBUOWr231&VXo~ZbQLteQw(kzXknIuR zZ@|cPI2uB>YV0s}2F4HzCbkBM6Qd@N8oT5T7)-69B;lB`J5qIP8(&{^c+}l-WABQw zkLf5n$i-fe$GtH|=S4qmrCp7C(0?LiOU zOncBH%)CXXPB^hF6efkaVj;{Co&1 z-f~ooriL4;70@#BdW7BZ>&u`s%c5QyiG>hp5Dl#1xM(Q~od^#WD^Qbr@Py{n8;(c7 zP}5*d`4FxOc9WYk?O?g>msd>WE%3SXB@W%mw$cB-5HoZ+iO~v@7FiF$P9kuZ>B%(^f29I9Qi#9Wf%t3kJ(xX3 zfyYq}k_4>8z;Ci zaRuUEaa@|>2!le$0qVYLp&)JB07BZp3~G z-wok=8EHG6QS?&0@MD+s;QJx`0A0hhH7h{d|6v7Qlm`%F+tbm~Us9#b>{;Rw&A*5} zgCAAk$H^i6iJGMPr-dM0_RGvFO30s6=cdnaRPMB~KZ{HHIV%Yls4LNhU&J2r%M_=- zk_QnPb6cJGh=n~(Z?W5)EK^xxaQZSljdy$euuQ!eL-;jQH+!hwmbYUxotgP?tX{rZ zx8OHYw@Vh`x2X>PjvX}dtpKkS0#E9>KwOVLh+fUicFk^>?JE>~cum?k?AmINCD>xhd literal 0 HcmV?d00001 diff --git a/config/tests/test_validate.py b/config/tests/test_validate.py new file mode 100644 index 0000000..1a5a248 --- /dev/null +++ b/config/tests/test_validate.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +# encoding: utf-8 +# coding: utf-8 + +from __future__ import absolute_import, print_function, unicode_literals # NOQA + +from ..hilbert_cli_config import load_yaml, _load, _parse, INPUT_DIRNAME #, _pprint + +import pytest # NOQA +import os # NOQA + + +FIXTURE_DIR = os.path.abspath(os.path.join( + os.path.dirname(os.path.realpath(__file__)), + 'data', + )) + + +import dill as pickle # 3-clause BSD + +class TestValidate: + def test_1(self, capsys): + global INPUT_DIRNAME + + g = os.path.join(FIXTURE_DIR, 'Hilbert.yml') + f = os.path.join(FIXTURE_DIR, 'Hilbert.yml.data.pickle') + + print(g) + print(f) + + assert os.path.exists(g) + assert os.path.exists(f) + + yml = _load(g) + assert yml is not None + + INPUT_DIRNAME = FIXTURE_DIR + + cwd = os.getcwd() + try: + os.chdir(INPUT_DIRNAME) + cfg = _parse(yml) + finally: + os.chdir(cwd) + + assert cfg is not None +# _pprint(cfg) + + with open(f, 'rb') as p: + # Pickle the 'data' dictionary using the highest protocol available. + d = pickle.load(p) +# _pprint(d) + assert d == cfg From 9bf3cf5fde9ab9c46a372fc2a5c23f7e048ed51f Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Wed, 16 Nov 2016 05:37:05 +0100 Subject: [PATCH 12/42] Minor fix NOTE: parent should also be a Validator... --- config/tests/test_version.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/config/tests/test_version.py b/config/tests/test_version.py index a4751d3..7b67230 100644 --- a/config/tests/test_version.py +++ b/config/tests/test_version.py @@ -17,22 +17,23 @@ def load(s): class TestVersions: def test_1(self): v = '0.0' - assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v)), parent=self) + assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v))) v = '0.1' - assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v)), parent=self) + assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v))) v = '1.2' - assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v)), parent=self) + assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v))) + def test_2(self): v = '0.0.1' - assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v)), parent=self) + assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v))) v = '0.1.2' - assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v)), parent=self) + assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v))) v = '1.2.3' - assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v)), parent=self) + assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v))) \ No newline at end of file From 23a582de0730d8815e21016692779ce13adab851 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Wed, 16 Nov 2016 05:39:43 +0100 Subject: [PATCH 13/42] Update Configuration model due to the meeting on 15.11.2016 * Station:type may be: standalone, server and default: standard + Station:client_settings is not required for standalone stations! TODO: implement the above + add to the design document * Profiles and Groups may not to be displayed on UI: no need in name/icon/description... Q: Tags are to be implemented via UI - outside of the general configuration file, right? --- docs/ConfigurationDD.png | Bin 120088 -> 121400 bytes docs/ConfigurationDD.xml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/ConfigurationDD.png b/docs/ConfigurationDD.png index ae89089b252836a5c8dd8b91144ca48d68010114..c5624c632bb025001b5faa6998beba5687422d5e 100644 GIT binary patch literal 121400 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%0Dc1Z|P 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 CY%LA| diff --git a/docs/ConfigurationDD.xml b/docs/ConfigurationDD.xml index 3d85d10..f674907 100644 --- a/docs/ConfigurationDD.xml +++ b/docs/ConfigurationDD.xml @@ -1 +1 @@ -7V1rj5s6Gv41I+2ulAib+8cmvR1pZlt1ujp7Po0IOAlbAlkgnc759ccGm4AxBBJgkjlOq1FwDAb8vBe/N9+py92vT7Gz3z5EHgruoOL9ulPf30Fo2gr+Sxpe8gbNBHnDJva9vKnU8Oj/iWgjPW9z8D2UVDqmURSk/r7a6EZhiNy00ubEcfRc7baOguqoe2eDag2PrhPUW3/3vXSbt1rQOLZ/Rv5my0YGhp3/snLcH5s4OoR0vDuorrNP/vPOYdeiD5psHS96LjWpH+7UZRxFaf5t92uJAvJq2WvLz/vY8Gtx3zEK0y4n4JnJT/npBAfE7jm7s/SFvQ3k4ZdDD6M43UabKHSCD8fWRfbEiFwT4CM32vku/q7g79t0F9Dm4llJOwq9d2Si8OEqiNwfedNHPwhoh/+hNH2hyHAOaYSbjmPfR9GeXTWNox9oGQVRnN2tqijLpaIUv7D5I33X+PKlnmud/MtHpiOZ5OiXn/6X3MVcp0d/FDedxi+ln8jhH/Ta9TdPJyOJDrHLcGXQ15068QaxfpaVN5L3XDqVztgnFO0QHgh3oOQ1U+YmsOmVYhQ4qf+zClyH4n9TnFtc7mvk4xs8donW6wTfSQUkrA8dT1UpWik165ZaHSZ/RHpWy4U0W69eiNE7u1D+WmoXwkhxXkrd9qRDIngoOo5hVG/YAEr7A+qX9deNE/1ha3/8JX9CdlSa9GNTRrkNZA+tyai4jQZun8K7UTHUb5CKoWrPjdLH1CqY1HRjrpY/5nk0DpXWYVRLnVstwwzEATTluigUjyDl7HRyFjKJdVMUWhOPqjGHlm4CLf97rtQ1q5fVDGMUmtPNv5fUhYyEJU1PQtOKfYs0De15iYShXYWkpYl+vVYKN/9uerU5nV4tKRy/bk1A4brdj8KVuWYa2mQEbihV2gOqfh4RG1oVzDYch4a5YaDWTmOGfll/oLf3N1W9rf/lUlpAwUaAwbVY4S+bNANn3nBgDY8o/uljVNJ2PMSB74vbSudzLCF59neBE6Iqha+jMGWMgtCLu/UD7955iQ4E6knquD/Y0WIbxf6fuL9TsAc8/SklQ2i0UOvxzEdyRTpWjBJ87ldGf6BouneSlN1PFATOPvFX2R2SLjsMOT9cRGka7Wgn9mgfueFzIyfP6ypMjZ1674foroE95WvGNobxE8Up+tWFEQAOuGxJ+Hy06BbrhG3ZmssaRYyihMt22KmGAHgL2uPdHZFcHWH423tCBPt94LuYmUUhOe4KTDpE3AhV/C5TThBV5iSMMhiX0UabnMDfhPgwQGtyBTIv+AaDd7Q5JTJokewd1w8391mf99qx5Rt936Tpeeun6BG3k3t6jh1yYoSvtw4y7Gx9z0Nhhq3USZ1VQUCU1eHn0Bf4P36jSyJ6dPxcS3wMjsf4P+kep8soxM/n+BmoEMb+M0pSIdxgZ7gxfBnd4AWNAdClN6Erfdmjnvj6Tk45l9VJ/AyFHx1OiR+ljh/8EjIIEX3yyUMpcgm3SXI04afGbz17NxIBIyGArTamQACw9AYOkuRc4Qkrvil+zfn8G86OvNNwlexLnMFvZC015kN5zSO7aIu0auBBvuRBoyMQKNqUELTP0M1LipDUz9+Sfq6aU+rnwAYC8BH+Fzq7Qh3ChB4WKCrLwSPKKl0kZ+rImY60f5X6NbBFrImgw0OJG/v7MvuRILkekEypRANmoRMp0b6LAZKB4RD7Um0ed9YnVZxtkSd/0aQi55TPzjb+fyCRfQsvcpMZfhcoDp1gRqIdZ44CdA0hMEPWypp5ugNn3kqFM9NaAW9t458V43gBXt0pMxg32u2xfoSnC2sY+RKuiROJm5sV/ma17BNWLPZ9LFOSHEYjh2m1eNE68hRalhiiUXI7BnYKtVfW3SvaOqfI13V3J3bp4wBrGIUd8u5ZgcZuC2BmtejrdLBvyE2dcIPfTimEqzIYVECnwXhMO0HGZVO0IC8sqUG7nzdJa5b4GC9ISvyzWJzeGYnNa4EuWDiHvzVIeyVG66qyL2d7rNkWKPVjzbY5XZhmcyBF1SpD5BILBqEIydpK0SClcBHPd3YRyT4pBYzkYdvlII6zw0fI5+PH4peW8BEEPB1lASMsLKSIHv+jeOpGoVQJCxHFfTF15mRUyLkhIEwKWVUxVFgGhk5Z4MIgVM3gcHthKFOzrVW0JGg25C8DH0/WBXb8VluIVOxOK3YDaHIap8lpWl2TK+yxFdurMYTt1RIYTk4toXPA4Ilf4ad8SvKV7ZOH1s4hSJ8coVfg4lXtmVEXUhXoqAoMYQQW4nSQlS0Q5UaeBVMiYzM+1AZOZRVFgQTPeOAR6JHjgQc2+JcuAA/mdgFRKlogxLQQiaBRECQwNI+GIKgJVDZmbPj82/3iw7fvT/+S0TmTTb7IrDre7DNFqzT78/lczu+I86t2VIIHmV+RoeFkwGYq414uXWKBLkusUeNeIJcnCeuG7SIRqgw7TbGHwJ0opalnXHoqV0Qjca2CLVy0IhKhZxCmBepCiakkw7m/bWuGVtCZaZ6FZuu1BTS0MjzDcru5vzG0EHH0ZOv9Pm7v3taB/nQgFbQxSUG0vhuLFIwmv9A+jo6ewNMY+pp3l7z0GgAkWt6Nx0vV2lQO7Fli34/+lqYU3Xav09Gn1OJ4opiqpikP5HUyXAut1sUvLV4nz0HW2m2FQ6WmABNoZd8S6ziwa6mvR0jlk+31MrxOdp8B0NofcDUDuP4XO5wsQahEnl7keVjFT7oyyM9Rkr6jp0gW+eosUmgEGYtHAlGaIzOB7aNnFEdhNU+pi8Ql530JHxDmPJ7U3K4DVSLTy2ioUlsMq0myfYr2pcTHzsuAx8fPX/Z8uK3kU6+FKH3KdbHS4OyRyURXig4WgTCNFGsyuclkomsGCVQmXA4asFkmyVyiCSddnVC/haA5nnw4e6pnzlRiVF1Bx57ppmEZpgfA2ll1s6fSmetrS23gZlmMi/5esrNXcBRMqWODJpkX7byn1Nn0VK6/PLz/7mykYn0FMLImVKyLdaFILLpZJHLv9X8ewNwdSqcrm9DxK1ytdoHqQBKfY+FTBROq9lCvmxJklM6486tOqJUzS9GU2T9t+TJNRWJFWT+v63/pkrZUh4Oo7PNdzUEDxnHQ1F0koFq7mWViFwVrqr+eWZ4d6G0VogEw5sch8N9x9ksotrQo0pzaq7byqcC9+1P/+VDeJlbwesz9Tk6Q4wCJekOS7NL6sOiUqFeQ7KW7ojDyqNZnh6PQ6qX4Vk9UFufx2re/dqJKMr8/Se/+pt1MP/Wnt7mnYXXT+/IqlVTXBsA0NFPRLQuyLSkK2WzM8x9UHdoa08RO8KpzyN2U5H6phL6U3Nm+fCVqNyYSzHzdf9Bxs6KLpWJPIdezO6WXwVJ+RU6pjvFoMsR87CzeTeCQIBjKS6Ysg37HL5/EVRaHyPSFLKv9gmhzGSE5Xo5MdzC9RpFzRWD8k1716wXHpMUX9YbkbOlUv2qMTFmqUSR8ijivw548KvKeyI4J1HkQ+AnRz6J1J8F0zvYJ0nk/JrimLXzYlAFCC+gnzdxHhLMGD/qqAhbmryeYmXnIjeI8ITQPDsEKZxwQDbPm1y/tJCP1pUkRKQhsHQ+RUKRtn2Jj/85X4rey4Lu1ik2tBpXuqzg+vUM37BqwLAGu2mrl08FupfYmEG1acxLe7yP3B4ofHIzA8HpRrt04ygeqS8ZvHqgKrBVAVJKhrcRsZ/YpKLmRS/Sfu6dsySnrfZ5V71PpDINij8lusz7MQrLJRIVnfRsl6VM5Ye1kwTiZqXY1KNI78o5hUCQyto/jopI7BR/RcNFOwTNlbmisylaRBkvZwaWxI/yuttULdNhY2NKUuVr6VC9oW3Oj9GE7J/d16JqcdwAosHqhoXYd5svbnvCN1RSBnv1fe9dhIAgMPC09WEOx1V1Trmpt472rU2hvatlWPnVchXZKfRbqwhT8YofYXonScpPYcbSaISrgjqfVmLBBN872iE0PcciMj7J27cjzLnCujTfvxjmhI79/ub9acSTtK7k44qyIQLCDT2EGKaNqkLLvjTWzdo7bpxzMw7ulXGePxZmM3j4OkbVGhKFhOJNWm8ubqppF92KZompWx71a6C00cpfqupvO4Xnr7nFjvA3Oa8Gw0rhm5Pv3XDIOvGI0RAEtp9jhR/xC90RyXavgval14HjuO4OLWDYEC8G37r4zRcvRkwb1h+8/v377crX4loqlULEULldESoE+hGJpNrlwDgmKiVZEqsWRzVeyb06SPEexJ3XCzjphQbnXqRNaoloTnCW1Sx5/FiN1wc5mvpSyZ1pbB5KykA+SUQTLW9hTzHbfGLw1+koQxbfCc7LJ3svMzV8fWQPHm9U/lGwtTLgVJCGN9Lvyz3pkH6t23kUWDp4iV/fe3b5vsts6SJTrCjuugihYlbmiMDZ5rrOxhzsR8hmkvOTtnAOq2nOW4EkyQdmKvMhMVed2KUeUy4ofLgcU2NZoCJemgA4koNdJoBDFr2wK4AWBSssmNBIH1187Uc6AT0Dl+l9sDIBKszGAloAbR5zUtKJW+dIte0aGvRQ33Sw4+TXDDmv6QXdiZFbbi+JhlDmWa+ZkEskAekuAC9C1uVX+uVuK9+nIkLEiXHhr4itHoEC2W1Qvc8t/VocwPTyGeOF5rRaXm1rrjGdR5CO3DKZ/ltc6imjJbZ0k5lsxKR5fW7ddzVvMjPv9bztn0yPEpT1rK5bk8brkoak8edRNASLAviGDO9TgWLrYANXrbr5+TifFrEBGRTGzr2OHIb68jd6zYE3f/pplcpC+UMVhL7eXivMJI/x2tJubrW8zZU0bvXNRmyEMvVBvimPqXtQmA6EsaTNCQdmCJ1xnTRutETuhGxw81Fwg4CA0+hDOM3umd5kH4gZe3a7TgrdEgmtEcE1ZEwdqTXvuoV9icIk3mZBIu0WkTVlZB2qNdd3ILiQJXiH97pO7kHh7s3ibtNgOFG0EcbpC00uSot35Wpa01Uxiq9E72GreeHAkFO4RJx1pI+WPF43nOa+P+eMmmNBhpivKHNiKZhr0b9V8Y0B1DlVLsXX6t3oPneM7OALR+UCRgRxmGrcBtXHCmqRy1qS+/fUTJdx5nz7X/3JrVbNLn0gUoQ70ii79/J5GjiQ7i8JvhX8FzgoFi2IGOSHf6PCvqQydOBq4KBqnCABQTRVOxs8gb3/uGJLWOxrI5sZ5bU5giNbp3QqZSV32unXZmpQS6LKitO23pMsaIuPASBLkDciJC2ORC25yU7qsBrS5rZU+RpXlmvZc0UufM3VZaLeOQkKZSx97FEVXtd60oosP44honMfusbPfPkQeIj3+Ag== \ No newline at end of file +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 \ No newline at end of file From d3d52c1c262aba53f29b4e3a43ad8ee534ee579b Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Fri, 18 Nov 2016 04:23:58 +0100 Subject: [PATCH 14/42] Starting to separate hilbert-cli-config.py into smaller units: helpers, loader, validators + main tool: hilbert Changes to the subcommand names in hilbert --- config/__init__.py | 4 +- config/helpers.py | 29 +++ config/hilbert-cli-config.py | 366 ++++------------------------------ config/hilbert.py | 256 ++++++++++++++++++++++++ config/tests/test_validate.py | 22 +- 5 files changed, 334 insertions(+), 343 deletions(-) create mode 100644 config/helpers.py mode change 100755 => 100644 config/hilbert-cli-config.py create mode 100755 config/hilbert.py diff --git a/config/__init__.py b/config/__init__.py index 77541cd..ca7e7d6 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import from __future__ import unicode_literals -__version__ = '0.2.0-dev' +__version__ = '0.2.1-dev' -from .hilbert_cli_config import * +# from hilbert_cli_config import * diff --git a/config/helpers.py b/config/helpers.py new file mode 100644 index 0000000..0e91605 --- /dev/null +++ b/config/helpers.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# encoding: utf-8 +# coding: utf-8 + +from __future__ import absolute_import, print_function, unicode_literals + +def pprint(cfg): + import pprint + print("## Validated/Parsed pretty Result: ") + pp = pprint.PrettyPrinter(indent=2) + pp.pprint(cfg) + +# import pickle +# import cPickle as pickle + +def pickle_dump(fn, d): + import dill as pickle # NOTE: 3-clause BSD + with open(fn, 'wb') as p: + # NOTE: Pickle the 'data' dictionary using the highest protocol available? + # pickle.HIGHEST_PROTOCOL = 4 added in Python 3.4 + pickle.dump(d, p, 2) # 2nd PROTOCOL was introduced in Python 2.3. + +def pickle_load(fn): + import dill as pickle # NOTE: 3-clause BSD + with open(fn, 'rb') as p: + d = pickle.load(p) + return d + + diff --git a/config/hilbert-cli-config.py b/config/hilbert-cli-config.py old mode 100755 new mode 100644 index 0ed29db..814d91f --- a/config/hilbert-cli-config.py +++ b/config/hilbert-cli-config.py @@ -1,10 +1,12 @@ -#!/usr/bin/env python3 # -*- coding: utf-8 -*- # encoding: utf-8 # coding: utf-8 from __future__ import absolute_import, print_function, unicode_literals +import logging +# log = logging.getLogger(__name__) + PEDANTIC = False # NOTE: to treat invalid values/keys as errors? INPUT_DIRNAME = './' OUTPUT_DIRNAME = INPUT_DIRNAME @@ -38,7 +40,13 @@ def _get_line_col(lc): return l, c -def key_error(key, value, lc, error_message, e='K'): + +############################################################### +class ConfigurationError(Exception): + def __init__(self, msg): + self._msg = msg + +def _key_error(key, value, lc, error_message, e='K'): (line, col) = _get_line_col(lc) if key is None: @@ -51,7 +59,7 @@ def key_error(key, value, lc, error_message, e='K'): print('---') -def key_note(key, lc, key_message, e='K'): +def _key_note(key, lc, key_message, e='K'): (line, col) = _get_line_col(lc) if key is None: @@ -61,7 +69,7 @@ def key_note(key, lc, key_message, e='K'): print('---') -def value_error(key, value, lc, error, e='E'): +def _value_error(key, value, lc, error, e='E'): (line, col) = _get_line_col(lc) if key is None: @@ -76,7 +84,7 @@ def value_error(key, value, lc, error, e='E'): # Unused??? # def value_warning(key, value, lc, error): -# value_error(key, value, lc, error, e='W') +# _value_error(key, value, lc, error, e='W') ############################################################### @@ -118,8 +126,8 @@ def construct_mapping(self, node, maptyp, deep=False): old = starts[key] print("WARNING: Key re-definition within some mapping: ") # mapping details? - key_error(key, old[1], old[0], "Previous Value: ") - key_error(key, value, key_node.start_mark, "New Value: ") + _key_error(key, old[1], old[0], "Previous Value: ") + _key_error(key, value, key_node.start_mark, "New Value: ") print('===') starts[key] = (key_node.start_mark, value) # in order to find all such problems! @@ -139,11 +147,6 @@ def __init__(self, stream, version=None, preserve_quotes=None): VersionedResolver.__init__(self, version) -############################################################### -class ConfigurationError(Exception): - def __init__(self, msg): - self._msg = msg - ############################################################### def load_yaml(f, Loader=VerboseRoundTripLoader, version=(1, 2), preserve_quotes=True): try: @@ -153,11 +156,6 @@ def load_yaml(f, Loader=VerboseRoundTripLoader, version=(1, 2), preserve_quotes= raise ConfigurationError(u"{}: {}".format(error_name, e)) -def load_yaml_file(filename): - with open(filename, 'r') as fh: - return load_yaml(fh) - - ############################################################### from ruamel.yaml.compat import PY2, PY3, text_type, string_types from abc import * @@ -294,7 +292,7 @@ def validate(self, d): for k in _rule.keys(): r = _rule[k] if r[0] and (k not in d): - key_note(k, _lc, "ERROR: Missing mandatory key `{}` (type: '%s')" % (_type)) # Raise Exception? + _key_note(k, _lc, "ERROR: Missing mandatory key `{}` (type: '%s')" % (_type)) # Raise Exception? _ret = False # NOTE: the following will add all the missing default values elif (not r[0]) and self._create_optional: # Optional Values should have some default values! @@ -309,7 +307,7 @@ def validate(self, d): r = _rule[k][1](self) if not r.validate(v): # TODO: save to self! - value_error(k, v, lc, "Error: invalid field '{}' value (type: '%s')" % _type) + _value_error(k, v, lc, "Error: invalid field '{}' value (type: '%s')" % _type) _ret = False _d[k] = r.get_data() @@ -317,18 +315,18 @@ def validate(self, d): _extra_rule = self.detect_extra_rule(k, v) # (KeyValidator, ValueValidator) if _extra_rule is None: - key_error(k, v, lc, "WARNING: Unhandled extra Key: '{}' (type: '%s')" % _type) + _key_error(k, v, lc, "WARNING: Unhandled extra Key: '{}' (type: '%s')" % _type) _ret = False else: _k = _extra_rule[0](self) if not _k.validate(k): - key_error(k, v, lc, "Error: invalid key '{}' (type: '%s')" % _type) + _key_error(k, v, lc, "Error: invalid key '{}' (type: '%s')" % _type) _ret = False else: _v = _extra_rule[1](self) if not _v.validate(v): # TODO: FIXME: wrong col (it was for key - not value)! - value_error(k, v, lc, "Error: invalid field value '{}' value (type: '%s')" % _type) + _value_error(k, v, lc, "Error: invalid field value '{}' value (type: '%s')" % _type) _ret = False else: _d[_k.get_data()] = _v.get_data() @@ -752,7 +750,7 @@ def validate(self, d): v = BaseString.parse(d, parent=self) if not re.match("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", v.lower()): - value_error(None, d, d.lc, "ERROR: Wrong MAC Address: [{}]") + _value_error(None, d, d.lc, "ERROR: Wrong MAC Address: [{}]") return False # TODO: verify the existence of that MAC address? @@ -817,21 +815,21 @@ def validate(self, d): if self._type_tag not in d: _lc = d.lc # start of the current mapping - key_error(self._type_tag, d, _lc, "ERROR: Missing mandatory key `{}`") + _key_error(self._type_tag, d, _lc, "ERROR: Missing mandatory key `{}`") return False t = self._type_cls.parse(d[self._type_tag], parent=self) if t not in _rule: _lc = d.lc # start of the current mapping - key_error(self._type_tag, t, _lc, "ERROR: unsupported/wrong variadic type: '{}'") + _key_error(self._type_tag, t, _lc, "ERROR: unsupported/wrong variadic type: '{}'") return False tt = _rule[t](self) if not tt.validate(d): _lc = d.lc.key(self._type_tag) - value_error('*', d, _lc, "ERROR: invalid mapping value '{}' for type '%s'" % t) + _value_error('*', d, _lc, "ERROR: invalid mapping value '{}' for type '%s'" % t) return False self.set_data(tt.get_data()) @@ -1123,13 +1121,13 @@ def validate(self, data): id = _id(self) if not id.validate(k): - key_error(k, v, _lc, "Invalid Key ID: '{}' (type: '%s')" % (_type)) # Raise Exception? + _key_error(k, v, _lc, "Invalid Key ID: '{}' (type: '%s')" % (_type)) # Raise Exception? _ret = False else: vv = _rule(self) if not vv.validate(v): - value_error(k, v, _lc, "invalid value '{}' value (type: '%s')" % (_type)) # Raise Exception? + _value_error(k, v, _lc, "invalid value '{}' value (type: '%s')" % (_type)) # Raise Exception? _ret = False elif _ret: _d[id.get_data()] = vv.get_data() @@ -1301,7 +1299,7 @@ def validate(self, d): _v = _type(self) if not _v.validate(i): _lc = d.lc - value_error("[%d]" % idx, d, _lc, "Wrong item in the given sequence!") + _value_error("[%d]" % idx, d, _lc, "Wrong item in the given sequence!") _ret = False else: _d.insert(idx, _v.get_data()) # append? @@ -1459,13 +1457,13 @@ def parse(cls, d, parent=None): self = cls(parent) if self._version_tag not in d: - key_note(self._version_tag, d.lc, "ERROR: Missing mandatory '{}' key field!") + _key_note(self._version_tag, d.lc, "ERROR: Missing mandatory '{}' key field!") raise ConfigurationError(u"{}: {}".format("ERROR:", "Missing version tag '{0}' in the input: '{1}'!".format(self._version_tag, d))) try: _v = SemanticVersion.parse(d[self._version_tag], parent=self) except: - value_error(self._version_tag, d, d.lc, "Wrong value of global '{}' specification!") + _value_error(self._version_tag, d, d.lc, "Wrong value of global '{}' specification!") raise self.set_version(_v) # NOTE: globally available now! @@ -1495,10 +1493,10 @@ def validate(self, data): if k in _applications: print("Error: '{}' is both a ServiceID and an ApplicationID:".format(k)) - key_error(k, _services[k], _lc, "Service key: {}") + _key_error(k, _services[k], _lc, "Service key: {}") _alc = _applications.lc.key(k) - key_error(k, _applications[k], _alc, "Application key: {}") + _key_error(k, _applications[k], _alc, "Application key: {}") # ! TODO: check Uniqueness of keys among (Profiles/Stations/Groups) !!!! # ! TODO: check for GroupID <-> StationID <-> ProfileID @@ -1506,305 +1504,15 @@ def validate(self, data): ############################################################### -# import pickle -# import cPickle as pickle -import dill as pickle - -from arghandler import * -import argparse - -import logging -import pprint - -def _version(): - print("## Python Version: '{}'".format(sys.version_info)) - print("## ruamel.yaml Version: '{}'".format(yaml.__version__)) - # pickle.HIGHEST_PROTOCOL ? - # arghandler - -def _load(f): - print("## YAML Validation: ") - return load_yaml_file(f) # TODO: check that this is a dictionary! +def load_yaml_file(filename): + with open(filename, 'r') as fh: + return load_yaml(fh) +# class Hilbert(object): -def _yaml_dump(d, stream=None): +def yaml_dump(d, stream=None): print(yaml.round_trip_dump(d, stream=stream)) - -def _pprint(cfg): - print("## Validated/Parsed pretty Result: ") - pp = pprint.PrettyPrinter(indent=2) - pp.pprint(cfg) - - -def _pickle_dump(f, d): - # f = '{}.pickle' . format(fn) - with open(f, 'wb') as p: - # Pickle the 'data' dictionary using the highest protocol available. - pickle.dump(d, p, pickle.HIGHEST_PROTOCOL) - - -def _parse(d, parent=None): +def parse(d, parent=None): return Global.parse(d, parent=parent) - - -@subcmd('test', help='Validate/parse/dump given general Hilbert configuration (YAML) file') -def cmd_test(parser, context, args): - global PEDANTIC - global INPUT_DIRNAME - global OUTPUT_DIRNAME - - # usage = "{} ".format(basename) - args = parser.parse_args(args) -# print('cmd_validate(parser, context, args): %s%s%s' % ('"', args, '"')) - - ctx = vars(context) - - if 'pedantic' in ctx: - PEDANTIC = True - - - fn = ctx['infile'] - assert fn is not None - - f = URI(None) - if f.validate(fn): - fn = f.get_data() - print("## Input file: '{}'".format(fn)) - else: - print("ERROR: wrong file specification: '{}'" . format(fn)) - exit(1) - - INPUT_DIRNAME = os.path.abspath(os.path.dirname(fn)) - - if 'outdir' in ctx: - out = args.outdir - else: - out = INPUT_DIRNAME - - assert out is not None - - if f.validate(out): - out = f.get_data() - print("## Output dir: '{}'".format(out)) - else: - print("ERROR: wrong directory specification: '{}'" . format(out)) - exit(1) - - OUTPUT_DIRNAME = os.path.abspath(out) - - - # Get the parsed result: - fd, path = tempfile.mkstemp() - old_stdout = sys.stdout - try: - with os.fdopen(fd, 'w') as tmp: -# sys.stdout = tmp - yml = _load(fn) -# sys.stdout = old_stdout - finally: - sys.stdout = old_stdout - os.remove(path) - - - - print("## RT_Dump of YAML: ") - _yaml_dump(yml) - - _pickle_dump('{}.pickle'.format(fn), yml) - - os.chdir(INPUT_DIRNAME) - print("## Data Validation/Parsing: ") - cfg = _parse(yml) - os.chdir(OUTPUT_DIRNAME) - - print("## File Format is of Version: '{}'".format(Global.get_version())) - - if cfg is None: - print("ERROR: no parsed result!") - exit(1) - else: - _pprint(cfg) - _pickle_dump('{}.data.pickle'.format(fn), cfg) - - -@subcmd('verify', help='Check correctness of a given general Hilbert configuration (YAML) file as far as possible...') -def cmd_verify(parser, context, args): - global PEDANTIC - global INPUT_DIRNAME - global OUTPUT_DIRNAME - - args = vars(parser.parse_args(args)) -# vars(args) - - ctx = vars(context) - - if 'pedantic' in ctx: - PEDANTIC = True - - - fn = ctx['infile'] - assert fn is not None - - f = URI(None) - if f.validate(fn): - fn = f.get_data() - print("## Input file: '{}'".format(fn)) - else: - print("ERROR: wrong file specification: '{}'" . format(fn)) - exit(1) - - INPUT_DIRNAME = os.path.abspath(os.path.dirname(fn)) - - if 'outdir' in ctx: - out = args.outdir - else: - out = INPUT_DIRNAME - - assert out is not None - - if f.validate(out): - out = f.get_data() - print("## Output dir: '{}'".format(out)) - else: - print("ERROR: wrong directory specification: '{}'" . format(out)) - exit(1) - - OUTPUT_DIRNAME = os.path.abspath(out) - - print("## Loading '{}'..." . format(fn)) - try: - yml = _load(fn) - print("## Input file is a valid YAML!") - except: - print("ERROR: wrong input file: '{}'!" . format(fn)) - raise - - os.chdir(INPUT_DIRNAME) - print("## Data Validation/Parsing: ") - cfg = _parse(yml) - - if cfg is None: - print("ERROR: semantically wrong input!") - exit(1) - else: - print("## Input file is a good Hilbert configuration!") - -# return cfg - - -@subcmd('dump', help='Verify the given general Hilbert configuration (YAML) file as far as possible and dump it to output dir') -def cmd_dump(parser, context, args): - global PEDANTIC - global INPUT_DIRNAME - global OUTPUT_DIRNAME - - parser.add_argument('-o', '--outfile', required=False, default=argparse.SUPPRESS, - help="specify output file (default: same as the input config file with '.pickle' suffix)") - - args = vars(parser.parse_args(args)) - - ctx = vars(context) - - if 'pedantic' in ctx: - PEDANTIC = True - - fn = ctx['infile'] - assert fn is not None - - f = URI(None) - if f.validate(fn): - fn = f.get_data() - print("## Input file: '{}'".format(fn)) - else: - print("ERROR: wrong file specification: '{}'" . format(fn)) - exit(1) - - INPUT_DIRNAME = os.path.abspath(os.path.dirname(fn)) - outfile = None - - if 'outfile' in args: - outfile = args['outfile'] - assert outfile is not None - - f = URI(None) - if not f.validate(outfile): - if not PEDANTIC: - print("## WARNING: Output file: '{}' already exists!".format(fn)) - else: - print("## ERROR: Output file: '{}' already exists!".format(fn)) - exit(1) - else: - outfile = '{}.pickle' . format(os.path.basename(fn)) - - - if 'outdir' in ctx: - out = args.outdir - else: - out = INPUT_DIRNAME - - assert out is not None - - if f.validate(out): - out = f.get_data() - print("## Output dir: '{}'".format(out)) - else: - print("ERROR: wrong directory specification: '{}'" . format(out)) - exit(1) - - OUTPUT_DIRNAME = os.path.abspath(out) - - print("## Loading '{}'..." . format(fn)) - try: - yml = _load(fn) - print("## Input file is a valid YAML!") - except: - print("ERROR: wrong input file: '{}'!" . format(fn)) - raise - - os.chdir(INPUT_DIRNAME) - print("## Data Validation/Parsing: ") - cfg = _parse(yml) - - if cfg is None: - print("ERROR: semantically wrong input!") - exit(1) - else: - print("## Input file is a good Hilbert configuration!") - - outfile = os.path.join(OUTPUT_DIRNAME, outfile) - print("## Writing the configuration into '{}'..." . format(outfile)) - _pickle_dump(outfile, cfg) - print("## Pickled configuration is now in '{}'!" . format(outfile)) - - -# return cfg - - - -def main(): - handler = ArgumentHandler(use_subcommand_help=True, enable_autocompletion=True, description="Validate/Parse Hilbert Configuration") - - # add_argument, set_logging_level, set_subcommands, - handler.add_argument('-q', '--quiet', nargs='?', help='decrease verbosity', default=argparse.SUPPRESS) - handler.add_argument('-v', '--verbose', nargs='?', help='increase verbosity', default=argparse.SUPPRESS) -# handler.set_logging_argument('-l', '--log_level', default_level=logging.INFO) - handler.add_argument('-p', '--pedantic', required=False, nargs='?', - help="turn on pedantic mode", default=argparse.SUPPRESS) - - handler.add_argument('-f', '--infile', required=False, default='Hilbert.yml', - help="specify intput file (default: 'Hilbert.yml')") - handler.add_argument('-O', '--outdir', required=False, default=argparse.SUPPRESS, - help="specify output directory (default: alongside with the input config file)") - - _argv = sys.argv - _argv = _argv[1:] - - if len(_argv) == 0: - _argv = ['-h'] - - handler.run(_argv) - -if __name__ == "__main__": - main() diff --git a/config/hilbert.py b/config/hilbert.py new file mode 100755 index 0000000..20ead09 --- /dev/null +++ b/config/hilbert.py @@ -0,0 +1,256 @@ +#!/usr/bin/env python2 + +# -*- coding: utf-8 -*- +# encoding: utf-8 +# coding: utf-8 + +from __future__ import absolute_import, print_function, unicode_literals + +from hilbert_cli_config import * +from helpers import * + +from arghandler import * # NOQA +import argparse # NOQA + +import logging +# log = logging.getLogger(__name__) + +def _version(): + import platform + import dill + import ruamel.yaml as yaml + print("## Python Version: '{}'".format(platform.python_version())) + print("## ruamel.yaml Version: '{}'".format(yaml.__version__)) + print("## dill Version: '{}'".format(dill.__version__)) + # arghandler version? dill version? etc? + +def _load(f): + print("## YAML Validation: ") + return load_yaml_file(f) # TODO: check that this is a dictionary! + + +@subcmd('version', help='Print version info') +def cmd_version(parser, context, args): + _version() + + +@subcmd('cfg_verify', help='Check correctness of a given general Hilbert configuration (YAML) file as far as possible...') +def cmd_verify(parser, context, args): + global PEDANTIC + global INPUT_DIRNAME + global OUTPUT_DIRNAME + + ctx = vars(context) + + if 'pedantic' in ctx: + PEDANTIC = ctx['pedantic'] + + + args = vars(parser.parse_args(args)) +# vars(args) + + fn = ctx['inputfile'] + assert fn is not None + + f = URI(None) + if f.validate(fn): + fn = f.get_data() + print("## Input file: '{}'".format(fn)) + else: + print("ERROR: wrong file specification: '{}'" . format(fn)) + exit(1) + + INPUT_DIRNAME = os.path.abspath(os.path.dirname(fn)) + + print("## Loading '{}'..." . format(fn)) + try: + yml = _load(fn) + print("## Input file is a valid YAML!") + except: + print("ERROR: wrong input file: '{}'!" . format(fn)) + raise + + os.chdir(INPUT_DIRNAME) + print("## Deep Configuration Validation/Parsing: ") + cfg = parse(yml) + + if cfg is None: + print("ERROR: semantically wrong input!") + exit(1) + + print("## Input file is a good Hilbert configuration!") + +# return cfg + + +@subcmd('cfg_dump', help='Load input .YAML or .Pickle file and dump it') +def cmd_dump(parser, context, args): + global PEDANTIC + global INPUT_DIRNAME + global OUTPUT_DIRNAME + + parser.add_argument('-O', '--outputdir', required=False, default=argparse.SUPPRESS, + help="specify output directory (default: alongside with the output dump file)") + + parser.add_argument('-od', '--outputdump', required=True, default=argparse.SUPPRESS, + help="specify output file (default: same as the input file with '.pickle' suffix)") + + ctx = vars(context) + + if 'pedantic' in ctx: + PEDANTIC = ctx['pedantic'] + + args = vars(parser.parse_args(args)) + + fn = None + df = None + + f = URI(None) + + if 'inputfile' in ctx: + fn = ctx['inputfile'] +# assert fn is not None + + if 'inputdump' in ctx: + df = ctx['inputdump'] +# assert df is not None + + if fn is not None: + if not f.validate(fn): + print("ERROR: wrong file specification: '{}'" . format(fn)) + exit(1) + print("## Input file: '{}'".format(fn)) + + if df is not None: + if not f.validate(df): + print("ERROR: wrong dump file specification: '{}'" . format(df)) + exit(1) + print("## Input dump file: '{}'".format(df)) + + + if (fn is None) and (df is None): + print("ERROR: input file/dump specification is missing!") + exit(1) + + if (fn is not None) and (df is not None): + print("ERROR: input file specification clashes with the input dump specification: specify a single input source!") + exit(1) + + + if fn is not None: + INPUT_DIRNAME = os.path.abspath(os.path.dirname(fn)) + else: + assert df is not None + INPUT_DIRNAME = os.path.abspath(os.path.dirname(df)) + + + out = None + + if 'outputdir' in args: + out = args['outputdir'] + + assert out is not None + + if not f.validate(out): + print("ERROR: wrong output directory specification: '{}'" . format(out)) + exit(1) + +# out = f.get_data() + print("## Output dir: '{}'".format(out)) + + OUTPUT_DIRNAME = os.path.abspath(out) + else: + OUTPUT_DIRNAME = INPUT_DIRNAME + + od = None + + if 'outputdump' in args: + od = args['outputdump'] + assert od is not None + elif fn is not None: + od = os.path.splitext(os.path.basename(fn))[0] + '.pickle' + OUTPUT_DIRNAME = INPUT_DIRNAME + else: + assert df is not None + od = os.path.splitext(os.path.basename(df))[0] + '.pickle' + OUTPUT_DIRNAME = INPUT_DIRNAME + + + f = URI(None) + if not f.validate(od): + if not PEDANTIC: + print("## WARNING: Output dump file: '{}' already exists!".format(od)) + else: + print("## ERROR: Output dump file: '{}' already exists!".format(od)) + exit(1) + + cfg = None + if fn is not None: + print("## Loading '{}'..." . format(fn)) + try: + yml = _load(fn) + print("## Input file is a valid YAML!") + + os.chdir(INPUT_DIRNAME) + print("## Data Validation/Parsing: ") + cfg = parse(yml) + + except: + print("ERROR: wrong input file: '{}'!" . format(fn)) + raise + else: + print("## Loading dump '{}'..." . format(df)) + try: + cfg = pickle_load(df) + print("## Input dump file is valid!") + except: + print("ERROR: wrong input dump file: '{}'!" . format(df)) + raise + + + if cfg is None: + print("ERROR: semantically wrong input!") + exit(1) + + print("## Input is OK!") + + print("## Writing the configuration into '{}'..." . format(od)) + pickle_dump(od, cfg) + print("## Pickled configuration is now in '{}'!" . format(od)) + + +# return cfg + + + +def main(): + handler = ArgumentHandler(use_subcommand_help=True, enable_autocompletion=True, description="Validate/Parse Hilbert Configuration") + + # add_argument, set_logging_level, set_subcommands, + handler.add_argument('-q', '--quiet', help='decrease verbosity', action='store_true') + handler.add_argument('-v', '--verbose', help='increase verbosity', action='store_true') + +# handler.set_logging_argument('-l', '--log_level', default_level=logging.INFO) + + # no arguments: 'store_const', 'store_true' or 'store_false' + handler.add_argument('-p', '--pedantic', required=False, action='store_true', + help="turn on pedantic mode") + + handler.add_argument('-if', '--inputfile', required=False, default='Hilbert.yml', + help="specify input file (default: 'Hilbert.yml')") + + handler.add_argument('-id', '--inputdump', required=False, + help="specify input dump file") + + _argv = sys.argv + _argv = _argv[1:] + + if len(_argv) == 0: + _argv = ['-h'] + + handler.run(_argv) + +if __name__ == "__main__": + main() + + \ No newline at end of file diff --git a/config/tests/test_validate.py b/config/tests/test_validate.py index 1a5a248..e112b54 100644 --- a/config/tests/test_validate.py +++ b/config/tests/test_validate.py @@ -4,7 +4,8 @@ from __future__ import absolute_import, print_function, unicode_literals # NOQA -from ..hilbert_cli_config import load_yaml, _load, _parse, INPUT_DIRNAME #, _pprint +from ..hilbert_cli_config import load_yaml_file, parse, INPUT_DIRNAME +from ..helpers import pickle_load, pprint import pytest # NOQA import os # NOQA @@ -15,9 +16,6 @@ 'data', )) - -import dill as pickle # 3-clause BSD - class TestValidate: def test_1(self, capsys): global INPUT_DIRNAME @@ -31,7 +29,7 @@ def test_1(self, capsys): assert os.path.exists(g) assert os.path.exists(f) - yml = _load(g) + yml = load_yaml_file(g) assert yml is not None INPUT_DIRNAME = FIXTURE_DIR @@ -39,15 +37,15 @@ def test_1(self, capsys): cwd = os.getcwd() try: os.chdir(INPUT_DIRNAME) - cfg = _parse(yml) + cfg = parse(yml) finally: os.chdir(cwd) assert cfg is not None -# _pprint(cfg) - with open(f, 'rb') as p: - # Pickle the 'data' dictionary using the highest protocol available. - d = pickle.load(p) -# _pprint(d) - assert d == cfg + d = pickle_load(f) + +# pprint(cfg) +# pprint(d) + + assert d == cfg From 92b61792c656014fc0d768c44ec92c6982979323 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Fri, 18 Nov 2016 19:46:33 +0100 Subject: [PATCH 15/42] Separated the main Hilbert tool from the library: /tools/hilbert.py NOTE: it requires ../config/*.py Also a few fixes in subcommand's argument handling (e.g. input sources & default values) --- config/hilbert-cli-config.py | 1518 --------------------------------- config/hilbert_cli_config.py | 1519 +++++++++++++++++++++++++++++++++- {config => tools}/hilbert.py | 93 ++- 3 files changed, 1573 insertions(+), 1557 deletions(-) delete mode 100644 config/hilbert-cli-config.py mode change 120000 => 100644 config/hilbert_cli_config.py rename {config => tools}/hilbert.py (79%) diff --git a/config/hilbert-cli-config.py b/config/hilbert-cli-config.py deleted file mode 100644 index 814d91f..0000000 --- a/config/hilbert-cli-config.py +++ /dev/null @@ -1,1518 +0,0 @@ -# -*- coding: utf-8 -*- -# encoding: utf-8 -# coding: utf-8 - -from __future__ import absolute_import, print_function, unicode_literals - -import logging -# log = logging.getLogger(__name__) - -PEDANTIC = False # NOTE: to treat invalid values/keys as errors? -INPUT_DIRNAME = './' -OUTPUT_DIRNAME = INPUT_DIRNAME - -############################################################### -up_arrow = '↑' - - -def _get_line_col(lc): - - if isinstance(lc, (list, tuple)): - l = lc[0] - c = lc[1] - else: - try: - l = lc.line - except: - print("Unexpected error: ", sys.exc_info()[0]) - print("Cannot get line out of: ", lc) - raise - - try: - c = lc.col - except: - try: - c = lc.column - except: - print("Unexpected error: ", sys.exc_info()[0]) - print("Cannot get col/column out of: ", lc) - raise - - return l, c - - -############################################################### -class ConfigurationError(Exception): - def __init__(self, msg): - self._msg = msg - -def _key_error(key, value, lc, error_message, e='K'): - (line, col) = _get_line_col(lc) - - if key is None: - key = '*' - - print('{}[line: {}, column: {}]: {}'.format(e, line + 1, col + 1, error_message.format(key))) - print('{}{}: {}'.format(' ' * col, key, value)) #! - # ! TODO: try to get access to original ruamel.yaml buffered lines...? - print('{}{}'.format(' ' * col, up_arrow)) - print('---') - - -def _key_note(key, lc, key_message, e='K'): - (line, col) = _get_line_col(lc) - - if key is None: - key = '*' - - print('{}[line: {}, column: {}]: {}'.format(e, line + 1, col + 1, key_message.format(key))) - print('---') - - -def _value_error(key, value, lc, error, e='E'): - (line, col) = _get_line_col(lc) - - if key is None: - key = '*' - - val_col = col + len(key) + 2 - print('{}[line: {}, column: {}]: {}'.format(e, line + 1, val_col + 1, error.format(key))) - print('{}{}: {}'.format(' ' * col, key, value)) #! - # ! TODO: try to get access to original ruamel.yaml buffered lines...? - print('{}{}'.format(' ' * val_col, up_arrow)) - print('---') - -# Unused??? -# def value_warning(key, value, lc, error): -# _value_error(key, value, lc, error, e='W') - - -############################################################### -import collections -import ruamel.yaml as yaml - -from ruamel.yaml.reader import Reader -from ruamel.yaml.scanner import RoundTripScanner # Scanner -from ruamel.yaml.parser import RoundTripParser # Parser, -from ruamel.yaml.composer import Composer -from ruamel.yaml.constructor import RoundTripConstructor # Constructor, SafeConstructor, -from ruamel.yaml.resolver import VersionedResolver # Resolver, -# from ruamel.yaml.nodes import MappingNode - - -############################################################### -class VerboseRoundTripConstructor(RoundTripConstructor): - def construct_mapping(self, node, maptyp, deep=False): - - m = RoundTripConstructor.construct_mapping(self, node, maptyp, deep=deep) # the actual construction! - - # additionally go through all nodes in the mapping to detect overwrites: - - starts = {} # already processed keys + locations and values - - for key_node, value_node in node.value: - # keys can be list -> deep - key = self.construct_object(key_node, deep=True) - - # lists are not hashable, but tuples are - if not isinstance(key, collections.Hashable): - if isinstance(key, list): - key = tuple(key) - - value = self.construct_object(value_node, deep=deep) - # TODO: check the lines above in the original Constructor.construct_mapping code for any changes/updates - - if key in starts: # Duplication detection - old = starts[key] - - print("WARNING: Key re-definition within some mapping: ") # mapping details? - _key_error(key, old[1], old[0], "Previous Value: ") - _key_error(key, value, key_node.start_mark, "New Value: ") - print('===') - - starts[key] = (key_node.start_mark, value) # in order to find all such problems! - - return m - - -############################################################### -class VerboseRoundTripLoader(Reader, RoundTripScanner, RoundTripParser, Composer, - VerboseRoundTripConstructor, VersionedResolver): - def __init__(self, stream, version=None, preserve_quotes=None): - Reader.__init__(self, stream) - RoundTripScanner.__init__(self) - RoundTripParser.__init__(self) - Composer.__init__(self) - VerboseRoundTripConstructor.__init__(self, preserve_quotes=preserve_quotes) - VersionedResolver.__init__(self, version) - - -############################################################### -def load_yaml(f, Loader=VerboseRoundTripLoader, version=(1, 2), preserve_quotes=True): - try: - return yaml.load(f, Loader=Loader, version=version, preserve_quotes=preserve_quotes) - except (IOError, yaml.YAMLError) as e: - error_name = getattr(e, '__module__', '') + '.' + e.__class__.__name__ - raise ConfigurationError(u"{}: {}".format(error_name, e)) - - -############################################################### -from ruamel.yaml.compat import PY2, PY3, text_type, string_types -from abc import * -import sys - -if PY3 and (sys.version_info[1] >= 4): - class AbstractValidator(ABC): - """AbstractValidator is the root Base class for any concrete implementation of entities - appearing in the general configuration file""" - - @abstractmethod - def validate(self, d): # TODO: FIXME: change API: return parsed value, throw exception if input is invalid! - pass -elif PY2 or PY3: - class AbstractValidator: - """AbstractValidator is the root Base class for any concrete implementation of entities - appearing in the general configuration file""" - __metaclass__ = ABCMeta - - @abstractmethod - def validate(self, d): - pass -# elif PY3: -# class AbstractValidator(metaclass=ABCMeta): -# """AbstractValidator is the root Base class for any concrete implementation of entities -# appearing in the general configuration file""" -# @abstractmethod -# def validate(self, d): -# pass -else: - raise NotImplementedError("Unsupported Python version: '{}'".format(sys.version_info)) - - -############################################################### -class Base(AbstractValidator): - """Abstract Base Class for the Config entities""" - - __version = [None] - - _parent = None - - _data = None - _default_data = None - - def __init__(self, parent): # TODO: add tag? here or in some child? - AbstractValidator.__init__(self) - assert self._parent is None - self._parent = parent - - @classmethod - def set_version(cls, v): - """To be set once only for any Validator class!""" - assert len(cls.__version) == 1 - assert cls.__version[0] is None - cls.__version[0] = v - - @classmethod - def get_version(cls, default=None): - assert len(cls.__version) == 1 - - if cls.__version[0] is not None: - return cls.__version[0] - - return default - - def set_data(self, d): - # assert self._data is None - # assert d is not None - self._data = d - - def get_data(self): - if self._data is None: - return self._default_data - - return self._data - - @classmethod - def parse(cls, d, parent=None): - self = cls(parent) - -# print(cls) -# print(parent) -# print(self) -# print(d) - - if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! - return self.get_data() - - # NOTE: .parse should! - raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) - - -############################################################### -class BaseRecord(Base): - """Aggregation of data as a record with some fixed data memebers""" - - # TODO: turn _default_type into a class-member (by moving it here)...? - - def __init__(self, parent): - Base.__init__(self, parent) - self._default_type = None # "default_base" - self._types = {} - self._create_optional = False - - - def detect_type(self, d): - """determine the type of variadic data for the format version""" - - assert not (self._default_type is None) - assert len(self._types) > 0 - - return self._default_type - - def detect_extra_rule(self, key, value): # Any extra unlisted keys in the mapping? - return None - - def validate(self, d): - # ! TODO: assert that d is a mapping with lc! - - _type = self.detect_type(d) - - assert not (_type is None) - assert _type in self._types - - _rule = self._types[_type] - - _ret = True - - _lc = d.lc # starting location of the mapping...? - (s, c) = (_lc.line, _lc.col) - - _d = {} - - for k in _rule.keys(): - r = _rule[k] - if r[0] and (k not in d): - _key_note(k, _lc, "ERROR: Missing mandatory key `{}` (type: '%s')" % (_type)) # Raise Exception? - _ret = False - # NOTE: the following will add all the missing default values - elif (not r[0]) and self._create_optional: # Optional Values should have some default values! - _d[k] = r[1](self).get_data() # NOTE: default value - no validation - - for offset, k in enumerate(d): - v = d.get(k) - l = s + offset # ?? - lc = (l, c) - - if k in _rule: - r = _rule[k][1](self) - - if not r.validate(v): # TODO: save to self! - _value_error(k, v, lc, "Error: invalid field '{}' value (type: '%s')" % _type) - _ret = False - - _d[k] = r.get_data() - else: - _extra_rule = self.detect_extra_rule(k, v) # (KeyValidator, ValueValidator) - - if _extra_rule is None: - _key_error(k, v, lc, "WARNING: Unhandled extra Key: '{}' (type: '%s')" % _type) - _ret = False - else: - _k = _extra_rule[0](self) - - if not _k.validate(k): - _key_error(k, v, lc, "Error: invalid key '{}' (type: '%s')" % _type) - _ret = False - else: - _v = _extra_rule[1](self) - if not _v.validate(v): # TODO: FIXME: wrong col (it was for key - not value)! - _value_error(k, v, lc, "Error: invalid field value '{}' value (type: '%s')" % _type) - _ret = False - else: - _d[_k.get_data()] = _v.get_data() - - if _ret: - self.set_data(_d) - - return _ret - - ############################################################### - - -class BaseScalar(Base): - """Single scalar value out of YAML scalars: strings, numbert etc.""" - - def __init__(self, parent): - Base.__init__(self, parent) - - def validate(self, d): - """check that data is a scalar: not a sequence or mapping or set""" - - if isinstance(d, (list, dict, tuple, set)): # ! Check if data is not a container? - print("ERROR: value: '{}' is not a scalar value!!" . format(d)) - return False - - self.set_data(d) - return True - - -############################################################### -class BaseString(BaseScalar): - """YAML String""" - def __init__(self, parent): - BaseScalar.__init__(self, parent) - - def validate(self, d): - """check whether data is a valid string. Note: should not care about format version""" - - s = BaseScalar.parse(d, parent=self) - - if not isinstance(s, string_types): - print("ERROR: value: '{}' is not a string!!" . format(d)) - return False - - self.set_data(text_type(d)) - return True - - -############################################################### -# import semver -import semantic_version # supports partial versions - - -class SemanticVersion(BaseString): - def __init__(self, parent): - BaseString.__init__(self, parent) - - def validate(self, d): - """check the string data to be a valid semantic verions""" - - _t = BaseString.parse(d, parent=self) - - _v = self.get_version(None) - try: -# if _v is None: # NOTE: the only initial validation: may be a partial version -# _v = semantic_version.Version(_t, partial=True) # TODO: check this! -# else: - _v = semantic_version.Version.parse(_t, partial=True, coerce=True) - except: - print("ERROR: wrong version data: '{0}' (see: '{1}')" . format(d, sys.exc_info())) - return False - - self.set_data(_v) - return True - - -############################################################### -class BaseUIString(BaseString): # visible to user => non empty! - def __init__(self, parent): - BaseString.__init__(self, parent) - - def validate(self, d): - """check whether data is a valid string""" - t = BaseString.parse(d, parent=self) - - if bool(t): # Non-empty - self.set_data(t) - return True - - return False - - -############################################################### -class BaseEnum(BaseString): # TODO: Generalize to not only strings...? - """Enumeration/collection of several fixed strings""" - - def __init__(self, parent): - BaseString.__init__(self, parent) - self._enum_list = [] # NOTE: will depend on the version... - - def validate(self, d): - """check whether data is in the list of fixed strings (see ._enum_list)""" - - t = BaseString.parse(d, parent=self) - - if not (t in self._enum_list): # check withing a list of possible string values - print("ERROR: string value: '{}' is not among known enum items!!".format(d)) - return False - - self.set_data(t) - return True - - -############################################################### -class ServiceType(BaseEnum): ## Q: Is 'Service::type' mandatory? default: 'compose' - def __init__(self, parent): - BaseEnum.__init__(self, parent) - - compose = 'compose' - self._enum_list = [compose] # NOTE: 'docker' and others may be possible later on - self._default_data = compose - - -############################################################### -class StationOMDTag(BaseEnum): ## Q: Is 'Station::omd_tag' mandatory? default: 'standalone' - def __init__(self, parent): - BaseEnum.__init__(self, parent) - - _v = 'standalone' - self._enum_list = ['agent', 'windows', _v] # possible values of omd_tag # will depend on format version! - self._default_data = _v - - -############################################################### -class StationPowerOnMethodType(BaseEnum): # Enum: [WOL], AMTvPRO, DockerMachine - def __init__(self, parent): - BaseEnum.__init__(self, parent) - - wol = 'WOL' - # NOTE: the list of possible values of PowerOnMethod::type (will depend on format version) - self._enum_list = [wol, 'DockerMachine'] # NOTE: 'AMTvPRO' and others may be possible later on - self._default_data = wol - - -############################################################### -import os - -if PY3: - from urllib.parse import urlparse - from urllib.request import urlopen -elif PY2: - from urlparse import urlparse - from urllib2 import urlopen - - -class URI(BaseString): - """Location of external file, either URL or local absolute or local relative to the input config file""" - - def __init__(self, parent): - BaseString.__init__(self, parent) - self._type = None - - def validate(self, d): - """check whether data is a valid URI""" - - v = BaseString.parse(d, parent=self) - - _ret = True - - if urlparse(v).scheme != "": - self._type = "url" - try: - urlopen(v).close() - except: - print("WARNING: URL: '{}' is not accessible!".format(v)) - _ret = not PEDANTIC - - # TODO: FIXME: base location should be the input file's dirname??? -# elif not os.path.isabs(v): -# v = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), v)) - - elif os.path.isfile(v): # Check whether file exists - self._type = "file" - - elif os.path.isdir(v): # Check whether directory exists - self._type = "dir" - - if not _ret: - print("WARNING: missing/unsupported resource location: {}".format(v)) - _ret = (not PEDANTIC) - - if _ret: - self.set_data(v) - - return _ret - -############################################################### -import re, tokenize - -if PY3: - def is_valid_id(k): - return k.isidentifier() -elif PY2: - def is_valid_id(k): - return re.match(tokenize.Name + '$', k) -else: - raise NotImplementedError("Unsupported Python version: '{}'".format(sys.version_info)) - -############################################################### -class BaseID(BaseString): - def __init__(self, parent): - BaseString.__init__(self, parent) - - def validate(self, d): - """check whether data is a valid ID string""" - - v = BaseString.parse(d, parent=self) - - if not is_valid_id(v): - print("ERROR: not a valid variable identifier! Input: '{}'" . format(d)) - return False - - self.set_data(v) - return True - -############################################################### -class ClientVariable(BaseID): # - def __init__(self, parent): - BaseID.__init__(self, parent) - - def validate(self, d): - """check whether data is a valid ID string""" - - v = BaseID.parse(d, parent=self) - - _ret = True - - if not (v == v.lower() or v == v.upper()): # ! Variables are all lower or upper case! - print("ERROR: a variable must be either in lower or upper case! Input: '{}'" . format(d)) - _ret = False - - # NOTE: starting with hilbert_ or HILBERT_ with letters, digits and '_'?? - if not re.match("^hilbert(_[a-z0-9]+)+$", v.lower()): - print("ERROR: variable must start with HILBERT/hilbert and contain words separated by underscores!" - " Input: '{}" .format(d)) - _ret = False - - if _ret: - self.set_data(v) - - return _ret - - -############################################################### -class ServiceID(BaseID): - def __init__(self, parent): - BaseID.__init__(self, parent) - - -############################################################### -class ApplicationID(BaseID): - def __init__(self, parent): - BaseID.__init__(self, parent) - - -############################################################### -class GroupID(BaseID): - def __init__(self, parent): - BaseID.__init__(self, parent) - - -############################################################### -class StationID(BaseID): - def __init__(self, parent): - BaseID.__init__(self, parent) - - -############################################################### -class ProfileID(BaseID): - def __init__(self, parent): - BaseID.__init__(self, parent) - - -############################################################### -class PresetID(BaseID): - def __init__(self, parent): - BaseID.__init__(self, parent) - - -############################################################### -import tempfile - -class AutoDetectionScript(BaseString): - def __init__(self, parent): - BaseString.__init__(self, parent) - self._default_data = '' - - def validate(self, d): - """check whether data is a valid script""" - script = BaseString.parse(d, parent=self) - - # NOTE: trying to check the BASH script: shellcheck & bash -n 'string': - fd, path = tempfile.mkstemp() - try: - with os.fdopen(fd, 'w') as tmp: -# print(script) - tmp.write(script) - - _cmd = ["bash", "-n", path] - try: - # NOTE: Check for valid bash script - subprocess.check_call(_cmd) # stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) - _ret = True - except: - print("WARNING: error running 'bash -n' to check '{0}' (exit code: {1})!" . format(text_type(script), sys.exc_info())) - _ret = not PEDANTIC # TODO: add a special switch? - - # NOTE: additionall tool: shellcheck (haskell!) - _cmd = ["shellcheck", "-s", "bash", path] - try: - # NOTE: Check for valid bash script - subprocess.check_call(_cmd) # stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) - _ret = True - except: - print("WARNING: error running 'shellcheck' to check '{0}' (exit code: {1})!".format(text_type(script), sys.exc_info())) - _ret = not PEDANTIC # TODO: add a special switch? - - finally: - os.remove(path) - - if _ret: - self.set_data(script) - - return True - - -############################################################### -class DockerComposeServiceName(BaseString): - def __init__(self, parent): - BaseString.__init__(self, parent) - - def validate(self, d): - """check whether data is a valid service name in file due to DockerComposeRef""" - - n = BaseString.parse(d, parent=self) - - self.set_data(n) - return True - -############################################################### -class DockerComposeRef(URI): - def __init__(self, parent): - URI.__init__(self, parent) - self._default_data = "docker-compose.yml" - - def validate(self, d): - """check whether data is a valid docker-compose file name""" - ref = URI.parse(d, parent=self) - self.set_data(ref) - return True - - # TODO: call docker-compose on the referenced file! in DockerService! - - -############################################################### -class Icon(URI): - def __init__(self, parent): - URI.__init__(self, parent) - - def validate(self, d): - """check whether data is a valid icon file name""" - ref = URI.parse(d, parent=self) - - # TODO: check the file contents (or extention) - - self.set_data(ref) - return True - - -############################################################### -import subprocess # , shlex - -class HostAddress(BaseString): - """SSH alias""" - - def __init__(self, parent): - BaseString.__init__(self, parent) - - def validate(self, d): - """check whether data is a valid ssh alias?""" - - _h = BaseString.parse(d, parent=self) - - _cmd = ["ssh", "-o", "ConnectTimeout=2", _h, "exit 0"] - try: - # NOTE: Check for ssh alias! - subprocess.check_call(_cmd, stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) - _ret = True - except subprocess.CalledProcessError as err: - print("WARNING: non-functional ssh alias: '{0}' => exit code: {1}!" . format(text_type(_h), err.returncode)) - _ret = not PEDANTIC # TODO: add a special switch? - except: # Any other exception is wrong... - print("WARNING: non-functional ssh alias: '{0}'. Moreover: Unexpected error: {1}" . format(text_type(_h), sys.exc_info())) - _ret = not PEDANTIC # TODO: add a special switch? - - if _ret: - self.set_data(_h) - - return _ret - -############################################################### -class HostMACAddress(BaseString): - """MAC Address of the station""" - - def __init__(self, parent): - BaseString.__init__(self, parent) - - def validate(self, d): - """check whether data is a valid ssh alias?""" - - v = BaseString.parse(d, parent=self) - - if not re.match("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", v.lower()): - _value_error(None, d, d.lc, "ERROR: Wrong MAC Address: [{}]") - return False - - # TODO: verify the existence of that MAC address? - self.set_data(v) - - return True - -############################################################### -class BaseBool(BaseScalar): - def __init__(self, parent): - BaseScalar.__init__(self, parent) - - def validate(self, d): - """check whether data is a valid string""" - ### TODO: Detect other YAML scalar types? - - if not isinstance(d, bool): - print("ERROR: not a boolean value: '{}'" . format(d)) - return False - - self.set_data(d) - return True - - -class StationVisibility(BaseBool): ## "hidden": True / [False] - def __init__(self, parent): - BaseBool.__init__(self, parent) - self._default_data = False - - -class AutoTurnon(BaseBool): # Bool, False - def __init__(self, parent): - BaseBool.__init__(self, parent) - self._default_data = False # no powering on by default!? - - -############################################################### -class VariadicRecordWrapper(Base): - """VariadicRecordWrapper record. Type is determined by the given 'type' field.""" - - def __init__(self, parent): - Base.__init__(self, parent) - - self._type_tag = "type" - self._type_cls = None - - self._default_type = None - self._types = {} - - def validate(self, d): - """determine the type of variadic data for the format version""" - - _ret = True - - assert self._default_type is not None - assert self._default_type in self._types - - _rule = self._types[self._default_type] # Version dependent! - assert _rule is not None - - assert self._type_cls is not None - - if self._type_tag not in d: - _lc = d.lc # start of the current mapping - _key_error(self._type_tag, d, _lc, "ERROR: Missing mandatory key `{}`") - return False - - t = self._type_cls.parse(d[self._type_tag], parent=self) - - if t not in _rule: - _lc = d.lc # start of the current mapping - _key_error(self._type_tag, t, _lc, "ERROR: unsupported/wrong variadic type: '{}'") - return False - - tt = _rule[t](self) - - if not tt.validate(d): - _lc = d.lc.key(self._type_tag) - _value_error('*', d, _lc, "ERROR: invalid mapping value '{}' for type '%s'" % t) - return False - - self.set_data(tt.get_data()) - return True - - -############################################################### -class StationPowerOnMethodWrapper(VariadicRecordWrapper): - """StationPowerOnMethod :: Wrapper""" - - def __init__(self, parent): - VariadicRecordWrapper.__init__(self, parent) - - T = StationPowerOnMethodType - self._type_cls = T - _wol = {T.parse("WOL"): WOL, T.parse("DockerMachine"): DockerMachine} - - self._default_type = "default_WOL_poweron_method_wrapper" - self._types[self._default_type] = _wol - - -############################################################### -class ServiceWrapper(VariadicRecordWrapper): - """Service :: Wrapper""" - - def __init__(self, parent): - VariadicRecordWrapper.__init__(self, parent) - - T = ServiceType - self._type_cls = T - _dc = {T.parse("compose"): DockerComposeService} - - self._default_type = "default_docker_compose_service_wrapper" - self._types[self._default_type] = _dc - - -############################################################### -class ApplicationWrapper(ServiceWrapper): - """Application :: Wrapper""" - - def __init__(self, parent): - ServiceWrapper.__init__(self, parent) - - T = ServiceType # same for docker-compose Services and Applications! - self._type_cls = T - _dc = {T.parse("compose"): DockerComposeApplication} - - self._default_type = "default_docker_compose_application_wrapper" - self._types[self._default_type] = _dc - - - - -############################################################### -class DockerMachine(BaseRecord): - """DockerMachine :: StationPowerOnMethod""" - - def __init__(self, parent): - BaseRecord.__init__(self, parent) - - self._type_tag = "type" - - self._default_type = "DockerMachine" - - DM_rule = { - self._type_tag: (True, StationPowerOnMethodType), # Mandatory! - "auto_turnon": (False, AutoTurnon), - "vm_name": (True, BaseString), - "vm_host_address": (True, HostAddress) - } - - self._types = {self._default_type: DM_rule} # ! NOTE: AMT - maybe later... - -class WOL(BaseRecord): - """WOL :: StationPowerOnMethod""" - - def __init__(self, parent): - BaseRecord.__init__(self, parent) - - self._type_tag = "type" - self._default_type = "WOL" - - WOL_rule = { - self._type_tag: (True, StationPowerOnMethodType), # Mandatory! - "auto_turnon": (False, AutoTurnon), - "mac": (True, HostMACAddress) - } - - self._types = {self._default_type: WOL_rule} - - -############################################################### -class DockerComposeService(BaseRecord): - """DockerCompose :: Service data type""" - - def __init__(self, parent): - BaseRecord.__init__(self, parent) - - self._type_tag = "type" - self._hook_tag = "auto_detections" - self._name_tag = "ref" - self._file_tag = "file" - - _compose_rule = { - self._type_tag: (True, ServiceType), # Mandatory - self._hook_tag: (False, AutoDetectionScript), - self._name_tag: (True, DockerComposeServiceName), - self._file_tag: (False, DockerComposeRef) - } - - self._default_type = "default_dc_service" - self._types = {self._default_type: _compose_rule} - self._create_optional = True - - def validate(self, d): - if not BaseRecord.validate(self, d): - assert self.get_data() is None - return False - - _d = self.get_data() - - _f = _d[self._file_tag] - - assert os.path.exists(_f) - - _n = _d[self._name_tag] - # TODO: Check the corresponding file for such a service -> Service in DockerService! - - DC = "docker-compose" - - fd, path = tempfile.mkstemp() - try: - with os.fdopen(fd, 'w') as tmp: - _cmd = [DC, "-f", _f, "config"] # TODO: use '--services'? - try: - subprocess.check_call(_cmd, stdout=tmp, stderr=open("/dev/null", 'w')) - _ret = True - except: - print("WARNING: error running '{}' to check '{}' (exit code: {})!".format(DC, _f, sys.exc_info())) - _ret = not PEDANTIC # TODO: add a special switch? - - with open(path, 'r') as tmp: - dc = load_yaml(tmp) - ss = None - for k in dc['services']: - if k == _n: - ss = dc['services'][k] - break - - if ss is None: - print("ERROR: missing service/application '{}' in file '{}' !".format(_n, _f)) - _ret = False - finally: -# print(path) - os.remove(path) - - return _ret - - -############################################################### -class DockerComposeApplication(DockerComposeService): - """DockerCompose :: Application""" - - def __init__(self, parent): - DockerComposeService.__init__(self, parent) - - _compose_rule = (self._types[self._default_type]).copy() - - _compose_rule.update({ - "name": (True, BaseUIString), # NOTE: name for UI! - "description": (True, BaseUIString), - "icon": (False, Icon), - "compatibleStations": (True, Group) - }) - - self._types[self._default_type] = _compose_rule - - -############################################################### -class Profile(BaseRecord): - """Profile""" - - def __init__(self, parent): - BaseRecord.__init__(self, parent) - - self._default_type = "default_profile" - - default_rule = { - "name": (True, BaseUIString), - "description": (True, BaseUIString), - "icon": (False, Icon), - "services": (True, ServiceList), - "supported_types": (False, ServiceTypeList) - } - - self._types = {self._default_type: default_rule} - - -############################################################### -class StationSSHOptions(BaseRecord): # optional: "Station::ssh_options" # record: user, port, key, key_ref - """StationSSHOptions""" - - def __init__(self, parent): - BaseRecord.__init__(self, parent) - - self._default_type = "default_station_ssh_options" - - default_rule = { - "user": (False, BaseString), - "key": (False, BaseString), - "port": (False, BaseString), - # TODO: BaseInt?? http://stackoverflow.com/questions/4187185/how-can-i-check-if-my-python-object-is-a-number - "key_ref": (False, URI), - } - - self._types = {self._default_type: default_rule} - - def validate(self, data): - """check whether data is a valid ssh connection options""" - - _ret = BaseRecord.validate(self, data) - - # TODO: Check for ssh connection: Use some Python SSH Wrapper (2/3) - return _ret - - -############################################################### -class Station(BaseRecord): - """Station""" - - def __init__(self, parent): - BaseRecord.__init__(self, parent) - - self._default_type = "default_station" - - default_rule = { - "name": (True, BaseUIString), - "description": (True, BaseUIString), - "icon": (False, Icon), - "extends": (False, StationID), - "profile": (True, ProfileID), - "address": (True, HostAddress), - "poweron_settings": (False, StationPowerOnMethodWrapper), # !! variadic, PowerOnType... - "ssh_options": (False, StationSSHOptions), # !!! record: user, port, key, key_ref - "omd_tag": (True, StationOMDTag), # ! like ServiceType: e.g. agent. Q: Is this mandatory? - "hidden": (False, StationVisibility), # Q: Is this mandatory? - "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) - } - - self._types = {self._default_type: default_rule} - - -############################################################### -class BaseIDMap(Base): - """Mapping: SomeTypeID -> AnyType""" - - def __init__(self, parent): - Base.__init__(self, parent) - self._default_type = None - self._types = {} # type -> (TypeID, Type) - - def detect_type(self, d): - """determine the type of variadic data for the format version""" - - assert not (self._default_type is None) - assert len(self._types) > 0 - - return self._default_type - - def validate(self, data): - _type = self.detect_type(data) - - assert not (_type is None) - assert _type in self._types - - (_id, _rule) = self._types[_type] - - _ret = True - - _lc = data.lc # starting position? - (s, c) = (_lc.line, _lc.col) - - _d = {} - for offset, k in enumerate(data): - v = data.get(k) # TODO: data[offset]??? - l = s + offset - _lc = (l, c) - - id = _id(self) - - if not id.validate(k): - _key_error(k, v, _lc, "Invalid Key ID: '{}' (type: '%s')" % (_type)) # Raise Exception? - _ret = False - else: - vv = _rule(self) - - if not vv.validate(v): - _value_error(k, v, _lc, "invalid value '{}' value (type: '%s')" % (_type)) # Raise Exception? - _ret = False - elif _ret: - _d[id.get_data()] = vv.get_data() - - if _ret: - self.set_data(_d) - - return _ret - - -############################################################### -class GlobalServices(BaseIDMap): - def __init__(self, parent): - BaseIDMap.__init__(self, parent) - self._default_type = "default_global_services" - self._types = {self._default_type: (ServiceID, ServiceWrapper)} - - # def validate(self, data): - # _ret = BaseID.validate(self, data) - # ### TODO: Any post processing? - # return _ret - - -############################################################### -class StationClientSettings( - BaseIDMap): # "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) - def __init__(self, parent): - BaseIDMap.__init__(self, parent) - self._default_type = "default_station_client_settings" - self._types = { - self._default_type: (ClientVariable, BaseScalar)} # ! TODO: only strings for now! More scalar types?! - - -############################################################### -class GlobalApplications(BaseIDMap): - def __init__(self, parent): - BaseIDMap.__init__(self, parent) - self._default_type = "default_global_applications" - self._types = {self._default_type: (ApplicationID, ApplicationWrapper)} - -############################################################### -class GlobalProfiles(BaseIDMap): - def __init__(self, parent): - BaseIDMap.__init__(self, parent) - self._default_type = "default_global_profiles" - self._types = {self._default_type: (ProfileID, Profile)} - - # def validate(self, data): - # _ret = BaseID.validate(self, data) - # ### TODO: Any post processing? - # return _ret - -def extend_dict(base, delta, _ext): - new = {} - - for k in base: - if k == _ext: - continue - - if k in delta: - v = delta.get(k, None) - - if v is None: - new[k] = base[k] - continue - - if k == 'client_settings': - t = base.get(k, {}).copy() - - assert isinstance(t, dict) - assert isinstance(v, dict) - - t.update(v) - new[k] = t - else: - new[k] = v # overwrite the rest - else: - new[k] = base[k] - - - for k in delta: - if not ((k == _ext) or (k in new)): - new[k] = delta[k] - - return new - -############################################################### -class GlobalStations(BaseIDMap): - def __init__(self, parent): - BaseIDMap.__init__(self, parent) - self._default_type = "default_global_stations" - self._types = {self._default_type: (StationID, Station)} - - def validate(self, d): - """Extension mechanism on top of the usual ID Mapping parsing""" - - if not BaseIDMap.validate(self, d): - return False - - _ext = 'extends' - - sts = self.get_data() - self.set_data(None) - - _ret = True - - _processed = {} - _todo = {} - for k in sts: - v = sts[k] - if v.get(_ext, None) is None: - _processed[k] = v - else: - _todo[k] = v - - _chg = True - while bool(_todo) and _chg: - _chg = False - _rest = {} - while bool(_todo): - k, v = _todo.popitem() - assert _ext in v - base = v[_ext] - if base in _processed: - _processed[k] = extend_dict(_processed[base], v, _ext) - _chg = True - else: - _rest[k] = v - _todo = _rest - - if bool(_todo): - print('ERROR: Cyclic dependencies between stations: {}!?' .format(_todo)) - _ret = False - - if _ret: - self.set_data(_processed) - - return _ret - - -############################################################### -class BaseList(Base): - """List of entities of the same type""" - - def __init__(self, parent): - Base.__init__(self, parent) - - def validate(self, d): - assert self._default_type is not None - assert len(self._types) > 0 - - # NOTE: determine the class of items based on the version and sample data - _type = self._types[self._default_type] - assert _type is not None - - if (not isinstance(d, (list, dict, tuple, set))) and isinstance(d, string_types): - try: - _d = _type.parse(BaseString.parse(d, parent=self), parent=self) - self.get_data(_d) - return True - except: - pass # Not a single string entry... - - # list!? - _d = [] - _ret = True - - for idx, i in enumerate(d): # What about a string? - _v = _type(self) - if not _v.validate(i): - _lc = d.lc - _value_error("[%d]" % idx, d, _lc, "Wrong item in the given sequence!") - _ret = False - else: - _d.insert(idx, _v.get_data()) # append? - - if _ret: - self.set_data(_d) - - return _ret - - -############################################################### -class GroupIDList(BaseList): - """List of GroupIDs or a single GroupID!""" - - def __init__(self, parent): - BaseList.__init__(self, parent) - - self._default_type = "default_GroupID_list" - self._types = {self._default_type: GroupID} - - -############################################################### -class ServiceList(BaseList): - """List of ServiceIDs or a single ServiceID!""" - - def __init__(self, parent): - BaseList.__init__(self, parent) - - self._default_type = "default_ServiceID_list" - self._types = {self._default_type: ServiceID} - - ############################################################### - - -class ServiceTypeList(BaseList): - """List of ServiceType's or a single ServiceType!""" - - def __init__(self, parent): - BaseList.__init__(self, parent) - - self._default_type = "default_ServiceType_list" - self._types = {self._default_type: ServiceType} - - -############################################################### -class Group(BaseRecord): # ? TODO: GroupSet & its .parent? - """Group""" - - def __init__(self, parent): - BaseRecord.__init__(self, parent) - - self._default_type = "default_group" - - self._include_tag = "include" - self._exclude_tag = "exclude" - self._intersectWith_tag = "intersectWith" - - default_rule = { - self._include_tag: (False, GroupIDList), - self._exclude_tag: (False, GroupIDList), - self._intersectWith_tag: (False, GroupIDList), - "name": (False, BaseUIString), - "description": (False, BaseUIString), - "icon": (False, Icon) - } - - self._types = {self._default_type: default_rule} - - def detect_extra_rule(self, key, value): # Any extra unlisted keys in the mapping? - if value is None: # Set item! - return (GroupID, BaseScalar) - return None - - def validate(self, data): - _ret = BaseRecord.validate(self, data) - # Add extra keys into include? - return _ret - - ############################################################### - - -class GlobalGroups(BaseIDMap): - def __init__(self, parent): - BaseIDMap.__init__(self, parent) - self._default_type = "default_global_groups" - self._types = {self._default_type: (GroupID, Group)} - - -############################################################### -class Preset(BaseRecord): - """Preset""" - - def __init__(self, parent): - BaseRecord.__init__(self, parent) - - self._default_type = "default_preset" - - # self.__tag = "Version" - default_rule = { - # self.__tag: (True , ??), # Mandatory - # self.__tag: (False, ??), # Optional - } - - self._types = {self._default_type: default_rule} - - raise NotImplementedError("Presets are not supported yet!") - - -############################################################### -class GlobalPresets(BaseIDMap): # Dummy for now! - def __init__(self, parent): - BaseIDMap.__init__(self, parent) - self._default_type = "default_global_presets" - self._types = {self._default_type: (PresetID, Preset)} - - def validate(self, data): - print("WARNING: Presets are not supported yet!") - # raise NotImplementedError("Presets are not supported yet!") - return True - - -############################################################### -class Global(BaseRecord): - """General Hilbert Configuration format""" - - def __init__(self, parent): - BaseRecord.__init__(self, parent) # This is the Main Root! - - self._default_type = "default_global" - - self._version_tag = "Version" - self._applications_tag = "Applications" - self._services_tag = "Services" - self._profiles_tag = "Profiles" - self._stations_tag = "Stations" - self._groups_tag = "Groups" - - ### explicit (optional) Type? - default_rule = { - self._version_tag: (True, SemanticVersion), # Mandatory, specifies supported Types of Config's Entity - self._services_tag: (True, GlobalServices), - self._applications_tag: (True, GlobalApplications), - self._profiles_tag: (True, GlobalProfiles), - self._stations_tag: (True, GlobalStations), - self._groups_tag: (False, GlobalGroups), # Optional - "Presets": (False, GlobalPresets), # Optional. May be removed! default? - } - - self._types = {self._default_type: default_rule} - - self._default_data = None - - @classmethod - def parse(cls, d, parent=None): - self = cls(parent) - - if self._version_tag not in d: - _key_note(self._version_tag, d.lc, "ERROR: Missing mandatory '{}' key field!") - raise ConfigurationError(u"{}: {}".format("ERROR:", "Missing version tag '{0}' in the input: '{1}'!".format(self._version_tag, d))) - - try: - _v = SemanticVersion.parse(d[self._version_tag], parent=self) - except: - _value_error(self._version_tag, d, d.lc, "Wrong value of global '{}' specification!") - raise - - self.set_version(_v) # NOTE: globally available now! - - if self.validate(d): - return self.get_data() - - return None - - def validate(self, data): - _ret = BaseRecord.validate(self, data) - - for offset, k in enumerate(data): - if k == self._version_tag: - if offset != 0: - print("Note: '{}' specified correctly but not ahead of everything else (offset: {})!".format( - self._version_tag, offset)) - _ret = False - break - - # NOTE: check uniqueness of keys among (Services/Applications): - _services = data.get(self._services_tag) # Rely on the above and use get_data? - _applications = data.get(self._applications_tag) - - for p, k in enumerate(_services): - _lc = _services.lc.key(k) - - if k in _applications: - print("Error: '{}' is both a ServiceID and an ApplicationID:".format(k)) - _key_error(k, _services[k], _lc, "Service key: {}") - - _alc = _applications.lc.key(k) - _key_error(k, _applications[k], _alc, "Application key: {}") - - # ! TODO: check Uniqueness of keys among (Profiles/Stations/Groups) !!!! - # ! TODO: check for GroupID <-> StationID <-> ProfileID - return _ret - - -############################################################### -def load_yaml_file(filename): - with open(filename, 'r') as fh: - return load_yaml(fh) - -# class Hilbert(object): - -def yaml_dump(d, stream=None): - print(yaml.round_trip_dump(d, stream=stream)) - -def parse(d, parent=None): - return Global.parse(d, parent=parent) - diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py deleted file mode 120000 index d235693..0000000 --- a/config/hilbert_cli_config.py +++ /dev/null @@ -1 +0,0 @@ -hilbert-cli-config.py \ No newline at end of file diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py new file mode 100644 index 0000000..814d91f --- /dev/null +++ b/config/hilbert_cli_config.py @@ -0,0 +1,1518 @@ +# -*- coding: utf-8 -*- +# encoding: utf-8 +# coding: utf-8 + +from __future__ import absolute_import, print_function, unicode_literals + +import logging +# log = logging.getLogger(__name__) + +PEDANTIC = False # NOTE: to treat invalid values/keys as errors? +INPUT_DIRNAME = './' +OUTPUT_DIRNAME = INPUT_DIRNAME + +############################################################### +up_arrow = '↑' + + +def _get_line_col(lc): + + if isinstance(lc, (list, tuple)): + l = lc[0] + c = lc[1] + else: + try: + l = lc.line + except: + print("Unexpected error: ", sys.exc_info()[0]) + print("Cannot get line out of: ", lc) + raise + + try: + c = lc.col + except: + try: + c = lc.column + except: + print("Unexpected error: ", sys.exc_info()[0]) + print("Cannot get col/column out of: ", lc) + raise + + return l, c + + +############################################################### +class ConfigurationError(Exception): + def __init__(self, msg): + self._msg = msg + +def _key_error(key, value, lc, error_message, e='K'): + (line, col) = _get_line_col(lc) + + if key is None: + key = '*' + + print('{}[line: {}, column: {}]: {}'.format(e, line + 1, col + 1, error_message.format(key))) + print('{}{}: {}'.format(' ' * col, key, value)) #! + # ! TODO: try to get access to original ruamel.yaml buffered lines...? + print('{}{}'.format(' ' * col, up_arrow)) + print('---') + + +def _key_note(key, lc, key_message, e='K'): + (line, col) = _get_line_col(lc) + + if key is None: + key = '*' + + print('{}[line: {}, column: {}]: {}'.format(e, line + 1, col + 1, key_message.format(key))) + print('---') + + +def _value_error(key, value, lc, error, e='E'): + (line, col) = _get_line_col(lc) + + if key is None: + key = '*' + + val_col = col + len(key) + 2 + print('{}[line: {}, column: {}]: {}'.format(e, line + 1, val_col + 1, error.format(key))) + print('{}{}: {}'.format(' ' * col, key, value)) #! + # ! TODO: try to get access to original ruamel.yaml buffered lines...? + print('{}{}'.format(' ' * val_col, up_arrow)) + print('---') + +# Unused??? +# def value_warning(key, value, lc, error): +# _value_error(key, value, lc, error, e='W') + + +############################################################### +import collections +import ruamel.yaml as yaml + +from ruamel.yaml.reader import Reader +from ruamel.yaml.scanner import RoundTripScanner # Scanner +from ruamel.yaml.parser import RoundTripParser # Parser, +from ruamel.yaml.composer import Composer +from ruamel.yaml.constructor import RoundTripConstructor # Constructor, SafeConstructor, +from ruamel.yaml.resolver import VersionedResolver # Resolver, +# from ruamel.yaml.nodes import MappingNode + + +############################################################### +class VerboseRoundTripConstructor(RoundTripConstructor): + def construct_mapping(self, node, maptyp, deep=False): + + m = RoundTripConstructor.construct_mapping(self, node, maptyp, deep=deep) # the actual construction! + + # additionally go through all nodes in the mapping to detect overwrites: + + starts = {} # already processed keys + locations and values + + for key_node, value_node in node.value: + # keys can be list -> deep + key = self.construct_object(key_node, deep=True) + + # lists are not hashable, but tuples are + if not isinstance(key, collections.Hashable): + if isinstance(key, list): + key = tuple(key) + + value = self.construct_object(value_node, deep=deep) + # TODO: check the lines above in the original Constructor.construct_mapping code for any changes/updates + + if key in starts: # Duplication detection + old = starts[key] + + print("WARNING: Key re-definition within some mapping: ") # mapping details? + _key_error(key, old[1], old[0], "Previous Value: ") + _key_error(key, value, key_node.start_mark, "New Value: ") + print('===') + + starts[key] = (key_node.start_mark, value) # in order to find all such problems! + + return m + + +############################################################### +class VerboseRoundTripLoader(Reader, RoundTripScanner, RoundTripParser, Composer, + VerboseRoundTripConstructor, VersionedResolver): + def __init__(self, stream, version=None, preserve_quotes=None): + Reader.__init__(self, stream) + RoundTripScanner.__init__(self) + RoundTripParser.__init__(self) + Composer.__init__(self) + VerboseRoundTripConstructor.__init__(self, preserve_quotes=preserve_quotes) + VersionedResolver.__init__(self, version) + + +############################################################### +def load_yaml(f, Loader=VerboseRoundTripLoader, version=(1, 2), preserve_quotes=True): + try: + return yaml.load(f, Loader=Loader, version=version, preserve_quotes=preserve_quotes) + except (IOError, yaml.YAMLError) as e: + error_name = getattr(e, '__module__', '') + '.' + e.__class__.__name__ + raise ConfigurationError(u"{}: {}".format(error_name, e)) + + +############################################################### +from ruamel.yaml.compat import PY2, PY3, text_type, string_types +from abc import * +import sys + +if PY3 and (sys.version_info[1] >= 4): + class AbstractValidator(ABC): + """AbstractValidator is the root Base class for any concrete implementation of entities + appearing in the general configuration file""" + + @abstractmethod + def validate(self, d): # TODO: FIXME: change API: return parsed value, throw exception if input is invalid! + pass +elif PY2 or PY3: + class AbstractValidator: + """AbstractValidator is the root Base class for any concrete implementation of entities + appearing in the general configuration file""" + __metaclass__ = ABCMeta + + @abstractmethod + def validate(self, d): + pass +# elif PY3: +# class AbstractValidator(metaclass=ABCMeta): +# """AbstractValidator is the root Base class for any concrete implementation of entities +# appearing in the general configuration file""" +# @abstractmethod +# def validate(self, d): +# pass +else: + raise NotImplementedError("Unsupported Python version: '{}'".format(sys.version_info)) + + +############################################################### +class Base(AbstractValidator): + """Abstract Base Class for the Config entities""" + + __version = [None] + + _parent = None + + _data = None + _default_data = None + + def __init__(self, parent): # TODO: add tag? here or in some child? + AbstractValidator.__init__(self) + assert self._parent is None + self._parent = parent + + @classmethod + def set_version(cls, v): + """To be set once only for any Validator class!""" + assert len(cls.__version) == 1 + assert cls.__version[0] is None + cls.__version[0] = v + + @classmethod + def get_version(cls, default=None): + assert len(cls.__version) == 1 + + if cls.__version[0] is not None: + return cls.__version[0] + + return default + + def set_data(self, d): + # assert self._data is None + # assert d is not None + self._data = d + + def get_data(self): + if self._data is None: + return self._default_data + + return self._data + + @classmethod + def parse(cls, d, parent=None): + self = cls(parent) + +# print(cls) +# print(parent) +# print(self) +# print(d) + + if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! + return self.get_data() + + # NOTE: .parse should! + raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) + + +############################################################### +class BaseRecord(Base): + """Aggregation of data as a record with some fixed data memebers""" + + # TODO: turn _default_type into a class-member (by moving it here)...? + + def __init__(self, parent): + Base.__init__(self, parent) + self._default_type = None # "default_base" + self._types = {} + self._create_optional = False + + + def detect_type(self, d): + """determine the type of variadic data for the format version""" + + assert not (self._default_type is None) + assert len(self._types) > 0 + + return self._default_type + + def detect_extra_rule(self, key, value): # Any extra unlisted keys in the mapping? + return None + + def validate(self, d): + # ! TODO: assert that d is a mapping with lc! + + _type = self.detect_type(d) + + assert not (_type is None) + assert _type in self._types + + _rule = self._types[_type] + + _ret = True + + _lc = d.lc # starting location of the mapping...? + (s, c) = (_lc.line, _lc.col) + + _d = {} + + for k in _rule.keys(): + r = _rule[k] + if r[0] and (k not in d): + _key_note(k, _lc, "ERROR: Missing mandatory key `{}` (type: '%s')" % (_type)) # Raise Exception? + _ret = False + # NOTE: the following will add all the missing default values + elif (not r[0]) and self._create_optional: # Optional Values should have some default values! + _d[k] = r[1](self).get_data() # NOTE: default value - no validation + + for offset, k in enumerate(d): + v = d.get(k) + l = s + offset # ?? + lc = (l, c) + + if k in _rule: + r = _rule[k][1](self) + + if not r.validate(v): # TODO: save to self! + _value_error(k, v, lc, "Error: invalid field '{}' value (type: '%s')" % _type) + _ret = False + + _d[k] = r.get_data() + else: + _extra_rule = self.detect_extra_rule(k, v) # (KeyValidator, ValueValidator) + + if _extra_rule is None: + _key_error(k, v, lc, "WARNING: Unhandled extra Key: '{}' (type: '%s')" % _type) + _ret = False + else: + _k = _extra_rule[0](self) + + if not _k.validate(k): + _key_error(k, v, lc, "Error: invalid key '{}' (type: '%s')" % _type) + _ret = False + else: + _v = _extra_rule[1](self) + if not _v.validate(v): # TODO: FIXME: wrong col (it was for key - not value)! + _value_error(k, v, lc, "Error: invalid field value '{}' value (type: '%s')" % _type) + _ret = False + else: + _d[_k.get_data()] = _v.get_data() + + if _ret: + self.set_data(_d) + + return _ret + + ############################################################### + + +class BaseScalar(Base): + """Single scalar value out of YAML scalars: strings, numbert etc.""" + + def __init__(self, parent): + Base.__init__(self, parent) + + def validate(self, d): + """check that data is a scalar: not a sequence or mapping or set""" + + if isinstance(d, (list, dict, tuple, set)): # ! Check if data is not a container? + print("ERROR: value: '{}' is not a scalar value!!" . format(d)) + return False + + self.set_data(d) + return True + + +############################################################### +class BaseString(BaseScalar): + """YAML String""" + def __init__(self, parent): + BaseScalar.__init__(self, parent) + + def validate(self, d): + """check whether data is a valid string. Note: should not care about format version""" + + s = BaseScalar.parse(d, parent=self) + + if not isinstance(s, string_types): + print("ERROR: value: '{}' is not a string!!" . format(d)) + return False + + self.set_data(text_type(d)) + return True + + +############################################################### +# import semver +import semantic_version # supports partial versions + + +class SemanticVersion(BaseString): + def __init__(self, parent): + BaseString.__init__(self, parent) + + def validate(self, d): + """check the string data to be a valid semantic verions""" + + _t = BaseString.parse(d, parent=self) + + _v = self.get_version(None) + try: +# if _v is None: # NOTE: the only initial validation: may be a partial version +# _v = semantic_version.Version(_t, partial=True) # TODO: check this! +# else: + _v = semantic_version.Version.parse(_t, partial=True, coerce=True) + except: + print("ERROR: wrong version data: '{0}' (see: '{1}')" . format(d, sys.exc_info())) + return False + + self.set_data(_v) + return True + + +############################################################### +class BaseUIString(BaseString): # visible to user => non empty! + def __init__(self, parent): + BaseString.__init__(self, parent) + + def validate(self, d): + """check whether data is a valid string""" + t = BaseString.parse(d, parent=self) + + if bool(t): # Non-empty + self.set_data(t) + return True + + return False + + +############################################################### +class BaseEnum(BaseString): # TODO: Generalize to not only strings...? + """Enumeration/collection of several fixed strings""" + + def __init__(self, parent): + BaseString.__init__(self, parent) + self._enum_list = [] # NOTE: will depend on the version... + + def validate(self, d): + """check whether data is in the list of fixed strings (see ._enum_list)""" + + t = BaseString.parse(d, parent=self) + + if not (t in self._enum_list): # check withing a list of possible string values + print("ERROR: string value: '{}' is not among known enum items!!".format(d)) + return False + + self.set_data(t) + return True + + +############################################################### +class ServiceType(BaseEnum): ## Q: Is 'Service::type' mandatory? default: 'compose' + def __init__(self, parent): + BaseEnum.__init__(self, parent) + + compose = 'compose' + self._enum_list = [compose] # NOTE: 'docker' and others may be possible later on + self._default_data = compose + + +############################################################### +class StationOMDTag(BaseEnum): ## Q: Is 'Station::omd_tag' mandatory? default: 'standalone' + def __init__(self, parent): + BaseEnum.__init__(self, parent) + + _v = 'standalone' + self._enum_list = ['agent', 'windows', _v] # possible values of omd_tag # will depend on format version! + self._default_data = _v + + +############################################################### +class StationPowerOnMethodType(BaseEnum): # Enum: [WOL], AMTvPRO, DockerMachine + def __init__(self, parent): + BaseEnum.__init__(self, parent) + + wol = 'WOL' + # NOTE: the list of possible values of PowerOnMethod::type (will depend on format version) + self._enum_list = [wol, 'DockerMachine'] # NOTE: 'AMTvPRO' and others may be possible later on + self._default_data = wol + + +############################################################### +import os + +if PY3: + from urllib.parse import urlparse + from urllib.request import urlopen +elif PY2: + from urlparse import urlparse + from urllib2 import urlopen + + +class URI(BaseString): + """Location of external file, either URL or local absolute or local relative to the input config file""" + + def __init__(self, parent): + BaseString.__init__(self, parent) + self._type = None + + def validate(self, d): + """check whether data is a valid URI""" + + v = BaseString.parse(d, parent=self) + + _ret = True + + if urlparse(v).scheme != "": + self._type = "url" + try: + urlopen(v).close() + except: + print("WARNING: URL: '{}' is not accessible!".format(v)) + _ret = not PEDANTIC + + # TODO: FIXME: base location should be the input file's dirname??? +# elif not os.path.isabs(v): +# v = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), v)) + + elif os.path.isfile(v): # Check whether file exists + self._type = "file" + + elif os.path.isdir(v): # Check whether directory exists + self._type = "dir" + + if not _ret: + print("WARNING: missing/unsupported resource location: {}".format(v)) + _ret = (not PEDANTIC) + + if _ret: + self.set_data(v) + + return _ret + +############################################################### +import re, tokenize + +if PY3: + def is_valid_id(k): + return k.isidentifier() +elif PY2: + def is_valid_id(k): + return re.match(tokenize.Name + '$', k) +else: + raise NotImplementedError("Unsupported Python version: '{}'".format(sys.version_info)) + +############################################################### +class BaseID(BaseString): + def __init__(self, parent): + BaseString.__init__(self, parent) + + def validate(self, d): + """check whether data is a valid ID string""" + + v = BaseString.parse(d, parent=self) + + if not is_valid_id(v): + print("ERROR: not a valid variable identifier! Input: '{}'" . format(d)) + return False + + self.set_data(v) + return True + +############################################################### +class ClientVariable(BaseID): # + def __init__(self, parent): + BaseID.__init__(self, parent) + + def validate(self, d): + """check whether data is a valid ID string""" + + v = BaseID.parse(d, parent=self) + + _ret = True + + if not (v == v.lower() or v == v.upper()): # ! Variables are all lower or upper case! + print("ERROR: a variable must be either in lower or upper case! Input: '{}'" . format(d)) + _ret = False + + # NOTE: starting with hilbert_ or HILBERT_ with letters, digits and '_'?? + if not re.match("^hilbert(_[a-z0-9]+)+$", v.lower()): + print("ERROR: variable must start with HILBERT/hilbert and contain words separated by underscores!" + " Input: '{}" .format(d)) + _ret = False + + if _ret: + self.set_data(v) + + return _ret + + +############################################################### +class ServiceID(BaseID): + def __init__(self, parent): + BaseID.__init__(self, parent) + + +############################################################### +class ApplicationID(BaseID): + def __init__(self, parent): + BaseID.__init__(self, parent) + + +############################################################### +class GroupID(BaseID): + def __init__(self, parent): + BaseID.__init__(self, parent) + + +############################################################### +class StationID(BaseID): + def __init__(self, parent): + BaseID.__init__(self, parent) + + +############################################################### +class ProfileID(BaseID): + def __init__(self, parent): + BaseID.__init__(self, parent) + + +############################################################### +class PresetID(BaseID): + def __init__(self, parent): + BaseID.__init__(self, parent) + + +############################################################### +import tempfile + +class AutoDetectionScript(BaseString): + def __init__(self, parent): + BaseString.__init__(self, parent) + self._default_data = '' + + def validate(self, d): + """check whether data is a valid script""" + script = BaseString.parse(d, parent=self) + + # NOTE: trying to check the BASH script: shellcheck & bash -n 'string': + fd, path = tempfile.mkstemp() + try: + with os.fdopen(fd, 'w') as tmp: +# print(script) + tmp.write(script) + + _cmd = ["bash", "-n", path] + try: + # NOTE: Check for valid bash script + subprocess.check_call(_cmd) # stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) + _ret = True + except: + print("WARNING: error running 'bash -n' to check '{0}' (exit code: {1})!" . format(text_type(script), sys.exc_info())) + _ret = not PEDANTIC # TODO: add a special switch? + + # NOTE: additionall tool: shellcheck (haskell!) + _cmd = ["shellcheck", "-s", "bash", path] + try: + # NOTE: Check for valid bash script + subprocess.check_call(_cmd) # stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) + _ret = True + except: + print("WARNING: error running 'shellcheck' to check '{0}' (exit code: {1})!".format(text_type(script), sys.exc_info())) + _ret = not PEDANTIC # TODO: add a special switch? + + finally: + os.remove(path) + + if _ret: + self.set_data(script) + + return True + + +############################################################### +class DockerComposeServiceName(BaseString): + def __init__(self, parent): + BaseString.__init__(self, parent) + + def validate(self, d): + """check whether data is a valid service name in file due to DockerComposeRef""" + + n = BaseString.parse(d, parent=self) + + self.set_data(n) + return True + +############################################################### +class DockerComposeRef(URI): + def __init__(self, parent): + URI.__init__(self, parent) + self._default_data = "docker-compose.yml" + + def validate(self, d): + """check whether data is a valid docker-compose file name""" + ref = URI.parse(d, parent=self) + self.set_data(ref) + return True + + # TODO: call docker-compose on the referenced file! in DockerService! + + +############################################################### +class Icon(URI): + def __init__(self, parent): + URI.__init__(self, parent) + + def validate(self, d): + """check whether data is a valid icon file name""" + ref = URI.parse(d, parent=self) + + # TODO: check the file contents (or extention) + + self.set_data(ref) + return True + + +############################################################### +import subprocess # , shlex + +class HostAddress(BaseString): + """SSH alias""" + + def __init__(self, parent): + BaseString.__init__(self, parent) + + def validate(self, d): + """check whether data is a valid ssh alias?""" + + _h = BaseString.parse(d, parent=self) + + _cmd = ["ssh", "-o", "ConnectTimeout=2", _h, "exit 0"] + try: + # NOTE: Check for ssh alias! + subprocess.check_call(_cmd, stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) + _ret = True + except subprocess.CalledProcessError as err: + print("WARNING: non-functional ssh alias: '{0}' => exit code: {1}!" . format(text_type(_h), err.returncode)) + _ret = not PEDANTIC # TODO: add a special switch? + except: # Any other exception is wrong... + print("WARNING: non-functional ssh alias: '{0}'. Moreover: Unexpected error: {1}" . format(text_type(_h), sys.exc_info())) + _ret = not PEDANTIC # TODO: add a special switch? + + if _ret: + self.set_data(_h) + + return _ret + +############################################################### +class HostMACAddress(BaseString): + """MAC Address of the station""" + + def __init__(self, parent): + BaseString.__init__(self, parent) + + def validate(self, d): + """check whether data is a valid ssh alias?""" + + v = BaseString.parse(d, parent=self) + + if not re.match("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", v.lower()): + _value_error(None, d, d.lc, "ERROR: Wrong MAC Address: [{}]") + return False + + # TODO: verify the existence of that MAC address? + self.set_data(v) + + return True + +############################################################### +class BaseBool(BaseScalar): + def __init__(self, parent): + BaseScalar.__init__(self, parent) + + def validate(self, d): + """check whether data is a valid string""" + ### TODO: Detect other YAML scalar types? + + if not isinstance(d, bool): + print("ERROR: not a boolean value: '{}'" . format(d)) + return False + + self.set_data(d) + return True + + +class StationVisibility(BaseBool): ## "hidden": True / [False] + def __init__(self, parent): + BaseBool.__init__(self, parent) + self._default_data = False + + +class AutoTurnon(BaseBool): # Bool, False + def __init__(self, parent): + BaseBool.__init__(self, parent) + self._default_data = False # no powering on by default!? + + +############################################################### +class VariadicRecordWrapper(Base): + """VariadicRecordWrapper record. Type is determined by the given 'type' field.""" + + def __init__(self, parent): + Base.__init__(self, parent) + + self._type_tag = "type" + self._type_cls = None + + self._default_type = None + self._types = {} + + def validate(self, d): + """determine the type of variadic data for the format version""" + + _ret = True + + assert self._default_type is not None + assert self._default_type in self._types + + _rule = self._types[self._default_type] # Version dependent! + assert _rule is not None + + assert self._type_cls is not None + + if self._type_tag not in d: + _lc = d.lc # start of the current mapping + _key_error(self._type_tag, d, _lc, "ERROR: Missing mandatory key `{}`") + return False + + t = self._type_cls.parse(d[self._type_tag], parent=self) + + if t not in _rule: + _lc = d.lc # start of the current mapping + _key_error(self._type_tag, t, _lc, "ERROR: unsupported/wrong variadic type: '{}'") + return False + + tt = _rule[t](self) + + if not tt.validate(d): + _lc = d.lc.key(self._type_tag) + _value_error('*', d, _lc, "ERROR: invalid mapping value '{}' for type '%s'" % t) + return False + + self.set_data(tt.get_data()) + return True + + +############################################################### +class StationPowerOnMethodWrapper(VariadicRecordWrapper): + """StationPowerOnMethod :: Wrapper""" + + def __init__(self, parent): + VariadicRecordWrapper.__init__(self, parent) + + T = StationPowerOnMethodType + self._type_cls = T + _wol = {T.parse("WOL"): WOL, T.parse("DockerMachine"): DockerMachine} + + self._default_type = "default_WOL_poweron_method_wrapper" + self._types[self._default_type] = _wol + + +############################################################### +class ServiceWrapper(VariadicRecordWrapper): + """Service :: Wrapper""" + + def __init__(self, parent): + VariadicRecordWrapper.__init__(self, parent) + + T = ServiceType + self._type_cls = T + _dc = {T.parse("compose"): DockerComposeService} + + self._default_type = "default_docker_compose_service_wrapper" + self._types[self._default_type] = _dc + + +############################################################### +class ApplicationWrapper(ServiceWrapper): + """Application :: Wrapper""" + + def __init__(self, parent): + ServiceWrapper.__init__(self, parent) + + T = ServiceType # same for docker-compose Services and Applications! + self._type_cls = T + _dc = {T.parse("compose"): DockerComposeApplication} + + self._default_type = "default_docker_compose_application_wrapper" + self._types[self._default_type] = _dc + + + + +############################################################### +class DockerMachine(BaseRecord): + """DockerMachine :: StationPowerOnMethod""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._type_tag = "type" + + self._default_type = "DockerMachine" + + DM_rule = { + self._type_tag: (True, StationPowerOnMethodType), # Mandatory! + "auto_turnon": (False, AutoTurnon), + "vm_name": (True, BaseString), + "vm_host_address": (True, HostAddress) + } + + self._types = {self._default_type: DM_rule} # ! NOTE: AMT - maybe later... + +class WOL(BaseRecord): + """WOL :: StationPowerOnMethod""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._type_tag = "type" + self._default_type = "WOL" + + WOL_rule = { + self._type_tag: (True, StationPowerOnMethodType), # Mandatory! + "auto_turnon": (False, AutoTurnon), + "mac": (True, HostMACAddress) + } + + self._types = {self._default_type: WOL_rule} + + +############################################################### +class DockerComposeService(BaseRecord): + """DockerCompose :: Service data type""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._type_tag = "type" + self._hook_tag = "auto_detections" + self._name_tag = "ref" + self._file_tag = "file" + + _compose_rule = { + self._type_tag: (True, ServiceType), # Mandatory + self._hook_tag: (False, AutoDetectionScript), + self._name_tag: (True, DockerComposeServiceName), + self._file_tag: (False, DockerComposeRef) + } + + self._default_type = "default_dc_service" + self._types = {self._default_type: _compose_rule} + self._create_optional = True + + def validate(self, d): + if not BaseRecord.validate(self, d): + assert self.get_data() is None + return False + + _d = self.get_data() + + _f = _d[self._file_tag] + + assert os.path.exists(_f) + + _n = _d[self._name_tag] + # TODO: Check the corresponding file for such a service -> Service in DockerService! + + DC = "docker-compose" + + fd, path = tempfile.mkstemp() + try: + with os.fdopen(fd, 'w') as tmp: + _cmd = [DC, "-f", _f, "config"] # TODO: use '--services'? + try: + subprocess.check_call(_cmd, stdout=tmp, stderr=open("/dev/null", 'w')) + _ret = True + except: + print("WARNING: error running '{}' to check '{}' (exit code: {})!".format(DC, _f, sys.exc_info())) + _ret = not PEDANTIC # TODO: add a special switch? + + with open(path, 'r') as tmp: + dc = load_yaml(tmp) + ss = None + for k in dc['services']: + if k == _n: + ss = dc['services'][k] + break + + if ss is None: + print("ERROR: missing service/application '{}' in file '{}' !".format(_n, _f)) + _ret = False + finally: +# print(path) + os.remove(path) + + return _ret + + +############################################################### +class DockerComposeApplication(DockerComposeService): + """DockerCompose :: Application""" + + def __init__(self, parent): + DockerComposeService.__init__(self, parent) + + _compose_rule = (self._types[self._default_type]).copy() + + _compose_rule.update({ + "name": (True, BaseUIString), # NOTE: name for UI! + "description": (True, BaseUIString), + "icon": (False, Icon), + "compatibleStations": (True, Group) + }) + + self._types[self._default_type] = _compose_rule + + +############################################################### +class Profile(BaseRecord): + """Profile""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._default_type = "default_profile" + + default_rule = { + "name": (True, BaseUIString), + "description": (True, BaseUIString), + "icon": (False, Icon), + "services": (True, ServiceList), + "supported_types": (False, ServiceTypeList) + } + + self._types = {self._default_type: default_rule} + + +############################################################### +class StationSSHOptions(BaseRecord): # optional: "Station::ssh_options" # record: user, port, key, key_ref + """StationSSHOptions""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._default_type = "default_station_ssh_options" + + default_rule = { + "user": (False, BaseString), + "key": (False, BaseString), + "port": (False, BaseString), + # TODO: BaseInt?? http://stackoverflow.com/questions/4187185/how-can-i-check-if-my-python-object-is-a-number + "key_ref": (False, URI), + } + + self._types = {self._default_type: default_rule} + + def validate(self, data): + """check whether data is a valid ssh connection options""" + + _ret = BaseRecord.validate(self, data) + + # TODO: Check for ssh connection: Use some Python SSH Wrapper (2/3) + return _ret + + +############################################################### +class Station(BaseRecord): + """Station""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._default_type = "default_station" + + default_rule = { + "name": (True, BaseUIString), + "description": (True, BaseUIString), + "icon": (False, Icon), + "extends": (False, StationID), + "profile": (True, ProfileID), + "address": (True, HostAddress), + "poweron_settings": (False, StationPowerOnMethodWrapper), # !! variadic, PowerOnType... + "ssh_options": (False, StationSSHOptions), # !!! record: user, port, key, key_ref + "omd_tag": (True, StationOMDTag), # ! like ServiceType: e.g. agent. Q: Is this mandatory? + "hidden": (False, StationVisibility), # Q: Is this mandatory? + "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) + } + + self._types = {self._default_type: default_rule} + + +############################################################### +class BaseIDMap(Base): + """Mapping: SomeTypeID -> AnyType""" + + def __init__(self, parent): + Base.__init__(self, parent) + self._default_type = None + self._types = {} # type -> (TypeID, Type) + + def detect_type(self, d): + """determine the type of variadic data for the format version""" + + assert not (self._default_type is None) + assert len(self._types) > 0 + + return self._default_type + + def validate(self, data): + _type = self.detect_type(data) + + assert not (_type is None) + assert _type in self._types + + (_id, _rule) = self._types[_type] + + _ret = True + + _lc = data.lc # starting position? + (s, c) = (_lc.line, _lc.col) + + _d = {} + for offset, k in enumerate(data): + v = data.get(k) # TODO: data[offset]??? + l = s + offset + _lc = (l, c) + + id = _id(self) + + if not id.validate(k): + _key_error(k, v, _lc, "Invalid Key ID: '{}' (type: '%s')" % (_type)) # Raise Exception? + _ret = False + else: + vv = _rule(self) + + if not vv.validate(v): + _value_error(k, v, _lc, "invalid value '{}' value (type: '%s')" % (_type)) # Raise Exception? + _ret = False + elif _ret: + _d[id.get_data()] = vv.get_data() + + if _ret: + self.set_data(_d) + + return _ret + + +############################################################### +class GlobalServices(BaseIDMap): + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_global_services" + self._types = {self._default_type: (ServiceID, ServiceWrapper)} + + # def validate(self, data): + # _ret = BaseID.validate(self, data) + # ### TODO: Any post processing? + # return _ret + + +############################################################### +class StationClientSettings( + BaseIDMap): # "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_station_client_settings" + self._types = { + self._default_type: (ClientVariable, BaseScalar)} # ! TODO: only strings for now! More scalar types?! + + +############################################################### +class GlobalApplications(BaseIDMap): + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_global_applications" + self._types = {self._default_type: (ApplicationID, ApplicationWrapper)} + +############################################################### +class GlobalProfiles(BaseIDMap): + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_global_profiles" + self._types = {self._default_type: (ProfileID, Profile)} + + # def validate(self, data): + # _ret = BaseID.validate(self, data) + # ### TODO: Any post processing? + # return _ret + +def extend_dict(base, delta, _ext): + new = {} + + for k in base: + if k == _ext: + continue + + if k in delta: + v = delta.get(k, None) + + if v is None: + new[k] = base[k] + continue + + if k == 'client_settings': + t = base.get(k, {}).copy() + + assert isinstance(t, dict) + assert isinstance(v, dict) + + t.update(v) + new[k] = t + else: + new[k] = v # overwrite the rest + else: + new[k] = base[k] + + + for k in delta: + if not ((k == _ext) or (k in new)): + new[k] = delta[k] + + return new + +############################################################### +class GlobalStations(BaseIDMap): + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_global_stations" + self._types = {self._default_type: (StationID, Station)} + + def validate(self, d): + """Extension mechanism on top of the usual ID Mapping parsing""" + + if not BaseIDMap.validate(self, d): + return False + + _ext = 'extends' + + sts = self.get_data() + self.set_data(None) + + _ret = True + + _processed = {} + _todo = {} + for k in sts: + v = sts[k] + if v.get(_ext, None) is None: + _processed[k] = v + else: + _todo[k] = v + + _chg = True + while bool(_todo) and _chg: + _chg = False + _rest = {} + while bool(_todo): + k, v = _todo.popitem() + assert _ext in v + base = v[_ext] + if base in _processed: + _processed[k] = extend_dict(_processed[base], v, _ext) + _chg = True + else: + _rest[k] = v + _todo = _rest + + if bool(_todo): + print('ERROR: Cyclic dependencies between stations: {}!?' .format(_todo)) + _ret = False + + if _ret: + self.set_data(_processed) + + return _ret + + +############################################################### +class BaseList(Base): + """List of entities of the same type""" + + def __init__(self, parent): + Base.__init__(self, parent) + + def validate(self, d): + assert self._default_type is not None + assert len(self._types) > 0 + + # NOTE: determine the class of items based on the version and sample data + _type = self._types[self._default_type] + assert _type is not None + + if (not isinstance(d, (list, dict, tuple, set))) and isinstance(d, string_types): + try: + _d = _type.parse(BaseString.parse(d, parent=self), parent=self) + self.get_data(_d) + return True + except: + pass # Not a single string entry... + + # list!? + _d = [] + _ret = True + + for idx, i in enumerate(d): # What about a string? + _v = _type(self) + if not _v.validate(i): + _lc = d.lc + _value_error("[%d]" % idx, d, _lc, "Wrong item in the given sequence!") + _ret = False + else: + _d.insert(idx, _v.get_data()) # append? + + if _ret: + self.set_data(_d) + + return _ret + + +############################################################### +class GroupIDList(BaseList): + """List of GroupIDs or a single GroupID!""" + + def __init__(self, parent): + BaseList.__init__(self, parent) + + self._default_type = "default_GroupID_list" + self._types = {self._default_type: GroupID} + + +############################################################### +class ServiceList(BaseList): + """List of ServiceIDs or a single ServiceID!""" + + def __init__(self, parent): + BaseList.__init__(self, parent) + + self._default_type = "default_ServiceID_list" + self._types = {self._default_type: ServiceID} + + ############################################################### + + +class ServiceTypeList(BaseList): + """List of ServiceType's or a single ServiceType!""" + + def __init__(self, parent): + BaseList.__init__(self, parent) + + self._default_type = "default_ServiceType_list" + self._types = {self._default_type: ServiceType} + + +############################################################### +class Group(BaseRecord): # ? TODO: GroupSet & its .parent? + """Group""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._default_type = "default_group" + + self._include_tag = "include" + self._exclude_tag = "exclude" + self._intersectWith_tag = "intersectWith" + + default_rule = { + self._include_tag: (False, GroupIDList), + self._exclude_tag: (False, GroupIDList), + self._intersectWith_tag: (False, GroupIDList), + "name": (False, BaseUIString), + "description": (False, BaseUIString), + "icon": (False, Icon) + } + + self._types = {self._default_type: default_rule} + + def detect_extra_rule(self, key, value): # Any extra unlisted keys in the mapping? + if value is None: # Set item! + return (GroupID, BaseScalar) + return None + + def validate(self, data): + _ret = BaseRecord.validate(self, data) + # Add extra keys into include? + return _ret + + ############################################################### + + +class GlobalGroups(BaseIDMap): + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_global_groups" + self._types = {self._default_type: (GroupID, Group)} + + +############################################################### +class Preset(BaseRecord): + """Preset""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) + + self._default_type = "default_preset" + + # self.__tag = "Version" + default_rule = { + # self.__tag: (True , ??), # Mandatory + # self.__tag: (False, ??), # Optional + } + + self._types = {self._default_type: default_rule} + + raise NotImplementedError("Presets are not supported yet!") + + +############################################################### +class GlobalPresets(BaseIDMap): # Dummy for now! + def __init__(self, parent): + BaseIDMap.__init__(self, parent) + self._default_type = "default_global_presets" + self._types = {self._default_type: (PresetID, Preset)} + + def validate(self, data): + print("WARNING: Presets are not supported yet!") + # raise NotImplementedError("Presets are not supported yet!") + return True + + +############################################################### +class Global(BaseRecord): + """General Hilbert Configuration format""" + + def __init__(self, parent): + BaseRecord.__init__(self, parent) # This is the Main Root! + + self._default_type = "default_global" + + self._version_tag = "Version" + self._applications_tag = "Applications" + self._services_tag = "Services" + self._profiles_tag = "Profiles" + self._stations_tag = "Stations" + self._groups_tag = "Groups" + + ### explicit (optional) Type? + default_rule = { + self._version_tag: (True, SemanticVersion), # Mandatory, specifies supported Types of Config's Entity + self._services_tag: (True, GlobalServices), + self._applications_tag: (True, GlobalApplications), + self._profiles_tag: (True, GlobalProfiles), + self._stations_tag: (True, GlobalStations), + self._groups_tag: (False, GlobalGroups), # Optional + "Presets": (False, GlobalPresets), # Optional. May be removed! default? + } + + self._types = {self._default_type: default_rule} + + self._default_data = None + + @classmethod + def parse(cls, d, parent=None): + self = cls(parent) + + if self._version_tag not in d: + _key_note(self._version_tag, d.lc, "ERROR: Missing mandatory '{}' key field!") + raise ConfigurationError(u"{}: {}".format("ERROR:", "Missing version tag '{0}' in the input: '{1}'!".format(self._version_tag, d))) + + try: + _v = SemanticVersion.parse(d[self._version_tag], parent=self) + except: + _value_error(self._version_tag, d, d.lc, "Wrong value of global '{}' specification!") + raise + + self.set_version(_v) # NOTE: globally available now! + + if self.validate(d): + return self.get_data() + + return None + + def validate(self, data): + _ret = BaseRecord.validate(self, data) + + for offset, k in enumerate(data): + if k == self._version_tag: + if offset != 0: + print("Note: '{}' specified correctly but not ahead of everything else (offset: {})!".format( + self._version_tag, offset)) + _ret = False + break + + # NOTE: check uniqueness of keys among (Services/Applications): + _services = data.get(self._services_tag) # Rely on the above and use get_data? + _applications = data.get(self._applications_tag) + + for p, k in enumerate(_services): + _lc = _services.lc.key(k) + + if k in _applications: + print("Error: '{}' is both a ServiceID and an ApplicationID:".format(k)) + _key_error(k, _services[k], _lc, "Service key: {}") + + _alc = _applications.lc.key(k) + _key_error(k, _applications[k], _alc, "Application key: {}") + + # ! TODO: check Uniqueness of keys among (Profiles/Stations/Groups) !!!! + # ! TODO: check for GroupID <-> StationID <-> ProfileID + return _ret + + +############################################################### +def load_yaml_file(filename): + with open(filename, 'r') as fh: + return load_yaml(fh) + +# class Hilbert(object): + +def yaml_dump(d, stream=None): + print(yaml.round_trip_dump(d, stream=stream)) + +def parse(d, parent=None): + return Global.parse(d, parent=parent) + diff --git a/config/hilbert.py b/tools/hilbert.py similarity index 79% rename from config/hilbert.py rename to tools/hilbert.py index 20ead09..d4be804 100755 --- a/config/hilbert.py +++ b/tools/hilbert.py @@ -6,9 +6,23 @@ from __future__ import absolute_import, print_function, unicode_literals +assert __name__ == "__main__" + +import sys +from os import path + +DIR=path.dirname( path.dirname( path.abspath(__file__) ) ) + +# sys.path.append( DIR ) +sys.path.append( path.join(DIR, 'config' ) ) + + from hilbert_cli_config import * from helpers import * +#from config.hilbert_cli_config import * +#from config.helpers import * + from arghandler import * # NOQA import argparse # NOQA @@ -49,7 +63,13 @@ def cmd_verify(parser, context, args): args = vars(parser.parse_args(args)) # vars(args) - fn = ctx['inputfile'] + fn = 'Hilbert.yml' + + if 'inputfile' not in ctx: + print("Warning: missing input file specification: using default '{}'!" . format(fn)) + else: + fn = ctx['inputfile'] + assert fn is not None f = URI(None) @@ -87,13 +107,13 @@ def cmd_verify(parser, context, args): def cmd_dump(parser, context, args): global PEDANTIC global INPUT_DIRNAME - global OUTPUT_DIRNAME +# global OUTPUT_DIRNAME - parser.add_argument('-O', '--outputdir', required=False, default=argparse.SUPPRESS, - help="specify output directory (default: alongside with the output dump file)") +# parser.add_argument('-O', '--outputdir', required=False, default=argparse.SUPPRESS, +# help="specify output directory (default: alongside with the output dump file)") parser.add_argument('-od', '--outputdump', required=True, default=argparse.SUPPRESS, - help="specify output file (default: same as the input file with '.pickle' suffix)") + help="specify output dump file") ctx = vars(context) @@ -114,7 +134,17 @@ def cmd_dump(parser, context, args): if 'inputdump' in ctx: df = ctx['inputdump'] # assert df is not None + + if (fn is None) and (df is None): + fn = 'Hilbert.yml' + print("Warning: missing input file specification: using default '{}'!" . format(fn)) +# print("ERROR: input file/dump specification is missing!") +# exit(1) + if (fn is not None) and (df is not None): + print("ERROR: input file specification clashes with the input dump specification: specify a single input source!") + exit(1) + if fn is not None: if not f.validate(fn): print("ERROR: wrong file specification: '{}'" . format(fn)) @@ -127,15 +157,6 @@ def cmd_dump(parser, context, args): exit(1) print("## Input dump file: '{}'".format(df)) - - if (fn is None) and (df is None): - print("ERROR: input file/dump specification is missing!") - exit(1) - - if (fn is not None) and (df is not None): - print("ERROR: input file specification clashes with the input dump specification: specify a single input source!") - exit(1) - if fn is not None: INPUT_DIRNAME = os.path.abspath(os.path.dirname(fn)) @@ -144,23 +165,22 @@ def cmd_dump(parser, context, args): INPUT_DIRNAME = os.path.abspath(os.path.dirname(df)) - out = None - - if 'outputdir' in args: - out = args['outputdir'] - - assert out is not None - - if not f.validate(out): - print("ERROR: wrong output directory specification: '{}'" . format(out)) - exit(1) - -# out = f.get_data() - print("## Output dir: '{}'".format(out)) - - OUTPUT_DIRNAME = os.path.abspath(out) - else: - OUTPUT_DIRNAME = INPUT_DIRNAME +# out = None +# if 'outputdir' in args: +# out = args['outputdir'] +# +# assert out is not None +# +# if not f.validate(out): +# print("ERROR: wrong output directory specification: '{}'" . format(out)) +# exit(1) +# +### out = f.get_data() +# print("## Output dir: '{}'".format(out)) +# +# OUTPUT_DIRNAME = os.path.abspath(out) +# else: +# OUTPUT_DIRNAME = INPUT_DIRNAME od = None @@ -169,11 +189,11 @@ def cmd_dump(parser, context, args): assert od is not None elif fn is not None: od = os.path.splitext(os.path.basename(fn))[0] + '.pickle' - OUTPUT_DIRNAME = INPUT_DIRNAME +# OUTPUT_DIRNAME = INPUT_DIRNAME else: assert df is not None od = os.path.splitext(os.path.basename(df))[0] + '.pickle' - OUTPUT_DIRNAME = INPUT_DIRNAME +# OUTPUT_DIRNAME = INPUT_DIRNAME f = URI(None) @@ -236,7 +256,7 @@ def main(): handler.add_argument('-p', '--pedantic', required=False, action='store_true', help="turn on pedantic mode") - handler.add_argument('-if', '--inputfile', required=False, default='Hilbert.yml', + handler.add_argument('-if', '--inputfile', required=False, help="specify input file (default: 'Hilbert.yml')") handler.add_argument('-id', '--inputdump', required=False, @@ -250,7 +270,4 @@ def main(): handler.run(_argv) -if __name__ == "__main__": - main() - - \ No newline at end of file +main() From 850ec47df55392609d0223ad8069e7d0dced09d6 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Fri, 18 Nov 2016 20:20:25 +0100 Subject: [PATCH 16/42] Added `cfg_show [-o ]` subcommand to display (a part of) the loaded configuration --- tools/hilbert.py | 97 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) diff --git a/tools/hilbert.py b/tools/hilbert.py index d4be804..7edb4de 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -243,6 +243,103 @@ def cmd_dump(parser, context, args): + +@subcmd('cfg_show', help='Load Configuration file and display some of its contents') +def cmd_show(parser, context, args): + global PEDANTIC + global INPUT_DIRNAME +# global OUTPUT_DIRNAME + + parser.add_argument('-o', '--object', required=False, default='all', + help="specify what to show (default: all)") + + ctx = vars(context) + + if 'pedantic' in ctx: + PEDANTIC = ctx['pedantic'] + + args = vars(parser.parse_args(args)) + + fn = None + df = None + + f = URI(None) + + if 'inputfile' in ctx: + fn = ctx['inputfile'] + + if 'inputdump' in ctx: + df = ctx['inputdump'] + + if (fn is None) and (df is None): + fn = 'Hilbert.yml' + print("Warning: missing input file specification: using default '{}'!" . format(fn)) +# exit(1) + + if (fn is not None) and (df is not None): + print("ERROR: input file specification clashes with the input dump specification: specify a single input source!") + exit(1) + + if fn is not None: + if not f.validate(fn): + print("ERROR: wrong file specification: '{}'" . format(fn)) + exit(1) + print("## Input file: '{}'".format(fn)) + + if df is not None: + if not f.validate(df): + print("ERROR: wrong dump file specification: '{}'" . format(df)) + exit(1) + print("## Input dump file: '{}'".format(df)) + + + if fn is not None: + INPUT_DIRNAME = os.path.abspath(os.path.dirname(fn)) + else: + assert df is not None + INPUT_DIRNAME = os.path.abspath(os.path.dirname(df)) + + cfg = None + if fn is not None: + print("## Loading '{}'..." . format(fn)) + try: + yml = _load(fn) + print("## Input file is a valid YAML!") + + os.chdir(INPUT_DIRNAME) + print("## Data Validation/Parsing: ") + cfg = parse(yml) + + except: + print("ERROR: wrong input file: '{}'!" . format(fn)) + raise + else: + print("## Loading dump '{}'..." . format(df)) + try: + cfg = pickle_load(df) + print("## Input dump file is valid!") + except: + print("ERROR: wrong input dump file: '{}'!" . format(df)) + raise + + + if cfg is None: + print("ERROR: could not get the configuration!") + exit(1) + + obj = 'all' + if 'object' in args: + obj = args['object'] + + print("## Configuration is OK! Showing: '{}'" . format(obj)) + + if obj == 'all': + pprint(cfg) + else: + print("## ERROR: Sorry cannot show '{}' yet!" . format(obj)) + exit(1) + + def main(): handler = ArgumentHandler(use_subcommand_help=True, enable_autocompletion=True, description="Validate/Parse Hilbert Configuration") From 1542e873dc3fc3c1ea13c28f22e2857ce0e14f6c Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Sat, 19 Nov 2016 04:45:45 +0100 Subject: [PATCH 17/42] Add more API to Validators (and keep them) (e.g. Hilbert) For instance: * printing * show * config library package may be anywhere (see adding path to /config/ in config/tests/test_validate.py and /tools/hilbert.py) Update: tests/data/Hilbert.yml.data.pickle contains Hilbert top class TODO: Validator.parse should return Validator (or throw an exception) --- config/helpers.py | 15 +++-- config/hilbert_cli_config.py | 75 ++++++++++++++++------ config/tests/data/Hilbert.yml.data.pickle | Bin 3210 -> 3878 bytes config/tests/test_loadwarnings.py | 1 + config/tests/test_validate.py | 27 ++++++-- config/tests/test_version.py | 4 +- tools/hilbert.py | 31 ++++----- 7 files changed, 106 insertions(+), 47 deletions(-) diff --git a/config/helpers.py b/config/helpers.py index 0e91605..2b45a0c 100644 --- a/config/helpers.py +++ b/config/helpers.py @@ -4,12 +4,9 @@ from __future__ import absolute_import, print_function, unicode_literals -def pprint(cfg): - import pprint - print("## Validated/Parsed pretty Result: ") - pp = pprint.PrettyPrinter(indent=2) - pp.pprint(cfg) - +# from .hilbert_cli_config import load_yaml # Hilbert # VerboseRoundTripLoader, + +############################################################### # import pickle # import cPickle as pickle @@ -26,4 +23,8 @@ def pickle_load(fn): d = pickle.load(p) return d - +############################################################### + +def yaml_dump(d, stream=None): + import ruamel.yaml as yaml + print(yaml.round_trip_dump(d, stream=stream)) diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index 814d91f..886932f 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -7,14 +7,28 @@ import logging # log = logging.getLogger(__name__) +# from .helpers import load_yaml, pprint + +############################################################### +import pprint as PP + +def pprint(cfg): + print("## Validated/Parsed pretty Result: ") + pp = PP.PrettyPrinter(indent=2) + pp.pprint(cfg) +# PP.pformat + + +############################################################### +# NOTE: Global variuables PEDANTIC = False # NOTE: to treat invalid values/keys as errors? INPUT_DIRNAME = './' -OUTPUT_DIRNAME = INPUT_DIRNAME +# OUTPUT_DIRNAME = INPUT_DIRNAME + ############################################################### up_arrow = '↑' - def _get_line_col(lc): if isinstance(lc, (list, tuple)): @@ -146,16 +160,7 @@ def __init__(self, stream, version=None, preserve_quotes=None): VerboseRoundTripConstructor.__init__(self, preserve_quotes=preserve_quotes) VersionedResolver.__init__(self, version) - -############################################################### -def load_yaml(f, Loader=VerboseRoundTripLoader, version=(1, 2), preserve_quotes=True): - try: - return yaml.load(f, Loader=Loader, version=version, preserve_quotes=preserve_quotes) - except (IOError, yaml.YAMLError) as e: - error_name = getattr(e, '__module__', '') + '.' + e.__class__.__name__ - raise ConfigurationError(u"{}: {}".format(error_name, e)) - - + ############################################################### from ruamel.yaml.compat import PY2, PY3, text_type, string_types from abc import * @@ -247,6 +252,17 @@ def parse(cls, d, parent=None): # NOTE: .parse should! raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) + def __repr__(self): + """Print using pretty formatter""" + + d = self.get_data() # vars(self) # ??? + return PP.pformat(d, indent=4, width=1) + + def __eq__(self, other): + return self.get_data() == other.get_data() + + def __ne__(self, other): + return not (self == other) # More general than self.value != other.value ############################################################### class BaseRecord(Base): @@ -1422,7 +1438,7 @@ def validate(self, data): ############################################################### -class Global(BaseRecord): +class Hilbert(BaseRecord): """General Hilbert Configuration format""" def __init__(self, parent): @@ -1501,18 +1517,41 @@ def validate(self, data): # ! TODO: check Uniqueness of keys among (Profiles/Stations/Groups) !!!! # ! TODO: check for GroupID <-> StationID <-> ProfileID return _ret + + + def show(self, what): + _d = self.get_data() + + if what == 'all': + print(self) + elif what in _d: + print(_d[what]) + else: + raise ConfigurationError(u"{}: {}".format("ERROR:", "Sorry cannot show '{0}' of {1}!" . format(what, type(self)))) ############################################################### +def load_yaml(f, Loader=VerboseRoundTripLoader, version=(1, 2), preserve_quotes=True): + try: + return yaml.load(f, Loader=Loader, version=version, preserve_quotes=preserve_quotes) + except (IOError, yaml.YAMLError) as e: + error_name = getattr(e, '__module__', '') + '.' + e.__class__.__name__ + raise ConfigurationError(u"{}: {}".format(error_name, e)) + + def load_yaml_file(filename): with open(filename, 'r') as fh: return load_yaml(fh) -# class Hilbert(object): +############################################################### +def parse_hilbert(d, parent=None): + cfg = Hilbert(None) + if not cfg.validate(d): +# pprint(d) + raise ConfigurationError(u"{}: {}".format("ERROR:", "Cannot parse given configuration!")) + + return cfg -def yaml_dump(d, stream=None): - print(yaml.round_trip_dump(d, stream=stream)) +# return Hilbert.parse(d, parent=parent) -def parse(d, parent=None): - return Global.parse(d, parent=parent) diff --git a/config/tests/data/Hilbert.yml.data.pickle b/config/tests/data/Hilbert.yml.data.pickle index 36c5dfe85b9b521e5412f344457504de01f4ae9d..e24eb793f402db70add6cf76ff369fbea80394a8 100644 GIT binary patch literal 3878 zcma)9hkM)B5m#(WlqoBc?bxZ)45V>gy0t)4vSf>?>(CM{DUwK;;IommEDC}UA8HWb zVaQTbG*MftQq#Tn-h1!8N1E=v_g?=&4-WtZGK#)R-=|L>aPRJS_q+SO!#z6`s_9kL zawJ99B*ioqwR&$qpNV02Rl-vM{-u0str3m*d<=w)zwu~7iCv>q`GcaWgWUb z=t+sa_(E`GM>7o@66;&}o?`ZqQ4)IBV7HjSa|@PgtBwuHjR!v#+9aWG4fe2T3zoU4 z=?JWUn`n_y60Tl@0dWsT%Qc(2ri4fbw>cX(Ov2tZ*vHUbP%Rs?g#B9{71V}oIGPe# zCE=PiI3V_5+$qa+n>HNWCdt4g3D>T{LxPH`){>@Rj)%4k7FIMgO2Tz(@KDz#dnGxR zqvXhSxSkG@J!iiX@r= zrEpYC23AH*)=fi&N0I?-QbZtOqd1yTx8YG997~DUq22V%+}V7oEG?As=kldeeo~st z6{bjTDi1?sM@-Iwt0Y<5W|1c?E`NuMzid^&Upn#e*@|6GSK% z=V$KBm1l|t0Zx#Fv2;wgnFiEj7@+mq*d77rjsZUe9 zNlN*t8KGRdLz>K$bJ9YtJPqd*%f*7|{EFPrd0UZn*|HrhVm&F~A6-4~nvPl%*b5Ee9eOY?zzro(0!vedeUE>?#8K}f^&6_{Ct+dY`A(&5=IIVbj+w$zZ= zY}LY?hG=!j&uK^omF!}Ax+wNzq)Ah`q+0VbUU(>Pb<*d{hvc|8rv}hWLIh znznU`pXg%o{YyDBKFnvvPVwX8eCGH#T%u<-u=IZC`#E46a}P)^2YN72K0-fO1{xk1 zF&#ELN52_r2e6T2)yaUhsTFqT0cVR^xgIQ~$j*kWz-6XznM`(gI6E?uJ#ivCI+`6D zgXOSTE8>cr6Wj%0{~e-Oa>XFdHf- zlyim2++4AckBEnRTy!6;C94I}8|@MBR1cn(3Ir!;%%^*B1#dZj7}-s|R)J@v#9aux z=`@yMok^CjrNOXlsAK>ItZ7;(DdA@I%nIDgRtv>!G)-HDXUXkgpDi9ne>r1?o6`(; zxuutvHRR28xbr0r)yXhW|DF>v^xQbc=eco-e7*-Sh$DVs1zr?G{NfJ8FJT;D2Jlk0 zlSJAEFJmtnMjc+hMN+S*z$@F5dR0eKuVxGs4Sj`MG_6otS`54<%;U9j`whFwx4e>iV5WiEr5u>+JU~@hP zaRS~I0)ICvR@su3OE`V-9=CHe-s{2p;wikp0v~u_Z+x%J}34e#+Ig|q<>x}{cJ6^4`I{jo&n{$_X@@Ah!9Y}*(;_!gUP|JwuZ7x$sJ8WZ!OaC-Tb zh7R8*J1un)zSCC0@3Mm$?h5d|0`BRF=u_hRsoAdC?%Caif&)JwJ>i$a4?Xx1JKtDg zD>wYugP*i%&rb^^p)Lni|5*io9!bZe(AxlQmrZewFkdJ`Ss!bw)OCL zVX=PSR;)kJ`xz%Sg(dYzdLNsBuuj-lu_8sAh6jHNZk0{V`?Cjs2_ycsV=(^~#{GL+ z+<#!)2Py175re;Z{hwU@%f-g-m%^36W()1VX#yXG-x|TA|ImKlDl8bY`Y%1?R{8${ DWGF0U literal 3210 zcma)833t@i6?QP-4KSNS*@99inI>3f3>Z8uO@uwz#`cUEjX)%ss2b^cq@t1LYB8Qt zHIS6nG;OnXPr9TVrES(OX|uLXy8Wu&_oNw16PHu_93LOO_wN1f{qFa@cWqq=T^XrY z^i|(Vv+SS$NMV}O%EUJO!d(a)i`i#`maGgcdBCtX3k9OI*YB@H6jnbfI znZ))LkNCc6*F5M6p*JJ%!F|&+b7%6Uva(RhpUsy_`AKC?C`?JhR37@Ibvl85c_^`M zIxm#UXYxW>kxFwgAPpJ5-^h)OWJgc(NAWkCJB2^6N#312G&7l3=8KY;S0<#ASS-Qj z*}LRjxWh25Dsg>94SWad!vAz)sZH22yHnn_);bKX$ag0~Pe@|9I6w2SP@X9kMA$0z z*h@!L%Tr++3(zW0m=gtMLMTnbc1*n^6=6YC#C+*Oz63j@{SDW&ed1>MMo_g(jrW2E zacyTw&5a$)!p=ZiZ>x0zLkxvs>N>Hxm~Y7KUElJNcJjqV-y_ru1Etq@ifuxY z3p}6e#MGjEe<1ha!FD}xPY4Gx#s+yK{Yu;=;sR&jVBDKA`iy>Kz}RF^nvz3O%1_OR z<54@Pik&}4YBy9TDN#lQ!Ul?d~9N^U&KEaIUhJa(M7f(MhkFIK8#5Z zU7aq@=fe?RbL>U4HWClRuuEzthG-7!s;`c~p&Rh2>u@-P`>Mv4*)C&n#n@_WOW}&> zQznXqvoli>u8eU|K5&O5QN<(h=^JqWb$B3zBUOWr231&VXo~ZbQLteQw(kzXknIuR zZ@|cPI2uB>YV0s}2F4HzCbkBM6Qd@N8oT5T7)-69B;lB`J5qIP8(&{^c+}l-WABQw zkLf5n$i-fe$GtH|=S4qmrCp7C(0?LiOU zOncBH%)CXXPB^hF6efkaVj;{Co&1 z-f~ooriL4;70@#BdW7BZ>&u`s%c5QyiG>hp5Dl#1xM(Q~od^#WD^Qbr@Py{n8;(c7 zP}5*d`4FxOc9WYk?O?g>msd>WE%3SXB@W%mw$cB-5HoZ+iO~v@7FiF$P9kuZ>B%(^f29I9Qi#9Wf%t3kJ(xX3 zfyYq}k_4>8z;Ci zaRuUEaa@|>2!le$0qVYLp&)JB07BZp3~G z-wok=8EHG6QS?&0@MD+s;QJx`0A0hhH7h{d|6v7Qlm`%F+tbm~Us9#b>{;Rw&A*5} zgCAAk$H^i6iJGMPr-dM0_RGvFO30s6=cdnaRPMB~KZ{HHIV%Yls4LNhU&J2r%M_=- zk_QnPb6cJGh=n~(Z?W5)EK^xxaQZSljdy$euuQ!eL-;jQH+!hwmbYUxotgP?tX{rZ zx8OHYw@Vh`x2X>PjvX}dtpKkS0#E9>KwOVLh+fUicFk^>?JE>~cum?k?AmINCD>xhd diff --git a/config/tests/test_loadwarnings.py b/config/tests/test_loadwarnings.py index 7eda196..2fa9ef8 100644 --- a/config/tests/test_loadwarnings.py +++ b/config/tests/test_loadwarnings.py @@ -5,6 +5,7 @@ from __future__ import absolute_import, print_function, unicode_literals # NOQA from ..hilbert_cli_config import load_yaml +# from ..helpers import load_yaml import pytest # NOQA diff --git a/config/tests/test_validate.py b/config/tests/test_validate.py index e112b54..8e9cc47 100644 --- a/config/tests/test_validate.py +++ b/config/tests/test_validate.py @@ -4,8 +4,20 @@ from __future__ import absolute_import, print_function, unicode_literals # NOQA -from ..hilbert_cli_config import load_yaml_file, parse, INPUT_DIRNAME -from ..helpers import pickle_load, pprint +import sys +from os import path + +DIR=path.dirname( path.dirname( path.abspath(__file__) ) ) +sys.path.append( DIR ) + + + +#from hilbert_cli_config import pprint, INPUT_DIRNAME +#from hilbert_cli_config import load_yaml, load_yaml_file, parse_hilbert, Hilbert +#from helpers import pickle_load + +from hilbert_cli_config import * +from helpers import * import pytest # NOQA import os # NOQA @@ -37,15 +49,18 @@ def test_1(self, capsys): cwd = os.getcwd() try: os.chdir(INPUT_DIRNAME) - cfg = parse(yml) + cfg = parse_hilbert(yml) finally: os.chdir(cwd) - - assert cfg is not None + + assert cfg is not None d = pickle_load(f) + assert d is not None + + assert type(d) == type(cfg) + # pprint(cfg) # pprint(d) - assert d == cfg diff --git a/config/tests/test_version.py b/config/tests/test_version.py index 7b67230..ab5ca4d 100644 --- a/config/tests/test_version.py +++ b/config/tests/test_version.py @@ -4,7 +4,9 @@ from __future__ import absolute_import, print_function, unicode_literals # NOQA -from ..hilbert_cli_config import load_yaml, SemanticVersion +from ..hilbert_cli_config import SemanticVersion +from ..hilbert_cli_config import load_yaml +# helpers import pytest # NOQA diff --git a/tools/hilbert.py b/tools/hilbert.py index 7edb4de..e909ebc 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -10,15 +10,13 @@ import sys from os import path - DIR=path.dirname( path.dirname( path.abspath(__file__) ) ) - -# sys.path.append( DIR ) sys.path.append( path.join(DIR, 'config' ) ) +# sys.path.append( DIR ) -from hilbert_cli_config import * from helpers import * +from hilbert_cli_config import * #from config.hilbert_cli_config import * #from config.helpers import * @@ -92,7 +90,7 @@ def cmd_verify(parser, context, args): os.chdir(INPUT_DIRNAME) print("## Deep Configuration Validation/Parsing: ") - cfg = parse(yml) + cfg = parse_hilbert(yml) if cfg is None: print("ERROR: semantically wrong input!") @@ -213,7 +211,7 @@ def cmd_dump(parser, context, args): os.chdir(INPUT_DIRNAME) print("## Data Validation/Parsing: ") - cfg = parse(yml) + cfg = parse_hilbert(yml) except: print("ERROR: wrong input file: '{}'!" . format(fn)) @@ -251,7 +249,7 @@ def cmd_show(parser, context, args): # global OUTPUT_DIRNAME parser.add_argument('-o', '--object', required=False, default='all', - help="specify what to show (default: all)") + help="specify the object in the config (default: all)") ctx = vars(context) @@ -307,8 +305,9 @@ def cmd_show(parser, context, args): print("## Input file is a valid YAML!") os.chdir(INPUT_DIRNAME) - print("## Data Validation/Parsing: ") - cfg = parse(yml) + print("## Data Validation/Parsing: ") + + cfg = parse_hilbert(yml) except: print("ERROR: wrong input file: '{}'!" . format(fn)) @@ -327,16 +326,18 @@ def cmd_show(parser, context, args): print("ERROR: could not get the configuration!") exit(1) + assert isinstance(cfg, Hilbert) + print("## Configuration is OK!") + obj = 'all' if 'object' in args: obj = args['object'] - - print("## Configuration is OK! Showing: '{}'" . format(obj)) - if obj == 'all': - pprint(cfg) - else: - print("## ERROR: Sorry cannot show '{}' yet!" . format(obj)) + try: + print("## Showing: '{}' for the configuration" . format(obj)) + cfg.show(obj) + except: + print("## ERROR: Sorry cannot show '{}' yet!" . format(obj)) exit(1) From 39cb7e2939ff738580cd849b4a3d110c3ec4b3a7 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Sun, 20 Nov 2016 07:35:40 +0100 Subject: [PATCH 18/42] Keep Validators to handle configuration objects NOTE: use .parse instead of .validate on temporary objects --- config/hilbert_cli_config.py | 676 +++++++++++++++------- config/tests/data/Hilbert.yml.data.pickle | Bin 3878 -> 11437 bytes config/tests/test_validate.py | 10 +- config/tests/test_version.py | 18 +- tools/hilbert.py | 67 ++- 5 files changed, 503 insertions(+), 268 deletions(-) diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index 886932f..9aa09ec 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -205,7 +205,10 @@ class Base(AbstractValidator): _data = None _default_data = None - def __init__(self, parent): # TODO: add tag? here or in some child? + def get_parent(self): + return self._parent + + def __init__(self, parent): # TODO: add tag? here or in some child? AbstractValidator.__init__(self) assert self._parent is None self._parent = parent @@ -232,22 +235,29 @@ def set_data(self, d): self._data = d def get_data(self): - if self._data is None: - return self._default_data + _d = self._data + if _d is None: + _d = self._default_data + +# if _d is None: +# return _d + +# while isinstance(_d, AbstractValidator): +# _d = _d.get_data() +# if _d is None: +# return _d - return self._data + return _d @classmethod def parse(cls, d, parent=None): self = cls(parent) -# print(cls) -# print(parent) -# print(self) -# print(d) + if d is None: + d = self._default_data if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! - return self.get_data() + return self # .get_data() # NOTE: .parse should! raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) @@ -255,15 +265,29 @@ def parse(cls, d, parent=None): def __repr__(self): """Print using pretty formatter""" - d = self.get_data() # vars(self) # ??? + d = self.get_data() # vars(self) # ??? return PP.pformat(d, indent=4, width=1) +# def __str__(self): +# """Convert to string""" +# +# d = self.get_data() # vars(self) # ??? +# return str(d) + def __eq__(self, other): + assert isinstance(self, AbstractValidator) + + if not isinstance(other, AbstractValidator): + return self.get_data() == other + + assert isinstance(other, AbstractValidator) + return self.get_data() == other.get_data() - + def __ne__(self, other): return not (self == other) # More general than self.value != other.value + ############################################################### class BaseRecord(Base): """Aggregation of data as a record with some fixed data memebers""" @@ -274,8 +298,8 @@ def __init__(self, parent): Base.__init__(self, parent) self._default_type = None # "default_base" self._types = {} - self._create_optional = False - + self._create_optional = False # Instantiate missing optional keys + self._type = None def detect_type(self, d): """determine the type of variadic data for the format version""" @@ -285,18 +309,19 @@ def detect_type(self, d): return self._default_type - def detect_extra_rule(self, key, value): # Any extra unlisted keys in the mapping? + def detect_extra_rule(self, key, value): + """Handling for extra un-recorded keys in the mapping""" return None def validate(self, d): # ! TODO: assert that d is a mapping with lc! - _type = self.detect_type(d) + self._type = self.detect_type(d) - assert not (_type is None) - assert _type in self._types + assert self._type is not None + assert self._type in self._types - _rule = self._types[_type] + _rule = self._types[self._type] _ret = True @@ -308,53 +333,88 @@ def validate(self, d): for k in _rule.keys(): r = _rule[k] if r[0] and (k not in d): - _key_note(k, _lc, "ERROR: Missing mandatory key `{}` (type: '%s')" % (_type)) # Raise Exception? + _key_note(k, _lc, "ERROR: Missing mandatory key `{}` (type: '%s')" % (self._type)) # Raise Exception? _ret = False # NOTE: the following will add all the missing default values - elif (not r[0]) and self._create_optional: # Optional Values should have some default values! - _d[k] = r[1](self).get_data() # NOTE: default value - no validation + elif self._create_optional and (not r[0]): # Optional Values should have some default values! + # TODO: FIXME: catch exception in the following: + _k = None + _v = None + try: + _k = BaseString.parse(k, parent=self) + except ConfigurationError as err: + _key_note(k, _lc, "Error: invalid _optional_ key field '{}' (type: '%s')" % self._type) + pprint(err) + _ret = False + + try: + _v = (r[1]).parse(None, parent=self) # Default Value! + except ConfigurationError as err: + _key_note(k, _lc, "Error: invalid default value (for optional key: '{}') (type: '%s')" % self._type) + pprint(err) + _ret = False + + if _ret: + assert _k is not None + _d[_k] = _v for offset, k in enumerate(d): v = d.get(k) + k = text_type(k) l = s + offset # ?? lc = (l, c) + _k = None + _v = None + if k in _rule: - r = _rule[k][1](self) + try: + _k = BaseString.parse(k, parent=self) + except ConfigurationError as err: + _key_error(k, v, lc, "Error: invalid key field '{}' (type: '%s')" % self._type) + pprint(err) + _ret = False - if not r.validate(v): # TODO: save to self! - _value_error(k, v, lc, "Error: invalid field '{}' value (type: '%s')" % _type) + try: + _v = (_rule[k][1]).parse(v, parent=self) + except ConfigurationError as err: + _value_error(k, v, lc, "Error: invalid field value (key: '{}') (type: '%s')" % self._type) + pprint(err) _ret = False - _d[k] = r.get_data() else: _extra_rule = self.detect_extra_rule(k, v) # (KeyValidator, ValueValidator) if _extra_rule is None: - _key_error(k, v, lc, "WARNING: Unhandled extra Key: '{}' (type: '%s')" % _type) + _key_error(k, v, lc, "WARNING: Unhandled extra Key: '{}' (type: '%s')" % self._type) _ret = False else: - _k = _extra_rule[0](self) + try: + _k = (_extra_rule[0]).parse(k, parent=self) + except ConfigurationError as err: + _key_error(k, v, lc, "Error: invalid key '{}' (type: '%s')" % self._type) + pprint(err) + _ret = False - if not _k.validate(k): - _key_error(k, v, lc, "Error: invalid key '{}' (type: '%s')" % _type) + try: + _v = (_extra_rule[1]).parse(v, parent=self) + except ConfigurationError as err: + # TODO: FIXME: wrong col (it was for key - not value)! + _value_error(k, v, lc, "Error: invalid field value '{}' value (type: '%s')" % self._type) + pprint(err) _ret = False - else: - _v = _extra_rule[1](self) - if not _v.validate(v): # TODO: FIXME: wrong col (it was for key - not value)! - _value_error(k, v, lc, "Error: invalid field value '{}' value (type: '%s')" % _type) - _ret = False - else: - _d[_k.get_data()] = _v.get_data() + + if _ret: + assert _k is not None + _d[_k] = _v if _ret: self.set_data(_d) return _ret - ############################################################### - +############################################################### class BaseScalar(Base): """Single scalar value out of YAML scalars: strings, numbert etc.""" @@ -364,23 +424,44 @@ def __init__(self, parent): def validate(self, d): """check that data is a scalar: not a sequence or mapping or set""" - if isinstance(d, (list, dict, tuple, set)): # ! Check if data is not a container? - print("ERROR: value: '{}' is not a scalar value!!" . format(d)) - return False + if d is not None: + if isinstance(d, (list, dict, tuple, set)): # ! Check if data is not a container? + print("ERROR: value: '{}' is not a scalar value!!" . format(d)) + return False + + if isinstance(d, string_types): + d = text_type(d) + # NOTE: None is also a scalar value...! self.set_data(d) return True + @classmethod + def parse(cls, d, parent=None): + self = cls(parent) + + if d is None: + d = self._default_data + + if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! + return self.get_data() + + # NOTE: .parse should! + raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) + ############################################################### class BaseString(BaseScalar): """YAML String""" def __init__(self, parent): BaseScalar.__init__(self, parent) + self._default_data = '' def validate(self, d): """check whether data is a valid string. Note: should not care about format version""" + assert d is not None + s = BaseScalar.parse(d, parent=self) if not isinstance(s, string_types): @@ -397,20 +478,21 @@ def validate(self, d): class SemanticVersion(BaseString): - def __init__(self, parent): + def __init__(self, parent, partial=True, coerce=True): BaseString.__init__(self, parent) + self._partial = partial + self._coerce = coerce + def validate(self, d): """check the string data to be a valid semantic verions""" _t = BaseString.parse(d, parent=self) - _v = self.get_version(None) + # self.get_version(None) # ??? + _v = None try: -# if _v is None: # NOTE: the only initial validation: may be a partial version -# _v = semantic_version.Version(_t, partial=True) # TODO: check this! -# else: - _v = semantic_version.Version.parse(_t, partial=True, coerce=True) + _v = semantic_version.Version.parse(_t, partial=self._partial, coerce=self._coerce) except: print("ERROR: wrong version data: '{0}' (see: '{1}')" . format(d, sys.exc_info())) return False @@ -418,11 +500,24 @@ def validate(self, d): self.set_data(_v) return True + @classmethod + def parse(cls, d, parent=None, partial=True, coerce=True): + self = cls(parent, partial=partial, coerce=coerce) + + if d is None: + d = self._default_data + + if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! + return self.get_data() + + # NOTE: .parse should! + raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) ############################################################### class BaseUIString(BaseString): # visible to user => non empty! def __init__(self, parent): BaseString.__init__(self, parent) + self._default_data = None def validate(self, d): """check whether data is a valid string""" @@ -457,22 +552,22 @@ def validate(self, d): ############################################################### -class ServiceType(BaseEnum): ## Q: Is 'Service::type' mandatory? default: 'compose' +class ServiceType(BaseEnum): # Q: Is 'Service::type' mandatory? default: 'compose' def __init__(self, parent): BaseEnum.__init__(self, parent) - compose = 'compose' - self._enum_list = [compose] # NOTE: 'docker' and others may be possible later on + compose = text_type('compose') + self._enum_list = [compose] # NOTE: 'docker' and others may be possible later on self._default_data = compose ############################################################### -class StationOMDTag(BaseEnum): ## Q: Is 'Station::omd_tag' mandatory? default: 'standalone' +class StationOMDTag(BaseEnum): # Q: Is 'Station::omd_tag' mandatory? default: 'standalone' def __init__(self, parent): BaseEnum.__init__(self, parent) - _v = 'standalone' - self._enum_list = ['agent', 'windows', _v] # possible values of omd_tag # will depend on format version! + _v = text_type('standalone') + self._enum_list = [text_type('agent'), text_type('windows'), _v] # NOTE: possible values of omd_tag self._default_data = _v @@ -481,9 +576,9 @@ class StationPowerOnMethodType(BaseEnum): # Enum: [WOL], AMTvPRO, DockerMachine def __init__(self, parent): BaseEnum.__init__(self, parent) - wol = 'WOL' + wol = text_type('WOL') # NOTE: the list of possible values of PowerOnMethod::type (will depend on format version) - self._enum_list = [wol, 'DockerMachine'] # NOTE: 'AMTvPRO' and others may be possible later on + self._enum_list = [wol, text_type('DockerMachine')] # NOTE: 'AMTvPRO' and others may be possible later on self._default_data = wol @@ -512,8 +607,8 @@ def validate(self, d): _ret = True - if urlparse(v).scheme != "": - self._type = "url" + if urlparse(v).scheme != '': + self._type = text_type('url') try: urlopen(v).close() except: @@ -525,10 +620,10 @@ def validate(self, d): # v = os.path.abspath(os.path.join(os.path.dirname(sys.argv[0]), v)) elif os.path.isfile(v): # Check whether file exists - self._type = "file" + self._type = text_type('file') elif os.path.isdir(v): # Check whether directory exists - self._type = "dir" + self._type = text_type('dir') if not _ret: print("WARNING: missing/unsupported resource location: {}".format(v)) @@ -539,6 +634,21 @@ def validate(self, d): return _ret + ## TODO: @classmethod check_uri() + + @classmethod + def parse(cls, d, parent=None): + self = cls(parent) + + if d is None: + d = self._default_data + + if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! + return self.get_data() # TODO: due to DockerComposeFile later on :-( + + # NOTE: .parse should! + raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) + ############################################################### import re, tokenize @@ -576,7 +686,7 @@ def __init__(self, parent): def validate(self, d): """check whether data is a valid ID string""" - v = BaseID.parse(d, parent=self) + v = BaseID.parse(d, parent=self) # .get_data() _ret = True @@ -585,7 +695,7 @@ def validate(self, d): _ret = False # NOTE: starting with hilbert_ or HILBERT_ with letters, digits and '_'?? - if not re.match("^hilbert(_[a-z0-9]+)+$", v.lower()): + if not re.match('^hilbert(_[a-z0-9]+)+$', v.lower()): print("ERROR: variable must start with HILBERT/hilbert and contain words separated by underscores!" " Input: '{}" .format(d)) _ret = False @@ -642,13 +752,19 @@ def __init__(self, parent): def validate(self, d): """check whether data is a valid script""" + + if (d is None) or (d == '') or (d == text_type('')): + self.set_data(text_type('')) + return True + script = BaseString.parse(d, parent=self) + assert bool(script) + # NOTE: trying to check the BASH script: shellcheck & bash -n 'string': fd, path = tempfile.mkstemp() try: with os.fdopen(fd, 'w') as tmp: -# print(script) tmp.write(script) _cmd = ["bash", "-n", path] @@ -696,15 +812,14 @@ def validate(self, d): class DockerComposeRef(URI): def __init__(self, parent): URI.__init__(self, parent) - self._default_data = "docker-compose.yml" + self._default_data = text_type('docker-compose.yml') def validate(self, d): """check whether data is a valid docker-compose file name""" - ref = URI.parse(d, parent=self) - self.set_data(ref) - return True - # TODO: call docker-compose on the referenced file! in DockerService! + # TODO: call docker-compose on the referenced file! in DockerService! + + return URI.validate(self, d) ############################################################### @@ -714,16 +829,13 @@ def __init__(self, parent): def validate(self, d): """check whether data is a valid icon file name""" - ref = URI.parse(d, parent=self) - # TODO: check the file contents (or extention) - - self.set_data(ref) - return True + # TODO: FIXME: check the file contents (or extention) + return URI.validate(self, d) ############################################################### -import subprocess # , shlex +import subprocess # , shlex class HostAddress(BaseString): """SSH alias""" @@ -736,22 +848,40 @@ def validate(self, d): _h = BaseString.parse(d, parent=self) - _cmd = ["ssh", "-o", "ConnectTimeout=2", _h, "exit 0"] + if not self.check_ssh_alias(_h): + if PEDANTIC: + return False + + self.set_data(_h) + return True + + @classmethod + def check_ssh_alias(cls, _h): + """Check for ssh alias""" + try: - # NOTE: Check for ssh alias! + _cmd = ["ssh", "-o", "ConnectTimeout=2", _h, "exit 0"] subprocess.check_call(_cmd, stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) - _ret = True + return True except subprocess.CalledProcessError as err: print("WARNING: non-functional ssh alias: '{0}' => exit code: {1}!" . format(text_type(_h), err.returncode)) - _ret = not PEDANTIC # TODO: add a special switch? except: # Any other exception is wrong... print("WARNING: non-functional ssh alias: '{0}'. Moreover: Unexpected error: {1}" . format(text_type(_h), sys.exc_info())) - _ret = not PEDANTIC # TODO: add a special switch? - if _ret: - self.set_data(_h) + return False - return _ret + @classmethod + def parse(cls, d, parent=None): + self = cls(parent) + + if d is None: + d = self._default_data + + if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! + return self # .get_data() + + # NOTE: .parse should! + raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) ############################################################### class HostMACAddress(BaseString): @@ -771,7 +901,6 @@ def validate(self, d): # TODO: verify the existence of that MAC address? self.set_data(v) - return True ############################################################### @@ -810,12 +939,26 @@ class VariadicRecordWrapper(Base): def __init__(self, parent): Base.__init__(self, parent) - self._type_tag = "type" + self._type_tag = text_type('type') self._type_cls = None self._default_type = None self._types = {} + # TODO: FIXME: make sure to use this .parse instead of .validate due to substitution in Wrapper objects!!! + + @classmethod + def parse(cls, d, parent=None): + """Will return a Validator of a different class""" + + self = cls(parent) # temporary wrapper object + + if d is None: + d = self._default_data + + if self.validate(d): + return self.get_data() + def validate(self, d): """determine the type of variadic data for the format version""" @@ -834,7 +977,7 @@ def validate(self, d): _key_error(self._type_tag, d, _lc, "ERROR: Missing mandatory key `{}`") return False - t = self._type_cls.parse(d[self._type_tag], parent=self) + t = self._type_cls.parse(d[self._type_tag], parent=self.get_parent()) ### ???? if t not in _rule: _lc = d.lc # start of the current mapping @@ -848,7 +991,7 @@ def validate(self, d): _value_error('*', d, _lc, "ERROR: invalid mapping value '{}' for type '%s'" % t) return False - self.set_data(tt.get_data()) + self.set_data(tt) # TODO: completely replace this with tt??? access Methods? return True @@ -897,8 +1040,6 @@ def __init__(self, parent): self._types[self._default_type] = _dc - - ############################################################### class DockerMachine(BaseRecord): """DockerMachine :: StationPowerOnMethod""" @@ -906,15 +1047,15 @@ class DockerMachine(BaseRecord): def __init__(self, parent): BaseRecord.__init__(self, parent) - self._type_tag = "type" + self._type_tag = text_type('type') - self._default_type = "DockerMachine" + self._default_type = 'DockerMachine' DM_rule = { self._type_tag: (True, StationPowerOnMethodType), # Mandatory! - "auto_turnon": (False, AutoTurnon), - "vm_name": (True, BaseString), - "vm_host_address": (True, HostAddress) + text_type('auto_turnon'): (False, AutoTurnon), + text_type('vm_name'): (True, BaseString), + text_type('vm_host_address'): (True, HostAddress) } self._types = {self._default_type: DM_rule} # ! NOTE: AMT - maybe later... @@ -925,13 +1066,13 @@ class WOL(BaseRecord): def __init__(self, parent): BaseRecord.__init__(self, parent) - self._type_tag = "type" - self._default_type = "WOL" + self._type_tag = text_type('type') + self._default_type = 'WOL' WOL_rule = { self._type_tag: (True, StationPowerOnMethodType), # Mandatory! - "auto_turnon": (False, AutoTurnon), - "mac": (True, HostMACAddress) + text_type('auto_turnon'): (False, AutoTurnon), + text_type('mac'): (True, HostMACAddress) } self._types = {self._default_type: WOL_rule} @@ -944,10 +1085,10 @@ class DockerComposeService(BaseRecord): def __init__(self, parent): BaseRecord.__init__(self, parent) - self._type_tag = "type" - self._hook_tag = "auto_detections" - self._name_tag = "ref" - self._file_tag = "file" + self._type_tag = text_type('type') + self._hook_tag = text_type('auto_detections') + self._name_tag = text_type('ref') + self._file_tag = text_type('file') _compose_rule = { self._type_tag: (True, ServiceType), # Mandatory @@ -958,6 +1099,7 @@ def __init__(self, parent): self._default_type = "default_dc_service" self._types = {self._default_type: _compose_rule} + self._create_optional = True def validate(self, d): @@ -967,11 +1109,19 @@ def validate(self, d): _d = self.get_data() + # TODO: remove Validators (BaseString) from strings used as dict keys! _f = _d[self._file_tag] - assert os.path.exists(_f) + while isinstance(_f, AbstractValidator): + _f = _f.get_data() + + assert os.path.exists(_f) # TODO: FIXME: use URI::check() instead?? _n = _d[self._name_tag] + + while isinstance(_n, AbstractValidator): + _n = _n.get_data() + # TODO: Check the corresponding file for such a service -> Service in DockerService! DC = "docker-compose" @@ -988,7 +1138,7 @@ def validate(self, d): _ret = not PEDANTIC # TODO: add a special switch? with open(path, 'r') as tmp: - dc = load_yaml(tmp) + dc = load_yaml(tmp) # NOTE: loading external Docker-Compose's YML file using our validating loader! ss = None for k in dc['services']: if k == _n: @@ -1015,10 +1165,10 @@ def __init__(self, parent): _compose_rule = (self._types[self._default_type]).copy() _compose_rule.update({ - "name": (True, BaseUIString), # NOTE: name for UI! - "description": (True, BaseUIString), - "icon": (False, Icon), - "compatibleStations": (True, Group) + text_type('name'): (True, BaseUIString), # NOTE: name for UI! + text_type('description'): (True, BaseUIString), + text_type('icon'): (False, Icon), + text_type('compatibleStations'): (True, Group) }) self._types[self._default_type] = _compose_rule @@ -1034,11 +1184,11 @@ def __init__(self, parent): self._default_type = "default_profile" default_rule = { - "name": (True, BaseUIString), - "description": (True, BaseUIString), - "icon": (False, Icon), - "services": (True, ServiceList), - "supported_types": (False, ServiceTypeList) + text_type('name'): (True, BaseUIString), + text_type('description'): (True, BaseUIString), + text_type('icon'): (False, Icon), + text_type('services'): (True, ServiceList), + text_type('supported_types'): (False, ServiceTypeList) } self._types = {self._default_type: default_rule} @@ -1054,11 +1204,11 @@ def __init__(self, parent): self._default_type = "default_station_ssh_options" default_rule = { - "user": (False, BaseString), - "key": (False, BaseString), - "port": (False, BaseString), + text_type('user'): (False, BaseString), + text_type('key'): (False, BaseString), + text_type('port'): (False, BaseString), # TODO: BaseInt?? http://stackoverflow.com/questions/4187185/how-can-i-check-if-my-python-object-is-a-number - "key_ref": (False, URI), + text_type('key_ref'): (False, URI), } self._types = {self._default_type: default_rule} @@ -1073,30 +1223,89 @@ def validate(self, data): ############################################################### -class Station(BaseRecord): +class Station(BaseRecord): # Wrapper """Station""" + _extends_tag = text_type('extends') + _client_settings_tag = text_type('client_settings') + def __init__(self, parent): BaseRecord.__init__(self, parent) self._default_type = "default_station" default_rule = { - "name": (True, BaseUIString), - "description": (True, BaseUIString), - "icon": (False, Icon), - "extends": (False, StationID), - "profile": (True, ProfileID), - "address": (True, HostAddress), - "poweron_settings": (False, StationPowerOnMethodWrapper), # !! variadic, PowerOnType... - "ssh_options": (False, StationSSHOptions), # !!! record: user, port, key, key_ref - "omd_tag": (True, StationOMDTag), # ! like ServiceType: e.g. agent. Q: Is this mandatory? - "hidden": (False, StationVisibility), # Q: Is this mandatory? - "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) - } + self._extends_tag: (False, StationID), + text_type('name'): (True, BaseUIString), + text_type('description'): (True, BaseUIString), + text_type('icon'): (False, Icon), + text_type('profile'): (True, ProfileID), + text_type('address'): (True, HostAddress), + text_type('poweron_settings'): (False, StationPowerOnMethodWrapper), # !! variadic, PowerOnType... + text_type('ssh_options'): (False, StationSSHOptions), # !!! record: user, port, key, key_ref + text_type('omd_tag'): (True, StationOMDTag), # ! like ServiceType: e.g. agent. Q: Is this mandatory? + text_type('hidden'): (False, StationVisibility), # Q: Is this mandatory? + self._client_settings_tag : (False, StationClientSettings) # IDMap : (BaseID, BaseString) + } # text_type('type'): (False, StationType), # TODO: ASAP!!! self._types = {self._default_type: default_rule} + def get_base(self): + _d = self.get_data() + assert _d is not None + _b = _d.get(self._extends_tag, None) # StationID (validated...) + + if _b is not None: + if isinstance(_b, AbstractValidator): + _b = _b.get_data() + + return _b + + def extend(delta, base): # delta == self! + assert delta.get_base() is not None + assert base.get_base() is None + + # assert delta.get_base() == base # ? + return delta + + # + # TODO: the following needs an update due to changes in API - not a clean merge - apply delta! + # + + d = delta.get_data() + + new = {} + + for k in base: + if k == delta._extends_tag: + continue + + if k in delta: + v = delta.get(k, None) + + if v is None: + new[k] = base[k] + continue + + if k == delta._client_settings_tag: + t = base.get(k, {}).copy() + + assert isinstance(t, dict) + assert isinstance(v, dict) + + t.update(v) + new[k] = t + else: + new[k] = v # overwrite the rest + else: + new[k] = base[k] + + for k in delta: + if not ((k == delta._extends_tag) or (k in new)): + new[k] = delta[k] + + return new + ############################################################### class BaseIDMap(Base): @@ -1115,38 +1324,50 @@ def detect_type(self, d): return self._default_type - def validate(self, data): - _type = self.detect_type(data) - - assert not (_type is None) - assert _type in self._types + def validate(self, d): + self._type = self.detect_type(d) - (_id, _rule) = self._types[_type] + assert self._type is not None + assert self._type in self._types - _ret = True + (_id_rule, _rule) = self._types[self._type] - _lc = data.lc # starting position? + _lc = d.lc # starting position? (s, c) = (_lc.line, _lc.col) _d = {} - for offset, k in enumerate(data): - v = data.get(k) # TODO: data[offset]??? + + _ret = True + for offset, k in enumerate(d): + v = d[k] # TODO: d[offset]??? l = s + offset _lc = (l, c) - id = _id(self) +# pprint(k) +# print(type(k)) - if not id.validate(k): - _key_error(k, v, _lc, "Invalid Key ID: '{}' (type: '%s')" % (_type)) # Raise Exception? + _id = None + _vv = None + + try: + _id = _id_rule.parse(k, parent=self) + except ConfigurationError as err: + _key_error(k, v, _lc, "Invalid ID: '{}' (type: '%s')" % (self._type)) # Raise Exception? + pprint(err) _ret = False - else: - vv = _rule(self) - if not vv.validate(v): - _value_error(k, v, _lc, "invalid value '{}' value (type: '%s')" % (_type)) # Raise Exception? - _ret = False - elif _ret: - _d[id.get_data()] = vv.get_data() + try: + _vv = _rule.parse(v, parent=self) + except ConfigurationError as err: + _value_error(k, v, _lc, "invalid Value (for ID: '{}') (type: '%s')" % (self._type)) # Raise Exception? + pprint(err) + _ret = False + + if _ret: + assert _id is not None + assert _vv is not None + # _id = _id.get_data() # ?? + _d[_id] = _vv # .get_data() if _ret: self.set_data(_d) @@ -1168,13 +1389,14 @@ def __init__(self, parent): ############################################################### -class StationClientSettings( - BaseIDMap): # "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) +# "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) +class StationClientSettings(BaseIDMap): def __init__(self, parent): BaseIDMap.__init__(self, parent) self._default_type = "default_station_client_settings" self._types = { - self._default_type: (ClientVariable, BaseScalar)} # ! TODO: only strings for now! More scalar types?! + self._default_type: (ClientVariable, BaseScalar) + } # ! TODO: only strings for now! More scalar types?! BaseScalar? ############################################################### @@ -1196,46 +1418,15 @@ def __init__(self, parent): # ### TODO: Any post processing? # return _ret -def extend_dict(base, delta, _ext): - new = {} - - for k in base: - if k == _ext: - continue - - if k in delta: - v = delta.get(k, None) - - if v is None: - new[k] = base[k] - continue - - if k == 'client_settings': - t = base.get(k, {}).copy() - - assert isinstance(t, dict) - assert isinstance(v, dict) - - t.update(v) - new[k] = t - else: - new[k] = v # overwrite the rest - else: - new[k] = base[k] - - - for k in delta: - if not ((k == _ext) or (k in new)): - new[k] = delta[k] - - return new ############################################################### class GlobalStations(BaseIDMap): + """Global mapping of station IDs to Station's""" + def __init__(self, parent): BaseIDMap.__init__(self, parent) self._default_type = "default_global_stations" - self._types = {self._default_type: (StationID, Station)} + self._types = {self._default_type: (StationID, Station)} # NOTE: {StationID -> Station} def validate(self, d): """Extension mechanism on top of the usual ID Mapping parsing""" @@ -1243,8 +1434,6 @@ def validate(self, d): if not BaseIDMap.validate(self, d): return False - _ext = 'extends' - sts = self.get_data() self.set_data(None) @@ -1252,11 +1441,15 @@ def validate(self, d): _processed = {} _todo = {} + for k in sts: - v = sts[k] - if v.get(_ext, None) is None: + v = sts[k] # TODO: popitem as below? + _b = v.get_base() + + if _b is None: # TODO: FIXME: add to Station API! _processed[k] = v else: + assert _b in sts # NOTE: any station extends some _known_ station! _todo[k] = v _chg = True @@ -1265,17 +1458,34 @@ def validate(self, d): _rest = {} while bool(_todo): k, v = _todo.popitem() - assert _ext in v - base = v[_ext] - if base in _processed: - _processed[k] = extend_dict(_processed[base], v, _ext) + +# print(k, ' :subj: ', type(k)) +# pprint(v) + + _b = v.get_base() + assert k != _b # no infinite self-recursive extensions! + + # print(_b, ' :base: ', type(_b)) + assert _b in _processed + + if _b in _processed: + _processed[k] = v.extend(_processed[_b]) +# pprint(_processed[k]) + # assert _processed[k] extends nothing...??? _chg = True else: _rest[k] = v + _todo = _rest +# pprint(_todo) + +# pprint(_processed) +# pprint(_todo) if bool(_todo): - print('ERROR: Cyclic dependencies between stations: {}!?' .format(_todo)) + print('ERROR: Cyclic dependencies between stations: ') + pprint(_todo) + _ret = False if _ret: @@ -1301,7 +1511,8 @@ def validate(self, d): if (not isinstance(d, (list, dict, tuple, set))) and isinstance(d, string_types): try: - _d = _type.parse(BaseString.parse(d, parent=self), parent=self) + _d = _type.parse(BaseString.parse(d, parent=self).get_data(), parent=self) + self.get_data(_d) return True except: @@ -1318,7 +1529,7 @@ def validate(self, d): _value_error("[%d]" % idx, d, _lc, "Wrong item in the given sequence!") _ret = False else: - _d.insert(idx, _v.get_data()) # append? + _d.insert(idx, _v) # append? if _ret: self.set_data(_d) @@ -1369,29 +1580,35 @@ def __init__(self, parent): self._default_type = "default_group" - self._include_tag = "include" - self._exclude_tag = "exclude" - self._intersectWith_tag = "intersectWith" + self._include_tag = text_type('include') + self._exclude_tag = text_type('exclude') + self._intersectWith_tag = text_type('intersectWith') default_rule = { self._include_tag: (False, GroupIDList), self._exclude_tag: (False, GroupIDList), - self._intersectWith_tag: (False, GroupIDList), - "name": (False, BaseUIString), - "description": (False, BaseUIString), - "icon": (False, Icon) + self._intersectWith_tag: (False, GroupIDList) } + # text_type('name'): (False, BaseUIString), + # text_type('description'): (False, BaseUIString), + # text_type('icon'): (False, Icon) self._types = {self._default_type: default_rule} def detect_extra_rule(self, key, value): # Any extra unlisted keys in the mapping? +# pprint(key) +# pprint(value) + if value is None: # Set item! - return (GroupID, BaseScalar) + return GroupID, BaseScalar + return None - def validate(self, data): - _ret = BaseRecord.validate(self, data) - # Add extra keys into include? + def validate(self, d): + _ret = BaseRecord.validate(self, d) + + # TODO: FIXME: Add extra keys into include! + return _ret ############################################################### @@ -1436,7 +1653,6 @@ def validate(self, data): # raise NotImplementedError("Presets are not supported yet!") return True - ############################################################### class Hilbert(BaseRecord): """General Hilbert Configuration format""" @@ -1446,12 +1662,12 @@ def __init__(self, parent): self._default_type = "default_global" - self._version_tag = "Version" - self._applications_tag = "Applications" - self._services_tag = "Services" - self._profiles_tag = "Profiles" - self._stations_tag = "Stations" - self._groups_tag = "Groups" + self._version_tag = text_type('Version') + self._applications_tag = text_type('Applications') + self._services_tag = text_type('Services') + self._profiles_tag = text_type('Profiles') + self._stations_tag = text_type('Stations') + self._groups_tag = text_type('Groups') ### explicit (optional) Type? default_rule = { @@ -1461,7 +1677,7 @@ def __init__(self, parent): self._profiles_tag: (True, GlobalProfiles), self._stations_tag: (True, GlobalStations), self._groups_tag: (False, GlobalGroups), # Optional - "Presets": (False, GlobalPresets), # Optional. May be removed! default? + text_type('Presets'): (False, GlobalPresets), # Optional. May be removed! default? } self._types = {self._default_type: default_rule} @@ -1472,6 +1688,9 @@ def __init__(self, parent): def parse(cls, d, parent=None): self = cls(parent) + if d is None: + d = self._default_data + if self._version_tag not in d: _key_note(self._version_tag, d.lc, "ERROR: Missing mandatory '{}' key field!") raise ConfigurationError(u"{}: {}".format("ERROR:", "Missing version tag '{0}' in the input: '{1}'!".format(self._version_tag, d))) @@ -1518,16 +1737,24 @@ def validate(self, data): # ! TODO: check for GroupID <-> StationID <-> ProfileID return _ret - def show(self, what): _d = self.get_data() - + + s = BaseString(self) + + _isstr = s.validate(what) + if what == 'all': print(self) - elif what in _d: - print(_d[what]) + if what == 'keys': + pprint([k for k in _d.keys()]) + elif isinstance(what, AbstractValidator) and (what in _d): + pprint(_d[what]) + elif _isstr and (s in _d): + pprint(_d[s]) else: - raise ConfigurationError(u"{}: {}".format("ERROR:", "Sorry cannot show '{0}' of {1}!" . format(what, type(self)))) + raise ConfigurationError(u"{}: {}".format("ERROR:", + "Sorry cannot show '{0}' of {1}!" . format(what, type(self)))) ############################################################### @@ -1543,15 +1770,14 @@ def load_yaml_file(filename): with open(filename, 'r') as fh: return load_yaml(fh) + ############################################################### def parse_hilbert(d, parent=None): - cfg = Hilbert(None) + assert d is not None + + cfg = Hilbert(parent) if not cfg.validate(d): -# pprint(d) raise ConfigurationError(u"{}: {}".format("ERROR:", "Cannot parse given configuration!")) return cfg - # return Hilbert.parse(d, parent=parent) - - diff --git a/config/tests/data/Hilbert.yml.data.pickle b/config/tests/data/Hilbert.yml.data.pickle index e24eb793f402db70add6cf76ff369fbea80394a8..bbff63ad15c516d2389a14c43678d61eb75cba25 100644 GIT binary patch literal 11437 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 literal 3878 zcma)9hkM)B5m#(WlqoBc?bxZ)45V>gy0t)4vSf>?>(CM{DUwK;;IommEDC}UA8HWb zVaQTbG*MftQq#Tn-h1!8N1E=v_g?=&4-WtZGK#)R-=|L>aPRJS_q+SO!#z6`s_9kL zawJ99B*ioqwR&$qpNV02Rl-vM{-u0str3m*d<=w)zwu~7iCv>q`GcaWgWUb z=t+sa_(E`GM>7o@66;&}o?`ZqQ4)IBV7HjSa|@PgtBwuHjR!v#+9aWG4fe2T3zoU4 z=?JWUn`n_y60Tl@0dWsT%Qc(2ri4fbw>cX(Ov2tZ*vHUbP%Rs?g#B9{71V}oIGPe# zCE=PiI3V_5+$qa+n>HNWCdt4g3D>T{LxPH`){>@Rj)%4k7FIMgO2Tz(@KDz#dnGxR zqvXhSxSkG@J!iiX@r= zrEpYC23AH*)=fi&N0I?-QbZtOqd1yTx8YG997~DUq22V%+}V7oEG?As=kldeeo~st z6{bjTDi1?sM@-Iwt0Y<5W|1c?E`NuMzid^&Upn#e*@|6GSK% z=V$KBm1l|t0Zx#Fv2;wgnFiEj7@+mq*d77rjsZUe9 zNlN*t8KGRdLz>K$bJ9YtJPqd*%f*7|{EFPrd0UZn*|HrhVm&F~A6-4~nvPl%*b5Ee9eOY?zzro(0!vedeUE>?#8K}f^&6_{Ct+dY`A(&5=IIVbj+w$zZ= zY}LY?hG=!j&uK^omF!}Ax+wNzq)Ah`q+0VbUU(>Pb<*d{hvc|8rv}hWLIh znznU`pXg%o{YyDBKFnvvPVwX8eCGH#T%u<-u=IZC`#E46a}P)^2YN72K0-fO1{xk1 zF&#ELN52_r2e6T2)yaUhsTFqT0cVR^xgIQ~$j*kWz-6XznM`(gI6E?uJ#ivCI+`6D zgXOSTE8>cr6Wj%0{~e-Oa>XFdHf- zlyim2++4AckBEnRTy!6;C94I}8|@MBR1cn(3Ir!;%%^*B1#dZj7}-s|R)J@v#9aux z=`@yMok^CjrNOXlsAK>ItZ7;(DdA@I%nIDgRtv>!G)-HDXUXkgpDi9ne>r1?o6`(; zxuutvHRR28xbr0r)yXhW|DF>v^xQbc=eco-e7*-Sh$DVs1zr?G{NfJ8FJT;D2Jlk0 zlSJAEFJmtnMjc+hMN+S*z$@F5dR0eKuVxGs4Sj`MG_6otS`54<%;U9j`whFwx4e>iV5WiEr5u>+JU~@hP zaRS~I0)ICvR@su3OE`V-9=CHe-s{2p;wikp0v~u_Z+x%J}34e#+Ig|q<>x}{cJ6^4`I{jo&n{$_X@@Ah!9Y}*(;_!gUP|JwuZ7x$sJ8WZ!OaC-Tb zh7R8*J1un)zSCC0@3Mm$?h5d|0`BRF=u_hRsoAdC?%Caif&)JwJ>i$a4?Xx1JKtDg zD>wYugP*i%&rb^^p)Lni|5*io9!bZe(AxlQmrZewFkdJ`Ss!bw)OCL zVX=PSR;)kJ`xz%Sg(dYzdLNsBuuj-lu_8sAh6jHNZk0{V`?Cjs2_ycsV=(^~#{GL+ z+<#!)2Py175re;Z{hwU@%f-g-m%^36W()1VX#yXG-x|TA|ImKlDl8bY`Y%1?R{8${ DWGF0U diff --git a/config/tests/test_validate.py b/config/tests/test_validate.py index 8e9cc47..dcdda37 100644 --- a/config/tests/test_validate.py +++ b/config/tests/test_validate.py @@ -11,11 +11,6 @@ sys.path.append( DIR ) - -#from hilbert_cli_config import pprint, INPUT_DIRNAME -#from hilbert_cli_config import load_yaml, load_yaml_file, parse_hilbert, Hilbert -#from helpers import pickle_load - from hilbert_cli_config import * from helpers import * @@ -61,6 +56,7 @@ def test_1(self, capsys): assert type(d) == type(cfg) -# pprint(cfg) -# pprint(d) + pprint(cfg) + pprint(d) + assert d == cfg diff --git a/config/tests/test_version.py b/config/tests/test_version.py index ab5ca4d..cd5a7b8 100644 --- a/config/tests/test_version.py +++ b/config/tests/test_version.py @@ -19,23 +19,29 @@ def load(s): class TestVersions: def test_1(self): v = '0.0' - assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v))) + assert Version.parse(v, partial=True, coerce=True) == \ + SemanticVersion.parse(load("'{}'" . format(v)), partial=True, coerce=True) v = '0.1' - assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v))) + assert Version.parse(v, partial=True, coerce=True) == \ + SemanticVersion.parse(load("'{}'" . format(v)), partial=True, coerce=True) v = '1.2' - assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v))) + assert Version.parse(v, partial=True, coerce=True) == \ + SemanticVersion.parse(load("'{}'" . format(v)), partial=True, coerce=True) def test_2(self): v = '0.0.1' - assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v))) + assert Version.parse(v, partial=True, coerce=True) == \ + SemanticVersion.parse(load("'{}'" . format(v)), partial=True, coerce=True) v = '0.1.2' - assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v))) + assert Version.parse(v, partial=True, coerce=True) == \ + SemanticVersion.parse(load("'{}'" . format(v)), partial=True, coerce=True) v = '1.2.3' - assert Version.parse(v, partial=True, coerce=True) == SemanticVersion.parse(load("'{}'" . format(v))) + assert Version.parse(v, partial=True, coerce=True) == \ + SemanticVersion.parse(load("'{}'" . format(v)), partial=True, coerce=True) \ No newline at end of file diff --git a/tools/hilbert.py b/tools/hilbert.py index e909ebc..054d03f 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -10,10 +10,8 @@ import sys from os import path -DIR=path.dirname( path.dirname( path.abspath(__file__) ) ) -sys.path.append( path.join(DIR, 'config' ) ) -# sys.path.append( DIR ) - +DIR=path.dirname(path.dirname(path.abspath(__file__))) +sys.path.append(path.join(DIR, 'config')) from helpers import * from hilbert_cli_config import * @@ -27,6 +25,7 @@ import logging # log = logging.getLogger(__name__) + def _version(): import platform import dill @@ -36,6 +35,7 @@ def _version(): print("## dill Version: '{}'".format(dill.__version__)) # arghandler version? dill version? etc? + def _load(f): print("## YAML Validation: ") return load_yaml_file(f) # TODO: check that this is a dictionary! @@ -96,12 +96,12 @@ def cmd_verify(parser, context, args): print("ERROR: semantically wrong input!") exit(1) - print("## Input file is a good Hilbert configuration!") - -# return cfg + print("## Input file '{}' contains good valid Hilbert configuration!" . format(fn)) + print("## Done") + exit(0) -@subcmd('cfg_dump', help='Load input .YAML or .Pickle file and dump it') +@subcmd('cfg_dump', help='Load input .YAML or .Pickle file and display/dump it') def cmd_dump(parser, context, args): global PEDANTIC global INPUT_DIRNAME @@ -110,7 +110,7 @@ def cmd_dump(parser, context, args): # parser.add_argument('-O', '--outputdir', required=False, default=argparse.SUPPRESS, # help="specify output directory (default: alongside with the output dump file)") - parser.add_argument('-od', '--outputdump', required=True, default=argparse.SUPPRESS, + parser.add_argument('-od', '--outputdump', default=argparse.SUPPRESS, help="specify output dump file") ctx = vars(context) @@ -182,25 +182,25 @@ def cmd_dump(parser, context, args): od = None + f = URI(None) + if 'outputdump' in args: od = args['outputdump'] assert od is not None - elif fn is not None: - od = os.path.splitext(os.path.basename(fn))[0] + '.pickle' -# OUTPUT_DIRNAME = INPUT_DIRNAME - else: - assert df is not None - od = os.path.splitext(os.path.basename(df))[0] + '.pickle' -# OUTPUT_DIRNAME = INPUT_DIRNAME - +# elif fn is not None: +# od = os.path.splitext(os.path.basename(fn))[0] + '.pickle' +## OUTPUT_DIRNAME = INPUT_DIRNAME +# else: +# assert df is not None +# od = os.path.splitext(os.path.basename(df))[0] + '.pickle' +## OUTPUT_DIRNAME = INPUT_DIRNAME - f = URI(None) - if not f.validate(od): - if not PEDANTIC: - print("## WARNING: Output dump file: '{}' already exists!".format(od)) - else: - print("## ERROR: Output dump file: '{}' already exists!".format(od)) - exit(1) + if not f.validate(od): + if not PEDANTIC: + print("## WARNING: Output dump file: '{}' already exists!".format(od)) + else: + print("## ERROR: Output dump file: '{}' already exists!".format(od)) + exit(1) cfg = None if fn is not None: @@ -230,11 +230,16 @@ def cmd_dump(parser, context, args): print("ERROR: semantically wrong input!") exit(1) - print("## Input is OK!") + print("## Input is OK: ") + print(cfg) + - print("## Writing the configuration into '{}'..." . format(od)) - pickle_dump(od, cfg) - print("## Pickled configuration is now in '{}'!" . format(od)) + if od is not None: + print("## Writing the configuration into '{}'..." . format(od)) + pickle_dump(od, cfg) +# print("## Pickled configuration is now in '{}'!" . format(od)) + print("## Done") + exit(0) # return cfg @@ -320,7 +325,6 @@ def cmd_show(parser, context, args): except: print("ERROR: wrong input dump file: '{}'!" . format(df)) raise - if cfg is None: print("ERROR: could not get the configuration!") @@ -335,11 +339,14 @@ def cmd_show(parser, context, args): try: print("## Showing: '{}' for the configuration" . format(obj)) - cfg.show(obj) + cfg.show(obj) # TODO pprint(QUERY!!!) except: print("## ERROR: Sorry cannot show '{}' yet!" . format(obj)) exit(1) + print("## Done") + exit(0) + def main(): handler = ArgumentHandler(use_subcommand_help=True, enable_autocompletion=True, description="Validate/Parse Hilbert Configuration") From e570cf5df44b75c2ec76df84f1d5e37a3dd31100 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Mon, 21 Nov 2016 03:39:38 +0100 Subject: [PATCH 19/42] Added generic Quering and Data-Dumping to Validators + corresponding sub-commands to the hilbert tool CHG: improved Version Validator (keep semantic Version object, but show a version string) ADD: switched to logging instead of printing --- config/helpers.py | 6 - config/hilbert_cli_config.py | 195 +++++---- config/tests/data/Hilbert.yml.data.pickle | Bin 11437 -> 11055 bytes config/tests/test_validate.py | 8 +- config/tests/test_version.py | 26 +- tools/hilbert.py | 493 +++++++++++----------- 6 files changed, 395 insertions(+), 333 deletions(-) diff --git a/config/helpers.py b/config/helpers.py index 2b45a0c..02825e3 100644 --- a/config/helpers.py +++ b/config/helpers.py @@ -22,9 +22,3 @@ def pickle_load(fn): with open(fn, 'rb') as p: d = pickle.load(p) return d - -############################################################### - -def yaml_dump(d, stream=None): - import ruamel.yaml as yaml - print(yaml.round_trip_dump(d, stream=stream)) diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index 9aa09ec..d1e3dfc 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -5,17 +5,18 @@ from __future__ import absolute_import, print_function, unicode_literals import logging -# log = logging.getLogger(__name__) +log = logging.getLogger(__name__) # from .helpers import load_yaml, pprint ############################################################### import pprint as PP +_pp = PP.PrettyPrinter(indent=4) def pprint(cfg): - print("## Validated/Parsed pretty Result: ") - pp = PP.PrettyPrinter(indent=2) - pp.pprint(cfg) +# print("## Validated/Parsed pretty Result: ") + global _pp + _pp.pprint(cfg) # TODO: use loggger? # PP.pformat @@ -38,8 +39,7 @@ def _get_line_col(lc): try: l = lc.line except: - print("Unexpected error: ", sys.exc_info()[0]) - print("Cannot get line out of: ", lc) + log.exception("Cannot get line out of '{}': Missing .line attribute!".format(lc)) raise try: @@ -48,8 +48,7 @@ def _get_line_col(lc): try: c = lc.column except: - print("Unexpected error: ", sys.exc_info()[0]) - print("Cannot get col/column out of: ", lc) + log.exception("Cannot get column out of '{}': Missing .col/.column attributes!".format(lc)) raise return l, c @@ -77,7 +76,7 @@ def _key_note(key, lc, key_message, e='K'): (line, col) = _get_line_col(lc) if key is None: - key = '*' + key = '?' print('{}[line: {}, column: {}]: {}'.format(e, line + 1, col + 1, key_message.format(key))) print('---') @@ -87,7 +86,7 @@ def _value_error(key, value, lc, error, e='E'): (line, col) = _get_line_col(lc) if key is None: - key = '*' + key = '?' val_col = col + len(key) + 2 print('{}[line: {}, column: {}]: {}'.format(e, line + 1, val_col + 1, error.format(key))) @@ -242,7 +241,7 @@ def get_data(self): # if _d is None: # return _d -# while isinstance(_d, AbstractValidator): +# while isinstance(_d, Base): # _d = _d.get_data() # if _d is None: # return _d @@ -275,18 +274,90 @@ def __repr__(self): # return str(d) def __eq__(self, other): - assert isinstance(self, AbstractValidator) + assert isinstance(self, Base) - if not isinstance(other, AbstractValidator): + if not isinstance(other, Base): return self.get_data() == other - assert isinstance(other, AbstractValidator) + assert isinstance(other, Base) return self.get_data() == other.get_data() def __ne__(self, other): return not (self == other) # More general than self.value != other.value + def data_dump(self): + _d = self.get_data() + + if _d is None: + return _d + + assert not isinstance(_d, (tuple, set)) + + if isinstance(_d, dict): + _dd = {} + for k in _d: + v = _d[k] + if isinstance(v, Base): + v = v.data_dump() + _dd[k] = v + return _dd + + if isinstance(_d, list): + _dd = [] + for idx, i in enumerate(_d): + v = i + if isinstance(v, Base): + v = v.data_dump() + _dd.insert(idx, v) + return _dd + +# if isinstance(_d, string_types): + return _d + + + + + + + + + def query(self, what): + log.debug("Querying '%s'", what) + + if (what is None) or (what == ''): + what = 'all' + + if what == 'all': + return self + + _d = self.get_data() + + if what == 'keys': + return _d.keys() + + s = BaseString.parse(what, parent=self) + + if s in _d: + return _d[s] + + sep = "/" + ss = s.split(sep) # NOTE: encode using pathes! + + h = ss[0] # top header + t = sep.join(ss[1:]) # tail + + if h in _d: + d = _d[ss[0]] + if isinstance(d, Base): + return d.query(t) + + log.warning("Could not query an object. Ignorring the tail: %s", t) + return d + + raise ConfigurationError(u"{}: {}".format("ERROR:", + "Sorry cannot show '{0}' of {1}!".format(what, type(self)))) + ############################################################### class BaseRecord(Base): @@ -478,11 +549,10 @@ def validate(self, d): class SemanticVersion(BaseString): - def __init__(self, parent, partial=True, coerce=True): + def __init__(self, parent, partial=False): BaseString.__init__(self, parent) self._partial = partial - self._coerce = coerce def validate(self, d): """check the string data to be a valid semantic verions""" @@ -492,7 +562,7 @@ def validate(self, d): # self.get_version(None) # ??? _v = None try: - _v = semantic_version.Version.parse(_t, partial=self._partial, coerce=self._coerce) + _v = semantic_version.Version(_t, partial=self._partial) except: print("ERROR: wrong version data: '{0}' (see: '{1}')" . format(d, sys.exc_info())) return False @@ -501,18 +571,21 @@ def validate(self, d): return True @classmethod - def parse(cls, d, parent=None, partial=True, coerce=True): - self = cls(parent, partial=partial, coerce=coerce) + def parse(cls, d, parent=None, partial=False): + self = cls(parent, partial=partial) - if d is None: - d = self._default_data + assert d is not None +# d = self._default_data if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! - return self.get_data() + return self # keep the validator to handle some general actions via its API: e.g. data_dump # NOTE: .parse should! raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) + def data_dump(self): + return str(self.get_data()) + ############################################################### class BaseUIString(BaseString): # visible to user => non empty! def __init__(self, parent): @@ -1112,14 +1185,14 @@ def validate(self, d): # TODO: remove Validators (BaseString) from strings used as dict keys! _f = _d[self._file_tag] - while isinstance(_f, AbstractValidator): + while isinstance(_f, Base): _f = _f.get_data() assert os.path.exists(_f) # TODO: FIXME: use URI::check() instead?? _n = _d[self._name_tag] - while isinstance(_n, AbstractValidator): + while isinstance(_n, Base): _n = _n.get_data() # TODO: Check the corresponding file for such a service -> Service in DockerService! @@ -1256,7 +1329,7 @@ def get_base(self): _b = _d.get(self._extends_tag, None) # StationID (validated...) if _b is not None: - if isinstance(_b, AbstractValidator): + if isinstance(_b, Base): _b = _b.get_data() return _b @@ -1343,9 +1416,6 @@ def validate(self, d): l = s + offset _lc = (l, c) -# pprint(k) -# print(type(k)) - _id = None _vv = None @@ -1459,9 +1529,6 @@ def validate(self, d): while bool(_todo): k, v = _todo.popitem() -# print(k, ' :subj: ', type(k)) -# pprint(v) - _b = v.get_base() assert k != _b # no infinite self-recursive extensions! @@ -1470,22 +1537,15 @@ def validate(self, d): if _b in _processed: _processed[k] = v.extend(_processed[_b]) -# pprint(_processed[k]) # assert _processed[k] extends nothing...??? _chg = True else: _rest[k] = v _todo = _rest -# pprint(_todo) - -# pprint(_processed) -# pprint(_todo) if bool(_todo): - print('ERROR: Cyclic dependencies between stations: ') - pprint(_todo) - + log.error('Cyclic dependencies between stations: {}' .format(_todo)) _ret = False if _ret: @@ -1501,35 +1561,40 @@ class BaseList(Base): def __init__(self, parent): Base.__init__(self, parent) + self._default_type = None + self._types = {} + def validate(self, d): assert self._default_type is not None assert len(self._types) > 0 + _lc = d.lc + # NOTE: determine the class of items based on the version and sample data - _type = self._types[self._default_type] - assert _type is not None + self._type = self._types[self._default_type] + assert self._type is not None if (not isinstance(d, (list, dict, tuple, set))) and isinstance(d, string_types): try: - _d = _type.parse(BaseString.parse(d, parent=self).get_data(), parent=self) - + _d = [self._type.parse(BaseString.parse(d, parent=self))] self.get_data(_d) return True except: pass # Not a single string entry... # list!? - _d = [] _ret = True + _d = [] for idx, i in enumerate(d): # What about a string? - _v = _type(self) - if not _v.validate(i): - _lc = d.lc + _v = None + try: + _v = self._type.parse(i, parent=self) + _d.insert(idx, _v) # append? + except ConfigurationError as err: _value_error("[%d]" % idx, d, _lc, "Wrong item in the given sequence!") + pprint(err) _ret = False - else: - _d.insert(idx, _v) # append? if _ret: self.set_data(_d) @@ -1558,9 +1623,8 @@ def __init__(self, parent): self._default_type = "default_ServiceID_list" self._types = {self._default_type: ServiceID} - ############################################################### - +############################################################### class ServiceTypeList(BaseList): """List of ServiceType's or a single ServiceType!""" @@ -1596,8 +1660,6 @@ def __init__(self, parent): self._types = {self._default_type: default_rule} def detect_extra_rule(self, key, value): # Any extra unlisted keys in the mapping? -# pprint(key) -# pprint(value) if value is None: # Set item! return GroupID, BaseScalar @@ -1696,7 +1758,7 @@ def parse(cls, d, parent=None): raise ConfigurationError(u"{}: {}".format("ERROR:", "Missing version tag '{0}' in the input: '{1}'!".format(self._version_tag, d))) try: - _v = SemanticVersion.parse(d[self._version_tag], parent=self) + _v = SemanticVersion.parse(d[self._version_tag], parent=self, partial=True) except: _value_error(self._version_tag, d, d.lc, "Wrong value of global '{}' specification!") raise @@ -1736,26 +1798,6 @@ def validate(self, data): # ! TODO: check Uniqueness of keys among (Profiles/Stations/Groups) !!!! # ! TODO: check for GroupID <-> StationID <-> ProfileID return _ret - - def show(self, what): - _d = self.get_data() - - s = BaseString(self) - - _isstr = s.validate(what) - - if what == 'all': - print(self) - if what == 'keys': - pprint([k for k in _d.keys()]) - elif isinstance(what, AbstractValidator) and (what in _d): - pprint(_d[what]) - elif _isstr and (s in _d): - pprint(_d[s]) - else: - raise ConfigurationError(u"{}: {}".format("ERROR:", - "Sorry cannot show '{0}' of {1}!" . format(what, type(self)))) - ############################################################### def load_yaml(f, Loader=VerboseRoundTripLoader, version=(1, 2), preserve_quotes=True): @@ -1781,3 +1823,8 @@ def parse_hilbert(d, parent=None): return cfg # return Hilbert.parse(d, parent=parent) + + +############################################################### +def yaml_dump(d, stream=None): + return yaml.round_trip_dump(d, stream=stream) diff --git a/config/tests/data/Hilbert.yml.data.pickle b/config/tests/data/Hilbert.yml.data.pickle index bbff63ad15c516d2389a14c43678d61eb75cba25..1845c5b5ccaf3d45a217f9a575f80271fb41db18 100644 GIT binary patch delta 4246 zcmaJ^d0-r672i!s(rgI`Hcd#|9L>^hW13n}TdYQUKw4Uh&}^F)+U;a_lG*8AyqPVH zIF5L%Sw+!~H!9wWiUn^4HR7$HR_hIFQHpoH4;1D1`(}5tSz`Wq-+RCJzVCbA`+djE z?fZ`Jx#N+x4a>}{!=aGTV_wB3dO&ugjg6ia3WW-G_Na`&9BqM>&!!UEgr2h{4oLU% zOWOPPKr=6gSbd}HMdQdQWX$L_H=;EbII_>XZAou06;5_jV=O~(ygSV3wAo6lY`#%?Q7fw!2tY7&hjDaaUe)ae>h*f=rsQphQD6J$vyAk8fhWn*(m z3|g0kLn}jNweFIniEM+IGA=2JN$ZNLb=aF;-s@&y#zq%1JEW3M>Xu{~#_^F%4viyu z2BB_DjX4$2DoPYRtXCaP*RjJ4O#-uyCX3L5P`{#1Y+6i0^og`(%cK;2e<+mAO~?@# zic|M`XjM*+LU&{mvNpHpGJ?D*4(H(V2KZ)i`8)t~ap^Fy9Z6l8%S`r+=cQ-2cSGkn z?(>NU?7FmSsC)rzvfF@;*NNN+v&!rXp*!*-NX6`n>GGL<39(tsmgo$aeJL$4OJY}` zDajO(fY~ywfZ3NRW?v4hj@g?SR$=xP&>eXtgTO3PBeOR%f`{$@G5acZm|^zSFzc8- zMko?GpUY1eS}uhxFCIXj!Ph{mGWc5Pj=T=CHiy?UVm=1nfPh&Hz7fD&48DnhT_9p- zI#)c}W7(R0YGD>Y0%lDwP#fXesK3aET9soeWMV0Bd9#;^*N?}zTl z2N(n@nHs75AS33Z@^)`sSLfCbF|2Y+9*6G89gwvH-N}gg`1r7QsC`NJBi^lDLwz4b z@Jww#MysxjA3xT;bonRXFwVmT^GPUX>UV!G<+9s<#z9u?nRB;w?^dd zinVy{XAoMF&qDHS--Q@F-d3aNykVz*s-qaEK zJYtc+J!l;H0;FQ{iyQ%a7q|MjR?OImR5DSy8RbhV^vhvyP2bY+SG?mr9o}@baZNwbgq0*om7xZI0g7Y*H~;=f5p{R8r?YPWCGdoH?ZMLVBJ>9(F^ z-j=PvfMWgty=Qp7MOZ>ap>*$q!&nsY|gWKdgGvNjzFV zf~6jiA44g!tX!$lJ%!3ri?<~BkR@zwLVg0>%#?uv`uU#L#Mtnc&?0F#7SMdP9B)%Ezb@9hA}5n%yxW`C>tSucH3ID79AoXfjhw>2gLNs2weSt!ro2MW#LB^gVWI#_rGv( zyRgMZ|;luv}$SPWJcLvf@H(!VRCNlVXaIXj(9;3JZ;gJYVdM=Bj7vIL>%*WTc=V+T9N z8?&037r6k&j!?Y0poyKnygbuqXR$F9$?;|mkj0lNX0D+~d^hp7g;cO^_!qwJ)A0#~tL<;=#QJF*&5o!Nf6{1f^lV&)kXx_aCO=$tu! zZb{YpryCa_rV3*3ddONIRr^F*_e+f?pZOV)GbPEfD`iX)dm1{6HK!Mi)w z9p32O9~*F=0Z&Pu3Ca3zM2q^X2K66eH?^Pf<0a36Wj=`cFzlt!9oa-b7qFQw|J~d| zOg$Y_=6wh*$yPdRpQXzP@R}~0l_%_SBD|x^rvKUv1DNB9GHc%@rjAs$p>bq8q)O!q zD5n1??Vx%JqpGYeYvxU%ANAkB6H|FqxT4@uF@u-Hob`O{SY3I=g7_Mp5_0 zm9%Q_i{}7PYgU^jl^mSRX5^{{bigfA?q3zY+PkyA&E3tgN{vULI}(Rf3)@4NU*o;R zX4RORV^)p#5%6p5eZXL@VIwyptF4ffYBUpO%x>0uLeuK S4u*I0KwC?iz6*+DgO33)<~St) delta 4727 zcma)9d3+pI9p6pUmZXi?+B6~OhJP?es(7IFLRtrDgM_oF)civ0A0lWVa@=6Ds3O5M-UhU`ZY{&Q%s@TBCGD>Wp(ir;PJJ zt5O0rE&!R<&#%fZN*6{WD(r z3llQ!yL%XRW?Eb9TcGxkd#j3nMJ?W|-z(`s2q~nh`rYP9sKyL;3 zkA=@WVDRv19}A!!J{>qFT9E&xh1_IpyeP3@g}~TwIi&#nYC7;}E9kz4QUIr~g-qzy z!C{xk>mYiteLZ+f?u+-Je` z041Kc5lLlsW^sT%2@T=I)thCkJ(VjKH2DOe1=@XBeUXw6t1l5&!(Zl{;oI;lbgRMYLGYG*l}-Q%QzNXtMvpM8zD|?d z)_5h1e1k5vX7)|+mV65|ILWu^5#FkYpgOwMcqjQg&VwCmdcO;w*$RJ;(wt&`-x=s^ z@B9JhS_1U_5R4^10>#($DD(fZlkV(`KJ4u8JaPVpwT@-ZqC zOR??jy104LIjwdBnR3XP>FORl4410>26T3PzlEea+3%?4H7we=JP!X>e7MPZs;lXw z->bMk(824@UdjIGh5yMpwY#kezE-(fqOxlgXk{Bo_y3nx(DSJ|xaBxKVM-jX;dqc{h$2|ScnQZqM^z-wf{xuu@Rl(d8i|ODy87_|M^fDPdEn#PFZjo*(1)( zK)Zc9-MmZa3@^sJ5nn(@UIF+qs-#UM#~HT(Wc*KfA*}I@k&W{=HVh4w&{GNK@u^>PfBTtPe6b|p=2@7zwE>J?Ll+w6AG z80%m7MNqZS5>0N+cTpFrxzHG_xk-gvbN880 zree0_c2z3S{GT=74OdI{fT~pXaxS;#lVqR0=6=b!Ag|=f$TQXaYJSDP$gY7jr$*OO zE`Bt^axOw|T&aFz@ diff --git a/config/tests/test_validate.py b/config/tests/test_validate.py index dcdda37..4840b9e 100644 --- a/config/tests/test_validate.py +++ b/config/tests/test_validate.py @@ -56,7 +56,11 @@ def test_1(self, capsys): assert type(d) == type(cfg) - pprint(cfg) - pprint(d) + print(cfg) + print(yaml_dump(cfg.data_dump())) + + + print(d) + print(yaml_dump(d.data_dump())) assert d == cfg diff --git a/config/tests/test_version.py b/config/tests/test_version.py index cd5a7b8..29e747e 100644 --- a/config/tests/test_version.py +++ b/config/tests/test_version.py @@ -14,34 +14,28 @@ def load(s): return load_yaml(s) -from semantic_version import Version # supports partial versions +from semantic_version import Version # supports partial versions class TestVersions: def test_1(self): v = '0.0' - assert Version.parse(v, partial=True, coerce=True) == \ - SemanticVersion.parse(load("'{}'" . format(v)), partial=True, coerce=True) + assert Version(v, partial=True) == \ + SemanticVersion.parse(load("'{}'" . format(v)), partial=True).get_data() v = '0.1' - assert Version.parse(v, partial=True, coerce=True) == \ - SemanticVersion.parse(load("'{}'" . format(v)), partial=True, coerce=True) + assert Version(v, partial=True) == \ + SemanticVersion.parse(load("'{}'" . format(v)), partial=True).get_data() v = '1.2' - assert Version.parse(v, partial=True, coerce=True) == \ - SemanticVersion.parse(load("'{}'" . format(v)), partial=True, coerce=True) + assert Version(v, partial=True) == \ + SemanticVersion.parse(load("'{}'" . format(v)), partial=True).get_data() - def test_2(self): v = '0.0.1' - assert Version.parse(v, partial=True, coerce=True) == \ - SemanticVersion.parse(load("'{}'" . format(v)), partial=True, coerce=True) + assert Version(v) == SemanticVersion.parse(load("'{}'" . format(v))).get_data() v = '0.1.2' - assert Version.parse(v, partial=True, coerce=True) == \ - SemanticVersion.parse(load("'{}'" . format(v)), partial=True, coerce=True) + assert Version(v) == SemanticVersion.parse(load("'{}'" . format(v))).get_data() v = '1.2.3' - assert Version.parse(v, partial=True, coerce=True) == \ - SemanticVersion.parse(load("'{}'" . format(v)), partial=True, coerce=True) - - \ No newline at end of file + assert Version(v) == SemanticVersion.parse(load("'{}'" . format(v))).get_data() diff --git a/tools/hilbert.py b/tools/hilbert.py index 054d03f..d5d8606 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -23,337 +23,358 @@ import argparse # NOQA import logging -# log = logging.getLogger(__name__) - +log = logging.getLogger(__name__) # + +# level=logging.INFO!!! , datefmt='%Y.%m.%d %I:%M:%S %p' +logging.basicConfig(format='%(levelname)s [%(filename)s:%(lineno)d]: %(message)s', level=logging.DEBUG) +# %(name)s Name of the logger (logging channel) +# %(levelno)s Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL) +# %(levelname)s Text logging level for the message ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL") +# %(pathname)s Full pathname of the source file where the logging call was issued (if available) +# %(filename)s Filename portion of pathname +# %(module)s Module (name portion of filename) +# %(lineno)d Source line number where the logging call was issued (if available) +# %(funcName)s Function name +# %(created)f Time when the LogRecord was created (time.time() return value) +# %(asctime)s Textual time when the LogRecord was created +# %(msecs)d Millisecond portion of the creation time +# %(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded +# (typically at application startup time) +# %(thread)d Thread ID (if available) +# %(threadName)s Thread name (if available) +# %(process)d Process ID (if available) +# %(message)s The result of record.getMessage(), computed just as the record is emitted +import traceback +def main_exception_handler(type, value, tb): + log.exception("Uncaught exception! Type: {0}, Value: {1}, TB: {2}".format(type, value, traceback.format_tb(tb))) + +# sys.excepthook = main_exception_handler # Install exception handler def _version(): import platform import dill import ruamel.yaml as yaml - print("## Python Version: '{}'".format(platform.python_version())) - print("## ruamel.yaml Version: '{}'".format(yaml.__version__)) - print("## dill Version: '{}'".format(dill.__version__)) + import semantic_version + log.info("Python version: {}".format(platform.python_version())) + log.info("ruamel.yaml version: {}".format(yaml.__version__)) + log.info("dill version: {}".format(dill.__version__)) + log.info("semantic_version version: {}".format(semantic_version.__version__)) +# log.info("Hilbert.Config version: {}".format(config.__version__)) # TODO! + # arghandler version? dill version? etc? def _load(f): - print("## YAML Validation: ") return load_yaml_file(f) # TODO: check that this is a dictionary! -@subcmd('version', help='Print version info') +@subcmd('version', help='Display version info') def cmd_version(parser, context, args): + log.debug("Running '{}'".format('cfg_version')) _version() + log.debug("Done") + exit(0) @subcmd('cfg_verify', help='Check correctness of a given general Hilbert configuration (YAML) file as far as possible...') def cmd_verify(parser, context, args): global PEDANTIC global INPUT_DIRNAME - global OUTPUT_DIRNAME - - ctx = vars(context) - - if 'pedantic' in ctx: - PEDANTIC = ctx['pedantic'] - - - args = vars(parser.parse_args(args)) -# vars(args) - - fn = 'Hilbert.yml' - if 'inputfile' not in ctx: - print("Warning: missing input file specification: using default '{}'!" . format(fn)) - else: - fn = ctx['inputfile'] - - assert fn is not None - - f = URI(None) - if f.validate(fn): - fn = f.get_data() - print("## Input file: '{}'".format(fn)) - else: - print("ERROR: wrong file specification: '{}'" . format(fn)) - exit(1) + log.debug("Running '{}'".format('cfg_verify')) - INPUT_DIRNAME = os.path.abspath(os.path.dirname(fn)) + ctx = vars(context) + pedantic_handler(parser, ctx, args) - print("## Loading '{}'..." . format(fn)) - try: - yml = _load(fn) - print("## Input file is a valid YAML!") - except: - print("ERROR: wrong input file: '{}'!" . format(fn)) - raise + if 'inputdump' in ctx: + df = ctx['inputdump'] + if df is not None: + log.error("Sorry: cannot verify a dump file.") + exit(1) - os.chdir(INPUT_DIRNAME) - print("## Deep Configuration Validation/Parsing: ") - cfg = parse_hilbert(yml) + args = parser.parse_args(args) + cfg = input_handler(parser, ctx, args) - if cfg is None: - print("ERROR: semantically wrong input!") - exit(1) - - print("## Input file '{}' contains good valid Hilbert configuration!" . format(fn)) - print("## Done") + log.debug("Done") exit(0) - -@subcmd('cfg_dump', help='Load input .YAML or .Pickle file and display/dump it') -def cmd_dump(parser, context, args): +def pedantic_handler(parser, ctx, args): global PEDANTIC - global INPUT_DIRNAME -# global OUTPUT_DIRNAME - -# parser.add_argument('-O', '--outputdir', required=False, default=argparse.SUPPRESS, -# help="specify output directory (default: alongside with the output dump file)") - - parser.add_argument('-od', '--outputdump', default=argparse.SUPPRESS, - help="specify output dump file") - - ctx = vars(context) if 'pedantic' in ctx: PEDANTIC = ctx['pedantic'] - args = vars(parser.parse_args(args)) - + if PEDANTIC: + log.debug("PEDANTIC mode is ON!") + +def input_handler(parser, ctx, args): + global INPUT_DIRNAME + fn = None df = None - - f = URI(None) if 'inputfile' in ctx: fn = ctx['inputfile'] -# assert fn is not None - + log.debug("Input YAML file specified: {}".format(fn)) + if 'inputdump' in ctx: df = ctx['inputdump'] -# assert df is not None + log.debug("Input dump file specified: {}".format(df)) if (fn is None) and (df is None): fn = 'Hilbert.yml' - print("Warning: missing input file specification: using default '{}'!" . format(fn)) -# print("ERROR: input file/dump specification is missing!") -# exit(1) - + log.warning("Missing input file specification: using default '{}'!".format(fn)) + if (fn is not None) and (df is not None): - print("ERROR: input file specification clashes with the input dump specification: specify a single input source!") - exit(1) - - if fn is not None: - if not f.validate(fn): - print("ERROR: wrong file specification: '{}'" . format(fn)) - exit(1) - print("## Input file: '{}'".format(fn)) - - if df is not None: - if not f.validate(df): - print("ERROR: wrong dump file specification: '{}'" . format(df)) + log.error("Input file specification clashes with the input dump specification: specify a single input source!") + exit(1) + + if fn is not None: + if not URI(None).validate(fn): + log.error("Wrong file specification: '{}'".format(fn)) + exit(1) + log.info("Input file: '{}'".format(fn)) + + if df is not None: + if not URI(None).validate(fn): + log.error("Wrong dump file specification: '{}'".format(df)) exit(1) - print("## Input dump file: '{}'".format(df)) - - + log.info("Input dump file: '{}'".format(df)) + if fn is not None: INPUT_DIRNAME = os.path.abspath(os.path.dirname(fn)) else: assert df is not None INPUT_DIRNAME = os.path.abspath(os.path.dirname(df)) - -# out = None -# if 'outputdir' in args: -# out = args['outputdir'] -# -# assert out is not None -# -# if not f.validate(out): -# print("ERROR: wrong output directory specification: '{}'" . format(out)) -# exit(1) -# -### out = f.get_data() -# print("## Output dir: '{}'".format(out)) -# -# OUTPUT_DIRNAME = os.path.abspath(out) -# else: -# OUTPUT_DIRNAME = INPUT_DIRNAME - - od = None - - f = URI(None) - - if 'outputdump' in args: - od = args['outputdump'] - assert od is not None -# elif fn is not None: -# od = os.path.splitext(os.path.basename(fn))[0] + '.pickle' -## OUTPUT_DIRNAME = INPUT_DIRNAME -# else: -# assert df is not None -# od = os.path.splitext(os.path.basename(df))[0] + '.pickle' -## OUTPUT_DIRNAME = INPUT_DIRNAME - - if not f.validate(od): - if not PEDANTIC: - print("## WARNING: Output dump file: '{}' already exists!".format(od)) - else: - print("## ERROR: Output dump file: '{}' already exists!".format(od)) - exit(1) - cfg = None + if fn is not None: - print("## Loading '{}'..." . format(fn)) + log.info("Loading '{}'...".format(fn)) try: yml = _load(fn) - print("## Input file is a valid YAML!") + log.info("Input file is a valid YAML!") os.chdir(INPUT_DIRNAME) - print("## Data Validation/Parsing: ") + log.info("Data Validation/Parsing: ") + cfg = parse_hilbert(yml) - + except: - print("ERROR: wrong input file: '{}'!" . format(fn)) - raise + log.exception("ERROR: wrong input file: '{}'!".format(fn)) + exit(1) else: - print("## Loading dump '{}'..." . format(df)) + log.info("Loading dump '{}'...".format(df)) try: cfg = pickle_load(df) - print("## Input dump file is valid!") + log.info("Input dump file is valid!") except: - print("ERROR: wrong input dump file: '{}'!" . format(df)) - raise - + log.exception("Wrong input dump file: '{}'!".format(df)) + exit(1) if cfg is None: - print("ERROR: semantically wrong input!") + log.error("Could not get the configuration!") exit(1) - print("## Input is OK: ") - print(cfg) + assert isinstance(cfg, Hilbert) + log.info("Configuration is OK!") + return cfg - if od is not None: - print("## Writing the configuration into '{}'..." . format(od)) - pickle_dump(od, cfg) -# print("## Pickled configuration is now in '{}'!" . format(od)) - print("## Done") - exit(0) +def output_handler(parser, ctx, args): + args = vars(args) -# return cfg + od = None + if 'outputdump' in args: + od = args['outputdump'] + log.debug("Specified output dump file: {}".format(od)) + assert od is not None + if URI(None).validate(od): + if not PEDANTIC: + log.warning("Output dump file: '{}' already exists! Will be overwritten!".format(od)) + else: + log.warning("Output dump file: '{}' already exists! Cannot overwrite it in PEDANTIC mode!".format(od)) + od = None + return od +def cmd_list(parser, context, args, obj): + ctx = vars(context) + pedantic_handler(parser, ctx, args) + cfg = input_handler(parser, ctx, args) + return cfg.query(obj) -@subcmd('cfg_show', help='Load Configuration file and display some of its contents') -def cmd_show(parser, context, args): - global PEDANTIC - global INPUT_DIRNAME -# global OUTPUT_DIRNAME +@subcmd('cfg_query', help='Load Configuration and query some part of it') +def cmd_query(parser, context, args): + log.debug("Running '{}'" . format('cfg_query')) parser.add_argument('-o', '--object', required=False, default='all', - help="specify the object in the config (default: all)") + help="specify the object in the config (default: 'all')") + parser.add_argument('-od', '--outputdump', default=argparse.SUPPRESS, + help="specify output dump file") - ctx = vars(context) + args = parser.parse_args(args) - if 'pedantic' in ctx: - PEDANTIC = ctx['pedantic'] + _args = vars(args) - args = vars(parser.parse_args(args)) - - fn = None - df = None - - f = URI(None) + obj = 'all' + if 'object' in _args: + obj = _args['object'] - if 'inputfile' in ctx: - fn = ctx['inputfile'] - - if 'inputdump' in ctx: - df = ctx['inputdump'] + try: + log.info("Querring object: '{}'... " . format(obj)) + obj = cmd_list(parser, context, args, obj) + except: + log.exception("Sorry cannot query '{}' yet!" . format(obj)) + exit(1) - if (fn is None) and (df is None): - fn = 'Hilbert.yml' - print("Warning: missing input file specification: using default '{}'!" . format(fn)) -# exit(1) - - if (fn is not None) and (df is not None): - print("ERROR: input file specification clashes with the input dump specification: specify a single input source!") - exit(1) - - if fn is not None: - if not f.validate(fn): - print("ERROR: wrong file specification: '{}'" . format(fn)) - exit(1) - print("## Input file: '{}'".format(fn)) - - if df is not None: - if not f.validate(df): - print("ERROR: wrong dump file specification: '{}'" . format(df)) - exit(1) - print("## Input dump file: '{}'".format(df)) - - - if fn is not None: - INPUT_DIRNAME = os.path.abspath(os.path.dirname(fn)) + assert obj is not None + + if isinstance(obj, Base): + print(yaml_dump(obj.data_dump())) else: - assert df is not None - INPUT_DIRNAME = os.path.abspath(os.path.dirname(df)) + print(yaml_dump(obj)) - cfg = None - if fn is not None: - print("## Loading '{}'..." . format(fn)) - try: - yml = _load(fn) - print("## Input file is a valid YAML!") + od = output_handler(parser, vars(context), args) - os.chdir(INPUT_DIRNAME) - print("## Data Validation/Parsing: ") + if od is not None: + log.info("Writing the configuration into '{}'...".format(od)) + pickle_dump(od, obj) - cfg = parse_hilbert(yml) - - except: - print("ERROR: wrong input file: '{}'!" . format(fn)) - raise + log.debug("Done") + exit(0) + +@subcmd('list_applications', help='Load Configuration and list its applications') +def cmd_list_applications(parser, context, args): + log.debug("Running '{}'" . format('list_applications')) + log.debug("Listing all Application ID...") + + args = parser.parse_args(args) + + obj = None + try: + obj = cmd_list(parser, context, args, 'Applications/keys') + except: + log.exception("Sorry could not get the list of '{}' from the input file!".format('applications')) + exit(1) + + assert obj is not None + + if isinstance(obj, Base): + print(yaml_dump(obj.data_dump())) else: - print("## Loading dump '{}'..." . format(df)) - try: - cfg = pickle_load(df) - print("## Input dump file is valid!") - except: - print("ERROR: wrong input dump file: '{}'!" . format(df)) - raise + print(yaml_dump(obj)) - if cfg is None: - print("ERROR: could not get the configuration!") + log.debug("Done") + exit(0) + +@subcmd('list_stations', help='Load Configuration and list its stations') +def cmd_list_stations(parser, context, args): + log.debug("Running '{}'" . format('list_stations')) + log.debug("Listing all Station ID...") + + args = parser.parse_args(args) + + obj = None + try: + obj = cmd_list(parser, context, args, 'Stations/keys') + except: + log.exception("Sorry could not get the list of '{}' from the input file!".format('stations')) exit(1) - assert isinstance(cfg, Hilbert) - print("## Configuration is OK!") - - obj = 'all' - if 'object' in args: - obj = args['object'] + assert obj is not None + + if isinstance(obj, Base): + print(yaml_dump(obj.data_dump())) + else: + print(yaml_dump(obj)) + + log.debug("Done") + exit(0) + + +@subcmd('list_profiles', help='Load Configuration and list its profiles') +def cmd_list_profiles(parser, context, args): + log.debug("Running '{}'" . format('list_profiles')) + log.debug("Listing all Profile ID...") + args = parser.parse_args(args) + + obj = None try: - print("## Showing: '{}' for the configuration" . format(obj)) - cfg.show(obj) # TODO pprint(QUERY!!!) + obj = cmd_list(parser, context, args, 'Profiles/keys') except: - print("## ERROR: Sorry cannot show '{}' yet!" . format(obj)) + log.exception("Sorry could not get the list of '{}' from the input file!".format('profiles')) exit(1) - print("## Done") + assert obj is not None + + if isinstance(obj, Base): + print(yaml_dump(obj.data_dump())) + else: + print(yaml_dump(obj)) + + log.debug("Done") exit(0) +@subcmd('list_groups', help='Load Configuration and list its named groups') +def cmd_list_groups(parser, context, args): + log.debug("Running '{}'" . format('list_groups')) + log.debug("Listing all Group ID...") + + args = parser.parse_args(args) + + obj = None + try: + obj = cmd_list(parser, context, args, 'Groups/keys') + except: + log.exception("Sorry could not get the list of '{}' from the input file!".format('groups')) + exit(1) + + assert obj is not None + + if isinstance(obj, Base): + print(yaml_dump(obj.data_dump())) + else: + print(yaml_dump(obj)) + + log.debug("Done") + exit(0) + + +@subcmd('list_services', help='Load Configuration and list its services') +def cmd_list_services(parser, context, args): + log.debug("Running '{}'" . format('list_services')) + log.debug("Listing all Service ID...") + + args = parser.parse_args(args) + + obj = None + try: + obj = cmd_list(parser, context, args, 'Services/keys') + except: + log.exception("Sorry could not get the list of '{}' from the input file!".format('services')) + exit(1) + + assert obj is not None + + if isinstance(obj, Base): + print(yaml_dump(obj.data_dump())) + else: + print(yaml_dump(obj)) + + log.debug("Done") + exit(0) + def main(): - handler = ArgumentHandler(use_subcommand_help=True, enable_autocompletion=True, description="Validate/Parse Hilbert Configuration") + handler = ArgumentHandler(use_subcommand_help=True, enable_autocompletion=True, description="Hilbert - server tool") # add_argument, set_logging_level, set_subcommands, - handler.add_argument('-q', '--quiet', help='decrease verbosity', action='store_true') - handler.add_argument('-v', '--verbose', help='increase verbosity', action='store_true') +# handler.add_argument('-q', '--quiet', help='decrease verbosity', action='store_true') +# handler.add_argument('-v', '--verbose', help='increase verbosity', action='store_true') # handler.set_logging_argument('-l', '--log_level', default_level=logging.INFO) @@ -361,18 +382,20 @@ def main(): handler.add_argument('-p', '--pedantic', required=False, action='store_true', help="turn on pedantic mode") + # 2 input sources: .YAML or .PICKLE handler.add_argument('-if', '--inputfile', required=False, - help="specify input file (default: 'Hilbert.yml')") - + help="specify input .YAML file (default: 'Hilbert.yml')") handler.add_argument('-id', '--inputdump', required=False, help="specify input dump file") - _argv = sys.argv - _argv = _argv[1:] + _argv = sys.argv[1:] + # NOTE: show help by if not arguments given if len(_argv) == 0: + log.debug("No command arguments given => Showing usage help!") _argv = ['-h'] handler.run(_argv) + main() From a385fa7f8a5e68893b9105d645124f8c7ab0dc90 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Mon, 21 Nov 2016 05:21:17 +0100 Subject: [PATCH 20/42] Addded stubs of required sub-commands (for the Dashboard) to server-side hilbert tool: - poweron/shutdown [] - deploy - start/finish [] - app_switch --- config/hilbert_cli_config.py | 100 +++++++++++++++++-- tools/hilbert.py | 188 +++++++++++++++++++++++++++++++++++ 2 files changed, 278 insertions(+), 10 deletions(-) diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index d1e3dfc..5099de2 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -292,7 +292,7 @@ def data_dump(self): if _d is None: return _d - assert not isinstance(_d, (tuple, set)) + assert not isinstance(_d, (tuple, set)) # TODO: is this true in general?!? if isinstance(_d, dict): _dd = {} @@ -316,15 +316,14 @@ def data_dump(self): return _d + def query(self, what): + """Generic query for data subset about this object""" + # NOTE: no data dumping here! Result may be a validator! - - - - - def query(self, what): log.debug("Querying '%s'", what) + if (what is None) or (what == ''): what = 'all' @@ -334,6 +333,7 @@ def query(self, what): _d = self.get_data() if what == 'keys': + assert isinstance(_d, dict) return _d.keys() s = BaseString.parse(what, parent=self) @@ -350,9 +350,9 @@ def query(self, what): if h in _d: d = _d[ss[0]] if isinstance(d, Base): - return d.query(t) + return d.query(t) # TODO: FIXME: avoid recursion... - log.warning("Could not query an object. Ignorring the tail: %s", t) + log.warning("Could not query an object. Ignoring the tail: %s", t) return d raise ConfigurationError(u"{}: {}".format("ERROR:", @@ -1133,6 +1133,14 @@ def __init__(self, parent): self._types = {self._default_type: DM_rule} # ! NOTE: AMT - maybe later... + + def run_action(self, action, action_args): + assert action == 'poweron' + + # process call: ssh to vm_host + docker-machione start vm_id + raise NotImplementedError("Running 'docker-machine start' action is not supported yet... Sorry!") + + class WOL(BaseRecord): """WOL :: StationPowerOnMethod""" @@ -1150,6 +1158,12 @@ def __init__(self, parent): self._types = {self._default_type: WOL_rule} + def run_action(self, action, action_args): + assert action == 'poweron' + + # process call: wakeonlan + mac + IP address (get from parent's ssh alias!?) + raise NotImplementedError("Running 'WOL' action is not supported yet... Sorry!") + ############################################################### class DockerComposeService(BaseRecord): @@ -1305,8 +1319,9 @@ class Station(BaseRecord): # Wrapper def __init__(self, parent): BaseRecord.__init__(self, parent) - self._default_type = "default_station" + self._poweron_tag = text_type('poweron_settings') + self._default_type = "default_station" default_rule = { self._extends_tag: (False, StationID), text_type('name'): (True, BaseUIString), @@ -1314,7 +1329,7 @@ def __init__(self, parent): text_type('icon'): (False, Icon), text_type('profile'): (True, ProfileID), text_type('address'): (True, HostAddress), - text_type('poweron_settings'): (False, StationPowerOnMethodWrapper), # !! variadic, PowerOnType... + self._poweron_tag: (False, StationPowerOnMethodWrapper), # !! variadic, PowerOnType... text_type('ssh_options'): (False, StationSSHOptions), # !!! record: user, port, key, key_ref text_type('omd_tag'): (True, StationOMDTag), # ! like ServiceType: e.g. agent. Q: Is this mandatory? text_type('hidden'): (False, StationVisibility), # Q: Is this mandatory? @@ -1323,6 +1338,71 @@ def __init__(self, parent): self._types = {self._default_type: default_rule} + def shutdown(self, action_args): + ### ssh address subprocess + raise NotImplementedError("Cannot shutdown this station!") + + def deploy(self, action_args): + ### see existing deploy.sh!? + raise NotImplementedError("Cannot deploy local configuration to this station!") + + def start_service(self, action_args): + raise NotImplementedError("Cannot start a service/application on this station!") + + def finish_service(self, action_args): + raise NotImplementedError("Cannot finish a service/application on this station!") + + def app_switch(self, action_args): + raise NotImplementedError("Cannot switch an application on this station!") + + def poweron(self, action_args): + _d = self.get_data() + assert _d is not None + + if not self._poweron_tag in _d: + log.error("Cannot Power-On this station since the corresponding method is missing!") + raise NotImplementedError("Cannot Power-On this station!") + + poweron = _d[self._poweron_tag] + if poweron is None: + log.error("Cannot Power-On this station since the corresponding method was not specified properly!") + raise NotImplementedError("Cannot Power-On this station!") + + poweron.run_action('poweron', action_args) # ???? + + def run_action(self, action, action_args): + """ + Run the given action on/with this station + + :param action_args: arguments to the action + :param action: + poweron [] + shutdown [] + deploy [] + start [] + finish [] + app_switch + + :return: nothing. + """ + + if action == 'poweron': + self.poweron(action_args) + elif action == 'shutdown': + self.shutdown(action_args) + elif action == 'deploy': + self.deploy(action_args) + elif action == 'start': + self.start_service(action_args) + elif action == 'finish': + self.finish_service(action_args) + elif action == 'app_switch': + self.app_switch(action_args) + + # Run 'ssh address hilbert-station action action_args'?! + raise NotImplementedError("Running action '{0} {1}' is not supported yet... Sorry!" . format(action, action_args)) + + def get_base(self): _d = self.get_data() assert _d is not None diff --git a/tools/hilbert.py b/tools/hilbert.py index d5d8606..09456c4 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -369,6 +369,194 @@ def cmd_list_services(parser, context, args): log.debug("Done") exit(0) + +def cmd_action(parser, context, args, stationId, action, action_args): + stations = None + try: + stations = cmd_list(parser, context, args, 'Stations/all') + except: + log.exception("Sorry could not get the list of '{}' from the input file!".format('stations')) + exit(1) + + assert stations is not None + assert stationId in stations.get_data() + + station = stations.get_data()[stationId] + + assert station is not None + + if isinstance(station, Base): + print(yaml_dump(station.data_dump())) + else: + print(yaml_dump(station)) + + log.debug("Trying to run '{0} {1}' on remote station '{2}'" . format(action, action_args, stationId)) + + try: + station.run_action(action, action_args) + except: + log.exception("Could not run '{0} {1}' on remote station '{2}'" . format(action, action_args, stationId)) + exit(1) + + +@subcmd('poweron', help='Load Configuration and poweron one of the stations') +def cmd_poweron(parser, context, args): + log.debug("Running '{}'" . format('cmd_poweron')) + + parser.add_argument('-s', '--station', required=True, help="specify the station") + parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments") + + args = parser.parse_args(args) + _args = vars(args) + assert 'station' in _args + stationId = _args['station'] + + action_args = None + if 'action_args' in _args: + action_args = _args['action_args'] + + cmd_action(parser, context, args, stationId, 'poweron', action_args) + + log.debug("Done") + exit(0) + + +@subcmd('shutdown', help='Load Configuration and shutdown one of the stations') +def cmd_shutdown(parser, context, args): + log.debug("Running '{}'" . format('cmd_shutdown')) + + parser.add_argument('-s', '--station', required=True, help="specify the station") + parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments") + + args = parser.parse_args(args) + _args = vars(args) + assert 'station' in _args + stationId = _args['station'] + + action_args = None + if 'action_args' in _args: + action_args = _args['action_args'] + + cmd_action(parser, context, args, stationId, 'shutdown', action_args) + + log.debug("Done") + exit(0) + +@subcmd('deploy', help='Load Configuration and deploy its part to one of the stations') +def cmd_deploy(parser, context, args): + log.debug("Running '{}'" . format('cmd_deploy')) + + parser.add_argument('-s', '--station', required=True, help="specify the station") + parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments") + + args = parser.parse_args(args) + _args = vars(args) + assert 'station' in _args + stationId = _args['station'] + + action_args = None + if 'action_args' in _args: + action_args = _args['action_args'] + + cmd_action(parser, context, args, stationId, 'deploy', action_args) + + log.debug("Done") + exit(0) + +@subcmd('start', help='Load Configuration and start a service/application on one of the stations') +def cmd_start(parser, context, args): + log.debug("Running '{}'" . format('cmd_deploy')) + + parser.add_argument('-s', '--station', required=True, help="specify the station") + parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments (ApplicationID/ServiceID)") + + args = parser.parse_args(args) + _args = vars(args) + assert 'station' in _args + stationId = _args['station'] + + action_args = None + if 'action_args' in _args: + action_args = _args['action_args'] + + cmd_action(parser, context, args, stationId, 'start', action_args) + + log.debug("Done") + exit(0) + + +@subcmd('finish', help='Load Configuration and finish a service/application on one of the stations') +def cmd_finish(parser, context, args): + log.debug("Running '{}'" . format('cmd_finish')) + + parser.add_argument('-s', '--station', required=True, help="specify the station") + parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments (ApplicationID/ServiceID)") + + args = parser.parse_args(args) + _args = vars(args) + assert 'station' in _args + stationId = _args['station'] + + action_args = None + if 'action_args' in _args: + action_args = _args['action_args'] + + cmd_action(parser, context, args, stationId, 'finish', action_args) + + log.debug("Done") + exit(0) + + +@subcmd('app_switch', help='Load Configuration and app_switch top application to the given one on one of the stations') +def cmd_app_switch(parser, context, args): + log.debug("Running '{}'" . format('cmd_app_switch')) + + parser.add_argument('-s', '--station', required=True, help="specify the station") + parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments (new ApplicationID)") + + args = parser.parse_args(args) + _args = vars(args) + assert 'station' in _args + stationId = _args['station'] + + action_args = None + if 'action_args' in _args: + action_args = _args['action_args'] + + cmd_action(parser, context, args, stationId, 'app_switch', action_args) + + log.debug("Done") + exit(0) + + + +@subcmd('station_action', help='Load Configuration and perform some action with one of stations') +def cmd_station_action(parser, context, args): + log.debug("Running '{}'" . format('station_action')) + + parser.add_argument('-s', '--station', required=True, help="specify the station") + parser.add_argument('-a', '--action', required=True, help="specify the action") + parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments") + + args = parser.parse_args(args) + _args = vars(args) + + assert 'station' in _args + assert 'action' in _args + + stationId = _args['station'] + action = _args['action'] + + action_args = None + if 'action_args' in _args: + action_args = _args['action_args'] + + cmd_action(parser, context, args, stationId, action, action_args) + + log.debug("Done") + exit(0) + + def main(): handler = ArgumentHandler(use_subcommand_help=True, enable_autocompletion=True, description="Hilbert - server tool") From 710e24a513d8352d8205789f8c83bbe88d4b19e0 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Mon, 21 Nov 2016 16:47:02 +0100 Subject: [PATCH 21/42] Repair `extends` mechnismus for stations --- config/hilbert_cli_config.py | 131 ++++++++++++++-------- config/tests/data/Hilbert.yml.data.pickle | Bin 11055 -> 11098 bytes 2 files changed, 87 insertions(+), 44 deletions(-) diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index 5099de2..94822ee 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -983,7 +983,6 @@ def __init__(self, parent): def validate(self, d): """check whether data is a valid string""" - ### TODO: Detect other YAML scalar types? if not isinstance(d, bool): print("ERROR: not a boolean value: '{}'" . format(d)) @@ -1320,6 +1319,9 @@ def __init__(self, parent): BaseRecord.__init__(self, parent) self._poweron_tag = text_type('poweron_settings') + self._ssh_options_tag = text_type('ssh_options') + self._address_tag = text_type('address') + self._ishidden_tag = text_type('hidden') self._default_type = "default_station" default_rule = { @@ -1328,16 +1330,42 @@ def __init__(self, parent): text_type('description'): (True, BaseUIString), text_type('icon'): (False, Icon), text_type('profile'): (True, ProfileID), - text_type('address'): (True, HostAddress), + self._address_tag: (True, HostAddress), self._poweron_tag: (False, StationPowerOnMethodWrapper), # !! variadic, PowerOnType... - text_type('ssh_options'): (False, StationSSHOptions), # !!! record: user, port, key, key_ref + self._ssh_options_tag: (False, StationSSHOptions), # !!! record: user, port, key, key_ref text_type('omd_tag'): (True, StationOMDTag), # ! like ServiceType: e.g. agent. Q: Is this mandatory? - text_type('hidden'): (False, StationVisibility), # Q: Is this mandatory? - self._client_settings_tag : (False, StationClientSettings) # IDMap : (BaseID, BaseString) + self._ishidden_tag: (False, StationVisibility), # Q: Is this mandatory? + self._client_settings_tag: (False, StationClientSettings) # IDMap : (BaseID, BaseString) } # text_type('type'): (False, StationType), # TODO: ASAP!!! self._types = {self._default_type: default_rule} + def is_hidden(self): + _d = self.get_data() + assert _d is not None + + _h = None + + if self._ishidden_tag in _d: + _h = _d[self._ishidden_tag] + else: + _h = StationVisibility.parse(None, parent=self) + + return _h + + def get_address(self): + _d = self.get_data() + assert _d is not None + + _h = None + + if self._address_tag in _d: + _h = _d[self._address_tag] + else: + _h = StationVisibility.parse(None, parent=self) + + return _h + def shutdown(self, action_args): ### ssh address subprocess raise NotImplementedError("Cannot shutdown this station!") @@ -1408,56 +1436,56 @@ def get_base(self): assert _d is not None _b = _d.get(self._extends_tag, None) # StationID (validated...) - if _b is not None: - if isinstance(_b, Base): - _b = _b.get_data() +# if _b is not None: +# if isinstance(_b, Base): +# _b = _b.get_data() return _b - def extend(delta, base): # delta == self! + def extend(delta, base): # delta == self! assert delta.get_base() is not None assert base.get_base() is None - # assert delta.get_base() == base # ? - return delta + # NOTE: at early stage there may be no parent data... + if delta.get_parent().get_data() is not None: + assert delta.get_base() in delta.get_parent().get_data() + assert delta.get_parent().get_data().get(delta.get_base(), None) == base - # - # TODO: the following needs an update due to changes in API - not a clean merge - apply delta! - # + _d = delta.get_data() + _b = base.get_data() - d = delta.get_data() + assert delta._extends_tag in _d + assert delta._extends_tag not in _b - new = {} + del _d[delta._extends_tag] + assert delta.get_base() is None - for k in base: - if k == delta._extends_tag: - continue + # NOTE: Extend/merge the client settings: + k = delta._client_settings_tag - if k in delta: - v = delta.get(k, None) + bb = _b.get(k, None) + if bb is not None: + dd = _d.get(k, None) + if dd is None: + dd = StationClientSettings.parse(None, parent=delta.get_parent()) - if v is None: - new[k] = base[k] - continue + assert isinstance(dd, StationClientSettings) + assert isinstance(bb, StationClientSettings) + dd.extend(bb) - if k == delta._client_settings_tag: - t = base.get(k, {}).copy() + _d[k] = dd - assert isinstance(t, dict) - assert isinstance(v, dict) + # NOTE: the following is an application of delta to base data + for k in _b: # NOTE: take from base only the missing parts + assert k != delta._extends_tag - t.update(v) - new[k] = t - else: - new[k] = v # overwrite the rest - else: - new[k] = base[k] + if k == delta._client_settings_tag: + continue - for k in delta: - if not ((k == delta._extends_tag) or (k in new)): - new[k] = delta[k] + v = _d.get(k, None) - return new + if v is None: # key from base is missing or None in delte? + _d[k] = _b[k] # TODO: is copy() required for complicated structures? ############################################################### @@ -1548,6 +1576,21 @@ def __init__(self, parent): self._default_type: (ClientVariable, BaseScalar) } # ! TODO: only strings for now! More scalar types?! BaseScalar? + def extend(delta, base): + assert isinstance(base, StationClientSettings) + + _b = base.get_data() + if _b is not None: + assert isinstance(_b, dict) + _b = _b.copy() + + # NOTE: merge and override settings from the base using the current delta: + _d = delta.get_data() + if _d is not None: + _b.update(_d) + + delta.set_data(_b) + ############################################################### class GlobalApplications(BaseIDMap): @@ -1584,8 +1627,7 @@ def validate(self, d): if not BaseIDMap.validate(self, d): return False - sts = self.get_data() - self.set_data(None) + sts = self.get_data() # NOTE: may be handy for postprocessing! _ret = True @@ -1616,8 +1658,9 @@ def validate(self, d): assert _b in _processed if _b in _processed: - _processed[k] = v.extend(_processed[_b]) - # assert _processed[k] extends nothing...??? + v.extend(_processed[_b]) + _processed[k] = v + assert v.get_base() is None _chg = True else: _rest[k] = v @@ -1628,8 +1671,8 @@ def validate(self, d): log.error('Cyclic dependencies between stations: {}' .format(_todo)) _ret = False - if _ret: - self.set_data(_processed) +# if _ret: +# self.set_data(_processed) return _ret diff --git a/config/tests/data/Hilbert.yml.data.pickle b/config/tests/data/Hilbert.yml.data.pickle index 1845c5b5ccaf3d45a217f9a575f80271fb41db18..f13d2ba248bda4c28074738a59df432ec8be9001 100644 GIT binary patch literal 11098 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 From 44bbadcdd4d9eac45a13ce9c642694a36f31e1ff Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Mon, 21 Nov 2016 20:16:12 +0100 Subject: [PATCH 22/42] Updated General System Design Diagram NOTE: see the legend to "General Hilbert Architecture" in the "Management back-end" google.document --- docs/GeneralDD.png | Bin 147671 -> 145314 bytes docs/GeneralDD.xml | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/GeneralDD.png b/docs/GeneralDD.png index 44ad1c77f031681d957d6f3065ebd324aed25dc9..7e5275ab6a329df212c78f74338f808cf3104b8c 100644 GIT binary patch literal 145314 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 Y*yJW7jhx(F3JCaM(3Ys`OP;s?1A?(@j{pDw diff --git a/docs/GeneralDD.xml b/docs/GeneralDD.xml index 0a78764..a531992 100644 --- a/docs/GeneralDD.xml +++ b/docs/GeneralDD.xml @@ -1 +1 @@ -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 \ No newline at end of file +7R1Zc+I4+tdQO/0AZVk+H3NOz1Z6OzuZqd55NGDAM4BZ43SSedjfvpJtCUmWfMoE0tBVaZBk2Za++9II3mxef06C3epLPA/XI9OYv47g7cg0TcP30H+45S1vAdB08pZlEs2LtkPDU/R3WDQaRetzNA/33MA0jtdptOMbZ/F2G85Sri1IkviFH7aI1/xdd8EyLDU8zYJ1ufVbNE9XRStw/EPH5zBaropbe+T9psHsr2USP2+L+23jbZj3bAIyTfGO+1Uwj1+Y+8G7EbxJ4jjNv21eb8I1XleyYuS69I085gher9LNGv0A6GvWfa+4GDS5GL1XEm5T9nbK+cgefw/Wz2RG0wk2OzTZdrrfZXMaDZqewuR7mKDWNbrx9RR/W6b0iZgH3r9Em3WA1hNev6yiNHzaBTPc9YKAkH+ZbANC/KQG+kUXGnct18F+TzqKCR8iPGnWPYs30azoXkTr9U28jpPs9vA++6D2dTAN19d0o8mQbKtJb5zMw0ToIbe7Z+YtusqrX+wXWpk0fBWBBCFeGG/CNHlDQ4reMQB2ASEF1o1tskcvBxi2nWLQigFfaBWNQYE3Szr9AQTQlwIK5BBh+rC0ZeEcoVXxM07SVbyMt8H67tDKbJW4/Mx+hq9R+h/m+x94yMTGv7boKWkX/nHoo/ue7XUaJOkVJg3MhuA2vBvFmHA7JyNmGEzwo+DGYkh+C0KtXPTrzzBN34rfwXMao6bDWz7E8a64ap8m8V8hA0vu3ZVzZ9AeQmOAAHXFcy7ibSq7WAI1ZMf38XMyKzbB9NyChAbJMixG+nbehneoEryScB2k0XeeMMrgpLj0MY7Q01CwNCEPlCa0+SnyJy2uYglOzUTAFCbK3640EdrR4I0ZtsMD9hUPbAoPXNxH+VzC+AILDkiTP8ABhejaNsQq84JV54NV5pljlXOaSAUsThrpj1We/45YZVywqhVWmQ48EloZApgC9zTRAepmMmX14MJkThUd3GNhgzYm44rU/DS5jOVpxSqyT4yGjHXdCG/uFWr/+uVWoQvjblFvrlWPGaQL1tFyi76vwwUeulsH0XY8xU+hBrvmmibgV62gRaySCXyZkqlBx3St0pKW1gHRjh3+igjSDiEhftEc2wmqeqSBWnAsKUbS/Wu+MqWVMCULQdp6oufYdLl9EFhVvFjsw7S0uG3lpDIMlxYcm0F2bSCL2u2CKZnDqFxXKq4RRDXKCy2za1B+3suu4cjWIEfHHbcSzn+fsfHuGr1tOi5wECN6hoZmTvaNDaJ1UdHh7F7RX+Pwl8xwQPL8PvtdsGXaSjSD0pQvwTZYhpswA5TbYL+axkEyJ9OgVxVmKhEVOnAntq1Ko+Rvz75g/mrsi49zmoQ7vao3rnsmAQYFihcjmFusM3FgkUkADayD+AdrHRTMf7fWHbjHsskyCeZR2JStHzConooQu517VOg+Jkk94NKp0lSLJzRD0FQpEyvjOYO9xn2C5MgQOxWUkoECt9m2b+EUzfX7L+jPT59/+/KALvnn0yflBPXyxQxtLBZXCgljmYlrOvZckMvMCTBsNA+wXc+33LLAQTkCBxPOhF7heFYVNDTGFtduvXfYU4C3Di36v+J5eBYrDgwJhz3aGruN1vhztJ6i9xvfPPwyJj4k46fHN6TEbc9hiW17wqwbgu93XHFHueJTsnSrNMX8PthFzNpOlQur2XxQmAwKAwK1GDBd1IBw2uYDI/s0NR9UAB5nJiAshbOauUO7eDSrGmYVEEoEzYOvfTzLlw1Llcly+pNpWFjsNNFNDeH7p7LIOY8SHEOAFuo1nF2Auwdw32SfjrYxihnV/vXGKGHLUMJtiBJEHjQm0HBAP9lSM5qUuSPHCVP0jPEWs8IpEkI+yfSpbjywHBBh4H/Vxszm7FG03YGyBAJk/FCHWYl6w6uUIB6lOSxsgGHtcIrFnCq3UT0hktvfXbu8nQtvFs5mcp51f59h5jZ+wLhJUJrBX3Uci9Ss7cq8PF5L5ES46duQg5qx3Q9Vi5ntEjAKUzS1fDuWMBEJIKuxfJcVU1v6nmrS0tZ2bnvCkxpe5QOJ46HlV7+AaDVuOV6w5fc2zhNPPYPxX9NVpkMUBrW90kp/tUTgPZlMmlDSo5jgaSzMMWzwfgOTsDaDEd2mU7UXDW+Dl/AmzuR7G8/+yuD213AZ7clmNgNLvKzRLFhfFc2baD7P2Maw8OqW4xKHA1eZbjsYuNqtV+ajgSskvLJqwevlFgZmRSCdxmkab3ixK96FW06P8WSCDBZjjJIO1UQ1ubnJrhPQp0pNUyt3FRjFCkkQ9BKSejv/eYkDWvbEZj+CaVyXC98ROJtfLYb4lcN7Swl0DyRGiXn0XWqWEL1/hS6l9nSRhkxvl9sfaFt2U5VVYr2OdnsBeQhpyybHymEoUeTuOZuUTCdvGFFfrbqrFP6S1qmOodfCjUxBKodldiTVNAWhuws3glJ3Ww93aoo1x4MvOe/rDIIPMaKz6ILHMNkjWSJ3Iz+lcYLzZRplc1yaPkpTJR16v+gA1VOWnujsoxM4M1M7SssTckJ+Bapv43+jtnaczkI/Ze1sNpKMzpJowT50Fhh+FZ3N9+lqhrT8/e11vuH/Q3NO9vtVox2tt5kimrld6tGeoCDlQIl3FlSpDf04ltrljSFHimW4Y7zPJHG8tADIkOmXLZJmovlzxnFu0BVo2cLkH/uC5YR7ZifyO3XYDKWkjy2ei4Upt3jOnaljOyNpsM/9/a3vONpkEaPB3sqjf3TsbQPleHBn1wk7tOhe82Z5swKWVKqjUoutpuRVKqYEOBeLeS1wcpZ44jtjlUyK8m3cZJbF2xaoAVe/26ykBVomHx9q2gJyNLXXW46Ijd4gaq4FhAe2qtVcU7TOaw5Vh4bMaCMoBwLVn1GoOxB2otMxTQ24g8nIYRVOfdseUUc+1suL78AwJU79DZqikOSSWMlITsHXfyF/FeSvisRVkcY+5I/Kji0cka5jDkXthqYtlj0wbXFkNrRhsOyCSx1FCTV50iBkECfeWcsYpoAmAAiiQeNsONufuD4EBnodz3Rtnw9hgIY7KXo8xzSGSUAFBm/dB06N/CFYTNuOf3f5xpFVq7nQoB+IBknCAc+OBol5tO5HIkGgJQlqOf79SZDMInkhQT8OCXI/gqkFAGviO7YNXKRoQFegHMD0JoaadJwzfWop8ZybgCQpVjCcAWgII89LHyMPdpjzJDQJ99HfRX46pgwFuKDR9vXIvh1JXA1t6VFO49Bn1NAHd2AhvTPqjYlnA1OgIv2IiDyOH/LXawkxAwQZ2JBIkvcg7GzzopGcq7VrjccW5SX5kBpVsUmR7wh2sdssdwm/OO5KMC+VsSMF2Ki5jC0YwseOIYlU9CR+KehqyEiEtrS66HmEyZxo4MSPGrhAiUXnwAUyQ11BBjKuV+CCJOKQC/f+96/oz+dgO19jUBX2q2MCQvslEsQXkkDMhTEPFNBNDW9Hieg+7MePG9KNZP7Sir9bskxvWKXwcxxgbZBZqBFYrbaL8/GAlXjiaspHXO12aySt50Jj52IRR4FYeEzqKq12NRjA0s36cQGWZkNdatFqLr5ZgYt8EIDEN0BJqeZEm9YJMWJJWosr/Vo7HnigZnyv4boL0bqXusyacQFbmWz8rzdCDJN59rEQwudG98cHuj0XfDgh3kCklgsqVAy3daNCixBVVozfZCVR8YVRUJE/xF4yz1Lqx5l4u1dY9ASs7ONBSHK5tYsDobLyqErvaO0tGBsTHxIxta9ILVjXxgSZ9ArVkqyV9y6TpM6urSBGnZVGtP8jUVMChddQu9YIQQOt8QdK+i8z1Yb8BtrS8y+OdViTbU9M9sNHEtNI3rbVizx74jAfUq2QlhqSd9dEDXTxctuXdP5TT+fv4K4RYlC8cjEk6Evonq9Gj+YJdGVPtJ7kSC4fUim0yAIdWEGmlEfZuRiu/jzKqvCpDkAghGdDIo2y7A8MZDSFTYyml0Sikm52IlF/HYGT5dtUJeSD+4yGfJtG5Rik7t4BjmE/sbtNbJ/Fh92RirxMcF8Rcud4OAawa/SxWRVCCKE9OdwCuEIAka7oPtGBXaPaOr2GA6dmPBDTMdqNJ+mbas28cryG2GYtNb8u9O986R9xl5wz/Rv71qQgSRkNdHnnn2nDCWCimzvWhB37cMIQPzHO2PScic9+jkL/Pj6FMiUU6qMkuPeKfb7Q5Q9NlyX2pA502YUk5+QE5FAXTFyGTtuCiHjOcigALSXLtuM/OJ0noKKs29/7+A3ttf5lJrR6mizB/zL2E5fNMQ5Tbgv5Y9vg0XrsFCYbpeDkQlB5RX/oaZAElZ+DdKo5RUq7Kj1dR4cz0CDpZ3QnzH7MgYrGQukSfgItnsEmbuTGe6ymLUehEoSAjURvUyUBq6Ut2oCuIUlqfKA1FUccl1QZP4lDeVx1tpIut1JuuJdMtI624ZgYtDNtY2KWp/l2h3UPJMm/7LO7VB0ZWeOXqvIS1JwnkGBU4d1NSqBpk6wm5kM7JAeNMf4Pdb4AMKwKsiAqSe8tWDTCUUKFORz1dEsNzWML7NIC69ZZOQIKhU/R+RgmEXp4DOenfg6b4AFWqbX64h46gxUcKKq0LFp4Qgb92AEC9mtS6caeUK537BZxE/pOJVCf11llu1osRNuVInThMX4Jk69buQjUrCbve0q/KoAuQymlLToy6qkc88aL3D0hl2T/EGiya8/+6gBSBDcHkGDunr6i3qfnXZhs4+9VIZic1KHn5ogGLxaqW/aUqTbhZhom6uiKRtIUCeh53qyvZmnMQn121t5jvI+K/P429SREzMny36/rQxiHktBMkSSSc2zYIB27LKE5OiQ0q0F0Rq2V6P3j5HtIf0UxCUlkfDmFvl62mgf7FV0q/kzIRoKA1ChNHX/HlzDNDsVv2hS1QTBM3Dqsi8e2JW6d365v+zhz+rBdxZlwbcjOnClHgnZcVY6EIqQGrmv4An/s6S+mYepQOq3eKHVyk5MzKVVRuy4mpUZ0QWYbAkQyaVwgzYOiNcCqOLhJZWomLIIyLNDRyzQWS3eNHa9ZUflOAFWu1PBRLNgUWU7ahE1pmzCt3hoHFeI6K4PefHnKuVAmgzdKfZJNc/tnsF3GuFxClL41DSY+l8JbVZW0DjKxBhnYtETvlaykFpSZKR0dQo5RNlL/vlvHwXzE1K5qYevlRNyqlaLA2jyY250YzMf0+IQRSbUhQLz32o+GJ1YiZtmudrvJKD+yKCxI9ukvmqSIyHCLRuzvzKLdvaIV2GZl034Nc+a577t06jO22q+eV7164JjLZ5S5+M/hNkzISVmLaPmc0ATGP66+PHw6n6UkWcpHgkSzhlN2Lk+apUOT70AWoleSvJJwEaKlnXEpOTLTaiVnHTRgj9oyJKJ+32C+eRRs4u2cU1uKIXq8Hte229jr0dqXTRCBKw9ACB1vydBeOqYxuPtqT7T+MFc1ngDTOeCGc/iOkF8WylqRoa9MxT+qaUSVoZ+bVVvW961O21cJlu+btO+bgvBqwSEUGxOoFZv2+mtbQvnRrL5SJ7Bo9WVHKnV1wUSohNralDgqTrdICYGGoFL7mmBaOqtWeIYkxvGd6bHcAm1IaHGyf9vOUB8u9Ytvcv/bI/6Fvz/dPJ50nkGVhfKEgzWwd0aFpw2CNYqLNYTmma7ULdNUmDmwHWgDXuTvdj5F68CLUnwwdOsiioUTdTpcYdZFLYsh+B2ugIXFQ3lFJm9VXMGHnAwUBQlg2VTCELuBCNbT0+d+obocadDOkFl0rhId6qmjXCRx7VE5V8mbhfJ6DMOTiw7n2Vi+gLZ9j7MhU9MwUIp5YoX2xk4cRyidNrYcQV6orYWj74TPsV0iW34NSSlfYWs+QKbC86S9tM4RJCaO7FQSoG9fH1qJRc2K/wxZ5NE88UqOesNXie5eRX2HzHiQ0klaiapFzgOEvMeSYFxfMmmbPh/zLNIWm+smokbnsNk2pLGLGGKWnQ+Hcn+C9Xwgo/mopcl8bFuikEjylFgruazSuRYrOWFmreWl9zZyVNh8u53zpwPhpTVjycjBA92hJyKwWLa+sdRjicEMNFxfd8y8LVYFhVBvaic9O/WEDrir9yAlYeaep0bx/C9qed7Nce2/czvyTs6yKRKX0cvUd+Qd0jSALaSr68pbNXnGPESEvumVXTsnz9YAtQlQvCaKVB1fM3XwNf/C10YtArNNT6bSe9oDs1XsRswSoFEX7TmXOBUNGtLNuYBRUq01sy6KMhrsat0CGNrxwwvr4onPSbMunnNpCHJHP5MYQ8JheBLsVl/iOU4Sufs/ \ No newline at end of file From 0134132185c91d46486dabbd6c99dfb97289d702 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Tue, 22 Nov 2016 14:02:14 +0100 Subject: [PATCH 23/42] Fixing hilbert CLI --- tools/hilbert | 1 + tools/hilbert.py | 163 ++++++++++++++++++++++++++++++++++------------- 2 files changed, 119 insertions(+), 45 deletions(-) create mode 120000 tools/hilbert diff --git a/tools/hilbert b/tools/hilbert new file mode 120000 index 0000000..8506212 --- /dev/null +++ b/tools/hilbert @@ -0,0 +1 @@ +hilbert.py \ No newline at end of file diff --git a/tools/hilbert.py b/tools/hilbert.py index 09456c4..90f53ac 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -19,7 +19,7 @@ #from config.hilbert_cli_config import * #from config.helpers import * -from arghandler import * # NOQA +from arghandler import * # NOQA import argparse # NOQA import logging @@ -44,6 +44,7 @@ # %(threadName)s Thread name (if available) # %(process)d Process ID (if available) # %(message)s The result of record.getMessage(), computed just as the record is emitted + import traceback def main_exception_handler(type, value, tb): log.exception("Uncaught exception! Type: {0}, Value: {1}, TB: {2}".format(type, value, traceback.format_tb(tb))) @@ -68,31 +69,36 @@ def _load(f): return load_yaml_file(f) # TODO: check that this is a dictionary! -@subcmd('version', help='Display version info') +# @subcmd('version', help='Display version info') # TODO: --version def cmd_version(parser, context, args): - log.debug("Running '{}'".format('cfg_version')) + log.debug("Running '{}'".format('--version')) _version() log.debug("Done") exit(0) -@subcmd('cfg_verify', help='Check correctness of a given general Hilbert configuration (YAML) file as far as possible...') +@subcmd('cfg_verify', help='Check correctness of a given general Hilbert configuration (YAML) file as far as possible') def cmd_verify(parser, context, args): global PEDANTIC global INPUT_DIRNAME log.debug("Running '{}'".format('cfg_verify')) + # 2 input sources: .YAML or .PICKLE + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + ctx = vars(context) pedantic_handler(parser, ctx, args) - if 'inputdump' in ctx: - df = ctx['inputdump'] - if df is not None: - log.error("Sorry: cannot verify a dump file.") - exit(1) - args = parser.parse_args(args) + + # if 'configdump' in ctx: + # df = ctx['configdump'] + # if df is not None: + # log.error("Sorry: cannot verify a dump file.") + # exit(1) + cfg = input_handler(parser, ctx, args) log.debug("Done") @@ -113,12 +119,14 @@ def input_handler(parser, ctx, args): fn = None df = None - if 'inputfile' in ctx: - fn = ctx['inputfile'] + args = vars(args) + + if 'configfile' in args: + fn = args['configfile'] log.debug("Input YAML file specified: {}".format(fn)) - if 'inputdump' in ctx: - df = ctx['inputdump'] + if 'configdump' in args: + df = args['configdump'] log.debug("Input dump file specified: {}".format(df)) if (fn is None) and (df is None): @@ -206,7 +214,7 @@ def cmd_list(parser, context, args, obj): return cfg.query(obj) -@subcmd('cfg_query', help='Load Configuration and query some part of it') +@subcmd('cfg_query', help='query some part of configuraton. possibly dump it to a file') def cmd_query(parser, context, args): log.debug("Running '{}'" . format('cfg_query')) @@ -215,6 +223,11 @@ def cmd_query(parser, context, args): parser.add_argument('-od', '--outputdump', default=argparse.SUPPRESS, help="specify output dump file") + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + parser.add_argument('-id', '--configdump', required=False, + help="specify input dump file") + args = parser.parse_args(args) _args = vars(args) @@ -246,13 +259,19 @@ def cmd_query(parser, context, args): log.debug("Done") exit(0) -@subcmd('list_applications', help='Load Configuration and list its applications') +@subcmd('list_applications', help='list application IDs') def cmd_list_applications(parser, context, args): log.debug("Running '{}'" . format('list_applications')) - log.debug("Listing all Application ID...") + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + parser.add_argument('-id', '--configdump', required=False, + help="specify input dump file") args = parser.parse_args(args) + log.debug("Listing all Application ID...") + + obj = None try: obj = cmd_list(parser, context, args, 'Applications/keys') @@ -270,13 +289,18 @@ def cmd_list_applications(parser, context, args): log.debug("Done") exit(0) -@subcmd('list_stations', help='Load Configuration and list its stations') +@subcmd('list_stations', help='list station IDs') def cmd_list_stations(parser, context, args): log.debug("Running '{}'" . format('list_stations')) - log.debug("Listing all Station ID...") + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + parser.add_argument('-id', '--configdump', required=False, + help="specify input dump file") args = parser.parse_args(args) + log.debug("Listing all Station ID...") + obj = None try: obj = cmd_list(parser, context, args, 'Stations/keys') @@ -295,13 +319,18 @@ def cmd_list_stations(parser, context, args): exit(0) -@subcmd('list_profiles', help='Load Configuration and list its profiles') +@subcmd('list_profiles', help='list profile IDs') def cmd_list_profiles(parser, context, args): log.debug("Running '{}'" . format('list_profiles')) - log.debug("Listing all Profile ID...") + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + parser.add_argument('-id', '--configdump', required=False, + help="specify input dump file") args = parser.parse_args(args) + log.debug("Listing all Profile ID...") + obj = None try: obj = cmd_list(parser, context, args, 'Profiles/keys') @@ -320,13 +349,18 @@ def cmd_list_profiles(parser, context, args): exit(0) -@subcmd('list_groups', help='Load Configuration and list its named groups') +@subcmd('list_groups', help='list (named) group IDs') def cmd_list_groups(parser, context, args): log.debug("Running '{}'" . format('list_groups')) - log.debug("Listing all Group ID...") + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + parser.add_argument('-id', '--configdump', required=False, + help="specify input dump file") args = parser.parse_args(args) + log.debug("Listing all Group ID...") + obj = None try: obj = cmd_list(parser, context, args, 'Groups/keys') @@ -345,13 +379,18 @@ def cmd_list_groups(parser, context, args): exit(0) -@subcmd('list_services', help='Load Configuration and list its services') +@subcmd('list_services', help='list service IDs') def cmd_list_services(parser, context, args): log.debug("Running '{}'" . format('list_services')) - log.debug("Listing all Service ID...") + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + parser.add_argument('-id', '--configdump', required=False, + help="specify input dump file") args = parser.parse_args(args) + log.debug("Listing all Service ID...") + obj = None try: obj = cmd_list(parser, context, args, 'Services/keys') @@ -369,7 +408,7 @@ def cmd_list_services(parser, context, args): log.debug("Done") exit(0) - +# NOTE: just a helper ATM def cmd_action(parser, context, args, stationId, action, action_args): stations = None try: @@ -385,24 +424,29 @@ def cmd_action(parser, context, args, stationId, action, action_args): assert station is not None - if isinstance(station, Base): - print(yaml_dump(station.data_dump())) - else: - print(yaml_dump(station)) +# if isinstance(station, Base): +# print(yaml_dump(station.data_dump())) +# else: +# print(yaml_dump(station)) log.debug("Trying to run '{0} {1}' on remote station '{2}'" . format(action, action_args, stationId)) try: - station.run_action(action, action_args) + station.run_action(action, action_args) # NOTE: temporary API for now except: log.exception("Could not run '{0} {1}' on remote station '{2}'" . format(action, action_args, stationId)) exit(1) -@subcmd('poweron', help='Load Configuration and poweron one of the stations') +@subcmd('poweron', help='poweron a station') def cmd_poweron(parser, context, args): log.debug("Running '{}'" . format('cmd_poweron')) + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + parser.add_argument('-id', '--configdump', required=False, + help="specify input dump file") + parser.add_argument('-s', '--station', required=True, help="specify the station") parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments") @@ -421,10 +465,15 @@ def cmd_poweron(parser, context, args): exit(0) -@subcmd('shutdown', help='Load Configuration and shutdown one of the stations') +@subcmd('shutdown', help='shutdown a station') def cmd_shutdown(parser, context, args): log.debug("Running '{}'" . format('cmd_shutdown')) + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + parser.add_argument('-id', '--configdump', required=False, + help="specify input dump file") + parser.add_argument('-s', '--station', required=True, help="specify the station") parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments") @@ -442,10 +491,15 @@ def cmd_shutdown(parser, context, args): log.debug("Done") exit(0) -@subcmd('deploy', help='Load Configuration and deploy its part to one of the stations') +@subcmd('deploy', help='deploy local configuration to a station') def cmd_deploy(parser, context, args): log.debug("Running '{}'" . format('cmd_deploy')) + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + parser.add_argument('-id', '--configdump', required=False, + help="specify input dump file") + parser.add_argument('-s', '--station', required=True, help="specify the station") parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments") @@ -463,10 +517,15 @@ def cmd_deploy(parser, context, args): log.debug("Done") exit(0) -@subcmd('start', help='Load Configuration and start a service/application on one of the stations') +@subcmd('start', help='start a service/application on a station') def cmd_start(parser, context, args): log.debug("Running '{}'" . format('cmd_deploy')) + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + parser.add_argument('-id', '--configdump', required=False, + help="specify input dump file") + parser.add_argument('-s', '--station', required=True, help="specify the station") parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments (ApplicationID/ServiceID)") @@ -485,10 +544,16 @@ def cmd_start(parser, context, args): exit(0) -@subcmd('finish', help='Load Configuration and finish a service/application on one of the stations') +@subcmd('finish', help='finish a service/application on a station') def cmd_finish(parser, context, args): log.debug("Running '{}'" . format('cmd_finish')) + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + parser.add_argument('-id', '--configdump', required=False, + help="specify input dump file") + + parser.add_argument('-s', '--station', required=True, help="specify the station") parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments (ApplicationID/ServiceID)") @@ -507,10 +572,15 @@ def cmd_finish(parser, context, args): exit(0) -@subcmd('app_switch', help='Load Configuration and app_switch top application to the given one on one of the stations') +@subcmd('app_switch', help='app_switch switch top application on a station') def cmd_app_switch(parser, context, args): log.debug("Running '{}'" . format('cmd_app_switch')) + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + parser.add_argument('-id', '--configdump', required=False, + help="specify input dump file") + parser.add_argument('-s', '--station', required=True, help="specify the station") parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments (new ApplicationID)") @@ -530,10 +600,15 @@ def cmd_app_switch(parser, context, args): -@subcmd('station_action', help='Load Configuration and perform some action with one of stations') +# @subcmd('station_action', help='perform some action with one of stations') def cmd_station_action(parser, context, args): log.debug("Running '{}'" . format('station_action')) + parser.add_argument('-if', '--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") + parser.add_argument('-id', '--configdump', required=False, + help="specify input dump file") + parser.add_argument('-s', '--station', required=True, help="specify the station") parser.add_argument('-a', '--action', required=True, help="specify the action") parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments") @@ -558,7 +633,10 @@ def cmd_station_action(parser, context, args): def main(): - handler = ArgumentHandler(use_subcommand_help=True, enable_autocompletion=True, description="Hilbert - server tool") +# handler = argparse.ArgumentParser() +# handler.parse_args() + + handler = ArgumentHandler(use_subcommand_help=True, enable_autocompletion=True, description="Hilbert - server tool: loads configuration and does something using it") # add_argument, set_logging_level, set_subcommands, # handler.add_argument('-q', '--quiet', help='decrease verbosity', action='store_true') @@ -570,12 +648,6 @@ def main(): handler.add_argument('-p', '--pedantic', required=False, action='store_true', help="turn on pedantic mode") - # 2 input sources: .YAML or .PICKLE - handler.add_argument('-if', '--inputfile', required=False, - help="specify input .YAML file (default: 'Hilbert.yml')") - handler.add_argument('-id', '--inputdump', required=False, - help="specify input dump file") - _argv = sys.argv[1:] # NOTE: show help by if not arguments given @@ -583,6 +655,7 @@ def main(): log.debug("No command arguments given => Showing usage help!") _argv = ['-h'] +# args = handler.parse_args() handler.run(_argv) From 1a84b6f8c2589592e7a47a7196dbf595ecc07219 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Tue, 22 Nov 2016 14:03:06 +0100 Subject: [PATCH 24/42] Notes about missing things --- config/hilbert_cli_config.py | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index 94822ee..77eee23 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -377,6 +377,7 @@ def detect_type(self, d): assert not (self._default_type is None) assert len(self._types) > 0 + assert isinstance(d, dict) return self._default_type @@ -396,10 +397,8 @@ def validate(self, d): _ret = True - _lc = d.lc # starting location of the mapping...? - (s, c) = (_lc.line, _lc.col) - _d = {} + _lc = d.lc # starting location of the mapping...? for k in _rule.keys(): r = _rule[k] @@ -429,6 +428,7 @@ def validate(self, d): assert _k is not None _d[_k] = _v + (s, c) = _get_line_col(_lc) for offset, k in enumerate(d): v = d.get(k) k = text_type(k) @@ -1035,6 +1035,7 @@ def validate(self, d): """determine the type of variadic data for the format version""" _ret = True + assert isinstance(d, dict) assert self._default_type is not None assert self._default_type in self._types @@ -1259,6 +1260,7 @@ def __init__(self, parent): self._types[self._default_type] = _compose_rule + # TODO: FIXME: add application to compatibleStations! ############################################################### class Profile(BaseRecord): @@ -1279,6 +1281,8 @@ def __init__(self, parent): self._types = {self._default_type: default_rule} + self._station_list = None # TODO: FIXME! + ############################################################### class StationSSHOptions(BaseRecord): # optional: "Station::ssh_options" # record: user, port, key, key_ref @@ -1340,6 +1344,8 @@ def __init__(self, parent): self._types = {self._default_type: default_rule} + self._compatible_applications = None # TODO: FIXME! + def is_hidden(self): _d = self.get_data() assert _d is not None @@ -1506,6 +1512,8 @@ def detect_type(self, d): return self._default_type def validate(self, d): + assert isinstance(d, dict) + self._type = self.detect_type(d) assert self._type is not None @@ -1514,7 +1522,7 @@ def validate(self, d): (_id_rule, _rule) = self._types[self._type] _lc = d.lc # starting position? - (s, c) = (_lc.line, _lc.col) + (s, c) = _get_line_col(_lc) _d = {} @@ -1576,6 +1584,8 @@ def __init__(self, parent): self._default_type: (ClientVariable, BaseScalar) } # ! TODO: only strings for now! More scalar types?! BaseScalar? + # TODO: FIXME: check for default hilbert applicationId! + def extend(delta, base): assert isinstance(base, StationClientSettings) @@ -1771,6 +1781,8 @@ def __init__(self, parent): self._exclude_tag = text_type('exclude') self._intersectWith_tag = text_type('intersectWith') + self._station_list = None # TODO: FIXME! + default_rule = { self._include_tag: (False, GroupIDList), self._exclude_tag: (False, GroupIDList), @@ -1796,9 +1808,9 @@ def validate(self, d): return _ret - ############################################################### +############################################################### class GlobalGroups(BaseIDMap): def __init__(self, parent): BaseIDMap.__init__(self, parent) From c5409aaf080b331ff6126ebb1c4c155e37496a7d Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Tue, 22 Nov 2016 14:04:00 +0100 Subject: [PATCH 25/42] Minor data cleanup --- config/tests/data/Hilbert.yml | 44 +++++++--------------- config/tests/data/Hilbert.yml.data.pickle | Bin 11098 -> 10782 bytes config/tests/data/docker-compose.yml | 1 + 3 files changed, 15 insertions(+), 30 deletions(-) diff --git a/config/tests/data/Hilbert.yml b/config/tests/data/Hilbert.yml index 9d6d4a5..1e113d7 100644 --- a/config/tests/data/Hilbert.yml +++ b/config/tests/data/Hilbert.yml @@ -1,32 +1,12 @@ ---- -########## -# AA: 1 # unknown!!! -########## -Version: 0.5.9 # 0.MAJOR.MINOR, later: MAJOR.MINOR -########## -# BB: 'a' # unknown!!! +Version: 0.6.0 # 0.MAJOR.MINOR, later: MAJOR.MINOR -Services: -# omd: - omd_agent: { type: compose, file: docker-compose.yml, ref: omd_agent, auto_detections: 'export HB_URL=${HILBERT_HEARTBEAT_URL}' } +Services: # file: docker-compose.yml, + omd_agent: { type: compose, ref: omd_agent, auto_detections: 'export HB_URL=${HILBERT_HEARTBEAT_URL}' } + omd: { type: compose, ref: omd_anew, auto_detections: 'export OMD=${HILBERT_OMD_PATH}' } # ptmx, registry, mng qr_handler - omd: { type: compose, file: dc.yml, ref: omd, auto_detections: 'export OMD=${HILBERT_OMD_PATH}' } - -Applications: - hb_test: - type: compose -# file: docker-compose.yml # default - may be omitted - ref: hb_test - auto_detections: 'export HB_URL=${HILBERT_HEARTBEAT_URL}' - description: Random HB testing - compatibleStations: - ? server - include: [vb_hb_tes_a] - intersectWith: [simple] - name: HB Testing Profiles: - standalone: + standalone: services: [] description: Generic Networking, without SSH & Docker & OMD agent. name: standalone @@ -58,7 +38,7 @@ Stations: omd_tag: standalone address: Problematic.SSH.Alias hidden: true # hide on Dashboard - client_settings: + client_settings: hilbert_autostart: true # Station starts Hilbert upon booting hilbert_autostart_delay: 20 # … with this delay in [sec] HILBERT_PREFERRED_LANGUAGE: de @@ -107,7 +87,11 @@ Stations: Groups: mygroup: { simple, exclude: [qr] } -Presets: # just an idea - default: {} # no changes - testb: { vb_hb_test_a: { hilbert_station_default_application: hb_test_b, HILBERT_HEARTBEAT_URL: 'http://127.0.0.1:7777'} } - +Applications: + hb_test: + type: compose + ref: hb_test # file: docker-compose.yml # default - may be omitted + auto_detections: 'export HB_URL=${HILBERT_HEARTBEAT_URL}' + name: HB-Test + description: Random HB testing + compatibleStations: { mygroup } diff --git a/config/tests/data/Hilbert.yml.data.pickle b/config/tests/data/Hilbert.yml.data.pickle index f13d2ba248bda4c28074738a59df432ec8be9001..d1b37e8505f128ddd87e09b16e9ba5aafad68d3b 100644 GIT binary patch literal 10782 zcma)C2Y4LC6}ABv4jXJR-M|?OBZDPdHa51XXG>VZvSjOY<{%-*Nw?PA`E;jwd*>3e z1X3f7vG&mPmBnxCm0nsi)ytY?o)pEzgEoSd^aTP;>H z&?1?pdQhE{ImYAF@=Enj_m&`J@kuheM*6hhD?H)&5 ztkRwmIW*}^WJ{I&Silvt%WC%2^nAQ`yOgVwu03s*Mfxl;dwR{D;cL{9{rNGh@yy7V z1sV;QV)m?>J-h0r=BdT(ax*WrG?Q&uZl;nQx96B8sYRLn{wkDmt~n*OBr_&Xw&G;U zle8i1dfs$uaVE4iAzIwR!e} z7L2Si3jwhUJ=@-HR+za4@LHWd9eN61>BB4IhM>AA3LF8N`g>yb;#vA*c1_K8xMsPz z$i(p<@^rSRm*8!|^x;BXyVk6MTpdETDF@bM{UizPO3jyk$h=9X1COAw~9JhKHx~Xl!32Q(Bs<6BB2zh zWEZ)IN;{p3Dd(;ez`&81y}V|xP`R_Y9K6o8S4K+ES9U82pCe|ks@bd4$3gNuf`m;( zzO)}*F}t;9x2e7mQGk&dNqZs(1(I%4=47y{nC-3EYxI4k?1W>tPZ?;SPgUo-Ccvj_ z`)8Xnnd}=<4ZAUWZO!h`C6_01iqwI~B?rO`?d%!JLhCzgc2Gw-2P;k~=h~rZb8*e? zQdc(lT+S)k-Lr|XC-3G*^TmASP|Ob3Y!ZICC=+O1#TYSH0*@O&4Gl~0Oqt74XCN9+ zOd>*!7M&*lwR;AQx@F$=MbL?^GrIxm4e+81;l>R*(%!V`C)}@ZhU*RKm=FF^E?X>@ z9Q&9^yFJ$Q!WnM#?BnR9>*x@f^m&In1XD-tMXo)47T(_1Kd`lTcqFrHxc8dg;o;t%%s^srdn&QL*E;EAR6M&k zeQE<|UvFY~WNU9?B$FB*u;bciDwWCZwQIZ9U)s42e_h?1@z0v{nT_N6dwMfFhf>Mj z%(m2Ua%kA*cg)o=6(-MYwE}0!B8}#pV)l?N>{ymwiWv^;xBI5jr!`EyEtMP@+Sz|Y zVx)g)Flmd5w$lDJ*`k}Z6FNt@&cr}6k=d3Q?y)7j{gkFjb|o{(-r+sH!?v702R)OB z8Wl&nIwz~6$a9@;6^>sj@6UE`+R$YutJTpN-?A!@52bhzcjH(LGk}#Qr*T^WQ_=1) zj8x540Lp&P9`J$ErW!{0gP|ud-&iMHvNKW4XI*>HtV~1DIrb1_VP*{6>G4yC#mAe| zUFaVySK`??(o-=MF5VHpw(3^mt)hpK@d;e!@fccPz4bJ%-{RRPYFxk7Aco)8ZZ=LC zMCK=%%^GH&Y%ZHNh>=e*S56tky{DSQv_Vv>nVxBbxb!sRhodReKWz|Lrp>^VL8y4T z@x#M2%5|V?mwcXQpHEHS zLYI62oFi-CEH7+wmKU`f$LuxZ#u$RO(Q$@*xA!MUhOf``Bt{aMU5SxC`{MK}=&SAK zzM-AH-r7!oKe#qPafdkLdAA~mI+)Ja+LxHZjyY!Elqs5tripzhX0{CtUemwbpZKL3 zFpe~_zt*+(WromZMh-!bNbFDW^7QgqBtukRYhPi?MxouBU|*@;oK%IzgAm^xPli5W zU)2QiSEuLUP1$koZ(h@c@7F56U+3A^`&w`FHxJ=FofCV@ojJ$8!K^ebsD9(rjK94} zN7dgR_vNy0CR({Q-9MT!qnV21Rx(-p76t6>o_(tV_H6|0+e5&1His30PMR1 zz`iE{?0W;izApgm`vbs!AOP$K1HgXhXaW1-X25>L2W);~vgp{4MgsO@3fPZ(_7hay z?F8&6L%@Ej39z4T0xTdF3n8`=$_WE%5TC*wTVsN>pHZiu(cx!_sv}|JbBf#%XdAn! z_@2B}s)#UkkRQCmi3)on>KfD+0xmyZj1d& z01ZMsO!)Pk+*hMAVNZE%pCdb&B}>SbcOt;v<=L+(8or)hjCqsgWWO7^D@uT4 zL>XfCzMB1>LIrXfB+qbLWWTRL_Xoh@a&tF!I!OC>12dOn4@7Ag9Wnc0gere(?!JjP8DB+RR|ZoO zJ>uEFs%8Gh2=(_cLj5C%Q2z`f)W3oV_3t1;{U?Y}{|zG4|NICgbLPU;HLJ>8RyDE8 zF|2BCm19vo%4j9Wfww7O$vjY6wlXrGG#+s1G_rs#sz?{!B@5Z+HAQfKkmDn!h>;fM z+HwMV%!8|MlSQa_vKS?`B`0!3fKE9{`xhzN9Bl5b$*CkWD>k^OoCe~wxvwUtqe5>hPylr}zotGXXMpI*nJ87_v&eJ5Cub|+ z0rQ|yH!(B5@d(flKPYgibcF)NfH%l;4ymu~9JF+Q+tt;*etq|b4c(Vq(!FtG_ohv9 zF1u(7#v?h8tx!jCHdmjIlLiVlqjElobP8FCiYIL-=^Br~HMn;sfV(;g;m%yi z?Np;*z#*-9iDL0uEWCq~ z)qKf`kn18;Jh>Pp<>K9ktU)8{`XjhsaHWHTH$_FUVE&kNf~6*FQPQM3Anre4f^{Ib zH)Lz+0-?Ym5NJIfo@^isg}DS3jWuDI4Wy8b%D0Jpx-{ZgIddfZbzE zHiN4sTTrTvd7mKNXmO7%myyiN7VOz4%TjT0TIa>1TuzRtg$Hvp7y0vF0nVCS$%*Rj zd=*;U+soA?x9krk5%z9HMLmH_^gTgqD+)9gZnna0N0IyBZJ-Sj*gdGUsG=970#^#X zUW11x+sR~B6sTpYw+~M}d4=i?7Si97(b@aaKg)V?n zCo2;NWdKdx5ixY>wpMn6d3tQC<9w55V8=q)oOdl*ak5Yr9<(7e5rb{elR?cM{=rG z;=70AxJ4+H9FgnDUB^S3ErxejH?49#+VoT<={Z4e04em0$Dr=XV^OMS+{iB93m!*W zL4mL4u1SWSbv)n1mSR_RT9YgZbvTZ)RfpdgT1SRop^mp4_*(GhaH0Tjdr|jfoJ_zQ zWhdSYIS3JjO9X84954f$0-7zb*+&v1F_0uhHW=B$Q=v?R-4ms8DWP#Bh?UV7LTnOs zPb|ttVTBw-grXw?B`*4!P*MRQ3MExC@lTbAIwRgcsA$xsKz0k#@Ya1d<* zgZD{RodHc(7)zzis+(QE<5(@EkzqLqxvmU2Zn+cQ8r zlJTF3zR>v3Lfw;RqihuFIpmnl_|FAHlkuMiLX`2JPsVd0TT^&&Q~aa)^ePpzg^_Q7Rf<#x5TXFDI=D4X|e%2Fgw}ypbHUq2WznfEuFG#+x}d zNE>fK-ILo6J2<><+jp|nV#aszz5Y(E_0yod8+~ReQsH}0@#MWIu_k}F_C7Sy zXG5?s4+bBr8b7wl`@s~I3LCyFGL?Ve(b>Y!H}XO7*5pGd85sEjq)&ZdFY;kD)i;9s z5BUfPQ3Ck7+U6(O25DmQQH;QfKZb`VA4jQ({sb!NlN(l>8^fm^-Pg${mGx6(RhF4A z7s0iGE1yPZ4n%v3B2s(b8 zmb;ELLz4}LoxL&nnhyVZIGlT5xf`u1O@uZ1M%bg<=5L~<+vabfqG5rSFy~DH5Uk;r zf(ILZ0+Mf|U7+sZ@I(+Sd=DO;+>25z{2f;G0yqS8PA{MILlkymp}E7$75T1?zYk?o zH2xk4M{A#$d>`Cy`l3c)HNUmNo$7D?fxh{Nt#AGj2nE8|t(u3zjU{=pW;$?iG9|M0 zWJ=9KM>LY^=*MUmXe|&;xx7z__mfBvaI60lJdcR+2gpevL$?p&;mJ?Q&d~Z0Dtf;Y zs#ZUm%frg`Gjgd4or7b=YR-|LgA$23^_Kn~|D^K^aMk3OD0OhY2Nv#SVqRhsa z2N5EEEL5m=1QK)}nkdRY*%!vDf3d+^i7*=fo5Sh0_(D(}b+KIb2EP-L|FB~j(DPqZ zJoz6=Kijm8xxr6L!ryFkj^Yz(Ec}6q%)tf~eRf^YQC701%6{9U&2fa$vhv9gDaBM zLjD9qCp;eHX)J`hW`(CKF_6sZkmm$cJXwUYo;4Svq2C4To}j-73VuZ*C!#wlcm%+Y z$w^>PC#%U4RG9)f1`$smfZS3vn;>^`I0O=%g1RTmP^w>^$}ZmvPa{o17&_1C>}>R= zGe~IkoijnG`%WR+Tc`uyTMA8{aTe%JcQI#!5dPf2_vGaqN=Js^=b-M%xf}!+L2%_lFzCTE%CJleMI2@|!B$0ZL8Qv9mF;c9B58o-X(~cs&W4`wMCUz%U+&_;r2eTIoto78v6y)IGTxrK%voF5ehiNoz93Hg+}|qlbh>WAu{HXpCz> zI7(w|2P>}IP^u*ToXR)GwX7bcF}R*bHO3CUq#pbS&}z}pPLk@@7-Xx_8bctoT4U9W tH6ATD?ZR;XAXA;Wt8_KN?nakc0BU%Ztkhvr7n3(|a-}9oJ+nI6`G0bIu6+Oi literal 11098 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 Date: Thu, 24 Nov 2016 05:39:35 +0100 Subject: [PATCH 26/42] Fixed hilbert's CLI according to review comments: *: sorted list of subcommends *: action arguments are positional now (no extra switches) +: '-vvv|-qqq' to increase/decrease verbosity (logging.level) +: '-V/--version' shows versions (for supporting libs and of hilbert/Python) +: '-H/--helpall' to output usage for all subcommends. *: use mutually_exclusive_group for --configfile|--configdump and -q|-v sets of arguments Note: separate SubCommandHandler in /config/subcmdparser.py (based on ArgumentHandler) Note: arguments are read left to right but actions handlers (e.g. for '-p', '-V`, '-h', '-H' ) will be immediately called by the standard parser. Therefore it may be worth adding '-vvv/-qqq' as left-most argument (then they will be taken into account!). --- config/__init__.py | 2 +- config/helpers.py | 2 +- config/hilbert_cli_config.py | 30 ++- config/subcmdparser.py | 320 +++++++++++++++++++++++++ config/tests/test_validate.py | 17 +- tools/hilbert.py | 430 +++++++++++++++++++--------------- 6 files changed, 601 insertions(+), 200 deletions(-) create mode 100644 config/subcmdparser.py diff --git a/config/__init__.py b/config/__init__.py index ca7e7d6..f1d5b34 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import from __future__ import unicode_literals -__version__ = '0.2.1-dev' +__version__ = '0.2.2-dev' # TODO: add git commit id? # from hilbert_cli_config import * diff --git a/config/helpers.py b/config/helpers.py index 02825e3..45a3eb4 100644 --- a/config/helpers.py +++ b/config/helpers.py @@ -4,7 +4,7 @@ from __future__ import absolute_import, print_function, unicode_literals -# from .hilbert_cli_config import load_yaml # Hilbert # VerboseRoundTripLoader, +# from .hilbert_cli_config import * # load_yaml # Hilbert # VerboseRoundTripLoader, ############################################################### # import pickle diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index 77eee23..e7a6696 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -161,7 +161,7 @@ def __init__(self, stream, version=None, preserve_quotes=None): ############################################################### -from ruamel.yaml.compat import PY2, PY3, text_type, string_types +from ruamel.yaml.compat import PY2, PY3, text_type, string_types, ordereddict from abc import * import sys @@ -890,7 +890,7 @@ def __init__(self, parent): def validate(self, d): """check whether data is a valid docker-compose file name""" - # TODO: call docker-compose on the referenced file! in DockerService! + # TODO: call docker-compose on the referenced file! Currently in DockerService!? return URI.validate(self, d) @@ -909,6 +909,7 @@ def validate(self, d): ############################################################### import subprocess # , shlex +# import paramiko class HostAddress(BaseString): """SSH alias""" @@ -932,14 +933,20 @@ def validate(self, d): def check_ssh_alias(cls, _h): """Check for ssh alias""" + log.debug("Checking ssh alias: '{0}'...".format(text_type(_h))) try: - _cmd = ["ssh", "-o", "ConnectTimeout=2", _h, "exit 0"] - subprocess.check_call(_cmd, stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) +# client = paramiko.SSHClient() +# client.load_system_host_keys() + + _cmd = ["ssh", "-o", "ConnectTimeout=1", _h, "exit 0"] + subprocess.check_call(_cmd, stdout=open("/dev/null", 'w')) # , stderr=open("/dev/null", 'w') + log.debug("Ssh alias '{0}' is functional!" . format(text_type(_h))) + return True except subprocess.CalledProcessError as err: - print("WARNING: non-functional ssh alias: '{0}' => exit code: {1}!" . format(text_type(_h), err.returncode)) + log.warning("Non-functional ssh alias: '{0}' => exit code: {1}!" . format(text_type(_h), err.returncode)) except: # Any other exception is wrong... - print("WARNING: non-functional ssh alias: '{0}'. Moreover: Unexpected error: {1}" . format(text_type(_h), sys.exc_info())) + log.warning("Non-functional ssh alias: '{0}'. Moreover: Unexpected error: {1}" . format(text_type(_h), sys.exc_info())) return False @@ -1202,13 +1209,18 @@ def validate(self, d): while isinstance(_f, Base): _f = _f.get_data() - assert os.path.exists(_f) # TODO: FIXME: use URI::check() instead?? - _n = _d[self._name_tag] - while isinstance(_n, Base): _n = _n.get_data() + if not os.path.exists(_f): # TODO: FIXME: use URI::check() instead?? + if PEDANTIC: + log.error("Missing file with docker-compose configuration: '%s'", _f) + return False + log.warning("Missing file with docker-compose configuration: '{0}'. Cannot check the service reference id: '{1}'" .format(_f, _n)) + return True + + # TODO: Check the corresponding file for such a service -> Service in DockerService! DC = "docker-compose" diff --git a/config/subcmdparser.py b/config/subcmdparser.py new file mode 100644 index 0000000..822523a --- /dev/null +++ b/config/subcmdparser.py @@ -0,0 +1,320 @@ +# import arghandler # NOQA + +import argparse # NOQA +import inspect # NOQA +import logging # NOQA +from operator import attrgetter + +################################# +# decorator +################################# +registered_subcommands = {} +registered_subcommands_help = {} + +def subcmd(arg=None, **kwargs): + """ + This decorator is used to register functions as subcommands with instances + of SubCommandHandler. + """ + if inspect.isfunction(arg): + return subcmd_fxn(arg, arg.__name__, kwargs) + else: + def inner_subcmd(fxn): + return subcmd_fxn(fxn, arg, kwargs) + + return inner_subcmd + + +def subcmd_fxn(cmd_fxn, name, kwargs): + global registered_subcommands, registered_subcommands_help + + # get the name of the command + if name is None: + name = cmd_fxn.__name__ + + registered_subcommands[name] = cmd_fxn + registered_subcommands_help[name] = kwargs.pop('help', '') + + return cmd_fxn + +######################### +class SortingHelpFormatter(argparse.RawTextHelpFormatter): + def __init__(self, *args, **kwargs): + argparse.RawTextHelpFormatter.__init__(self, indent_increment=1, max_help_position=17, + *args, **kwargs) +# def add_arguments(self, actions): +# actions = sorted(actions, key=attrgetter('help')) +# super(SortingHelpFormatter, self).add_arguments(actions) + +######################### +class SubCommandHandler(argparse.ArgumentParser): + """Modified ArgumentHandler from https://github.com/druths/arghandler""" + + def __init__(self, *args, **kwargs): + """ + All constructor arguments are the same as found in `argparse.ArgumentParser`. + + kwargs + ------ + * `use_subcommand_help [=False]`: when printing out the help message, use a shortened + version of the help message that simply shows the sub-commands supported and + their description. + + * `enable_autocompletion [=False]`: make it so that the command line + supports autocompletion + + """ + + ### extract any special keywords here + self._use_subcommand_help = kwargs.pop('use_subcommand_help', False) + self._enable_autocompletion = kwargs.pop('enable_autocompletion', False) + + self._log = kwargs.pop('log', None) + if self._log is None: + self._log = logging.getLogger(__name__) + + self._logging_handler_done = False + + self._ignore_remainder = False + self._use_subcommands = True + self._subcommand_lookup = dict() + self._subcommand_help = dict() + + self._has_parsed = False + + # setup the class + if self._use_subcommand_help: + argparse.ArgumentParser.__init__(self, formatter_class=SortingHelpFormatter, *args, **kwargs) + else: + argparse.ArgumentParser.__init__(self, *args, **kwargs) + + def add_argument(self, *args, **kwargs): + """ + This has the same functionality as `argparse.ArgumentParser.add_argument`. + """ + # just watch for the REMAINDER nargs to see if subcommands are relevant + + assert not(self._ignore_remainder and 'nargs' in kwargs and kwargs['nargs'] == argparse.REMAINDER) + # self._use_subcommands = False + + return argparse.ArgumentParser.add_argument(self, *args, **kwargs) + + def set_subcommands(self, subcommand_lookup): + """ + Provide a set of subcommands that this instance of ArgumentHandler should + support. This is an alternative to using the decorator `@subcmd`. Note that + the total set of subcommands supported will be those specified in this method + combined with those identified by the decorator. + """ + if type(subcommand_lookup) is not dict: + raise TypeError('subcommands must be specified as a dict') + + # sanity check the subcommands + self._subcommand_lookup = {} + self._subcommand_help = {} + for cn, cf in subcommand_lookup.items(): + if type(cn) is not str: + raise TypeError('subcommand keys must be strings. Found %s' % str(cn)) + if type(cf) == tuple: + if not callable(cf[0]): + raise TypeError('subcommand with name %s must be callable' % cn) + else: + self._subcommand_lookup[cn] = cf[0] + self._subcommand_help[cn] = cf[1] + elif not callable(cf): + raise TypeError('subcommand with name %s must be callable' % cn) + else: + self._subcommand_lookup[cn] = cf + self._subcommand_help[cn] = '' + + return + + def logging_handler(parser, args): + if not parser._logging_handler_done: + + _args = vars(args) + + log = parser._log + level = log.level + + # NOTE: logging levels are as follows: + # logging.CRITICAL = 50 + # logging.ERROR = 40 + # logging.WARNING = 30 + # logging.INFO = 20 + # logging.DEBUG = 10 + # logging.NOTSET = 0 + + delta = _args.get('verbose', None) + if delta is not None: + level = max(logging.DEBUG, level - int(delta) * logging.DEBUG) + + delta = _args.get('quiet', None) + if delta is not None: + level = min(logging.CRITICAL, level + int(delta) * logging.DEBUG) + + if log.level != level: + log.debug("Changing logging level: {0} -> {1}" + .format(logging.getLevelName(log.level), logging.getLevelName(level))) + log.setLevel(level) + log.debug("New logging level: {0}".format(logging.getLevelName(log.level))) + + parser._logging_handler_done = True + + + + def parse_args(self, argv=None): + """ + Works the same as `argparse.ArgumentParser.parse_args`. + """ + + group = self.add_mutually_exclusive_group() + group.add_argument("-v", "--verbose", action="count", help='increase verbosity') + group.add_argument("-q", "--quiet", action="count", help='decrease verbosity') + + # add_argument, set_logging_level, set_subcommands, + # handler.set_logging_argument('-l', '--log_level', default_level=logging.INFO) + + self.add_argument('-H', '--helpall', action=HelpAllAction, + nargs=0, default=argparse.SUPPRESS, required=False, type=None, metavar=None, + help="show detailed help and exit") + + + global registered_subcommands, registered_subcommands_help + + if self._has_parsed: + raise Exception('ArgumentHandler.parse_args can only be called once') + + # collect subcommands into _subcommand_lookup + for cn, cf in registered_subcommands.items(): + self._subcommand_lookup[cn] = cf + self._subcommand_help[cn] = registered_subcommands_help[cn] + + assert len(self._subcommand_lookup) > 0 +# self._use_subcommands = False + + # add in subcommands if appropriate + assert self._use_subcommands +# if not self._use_subcommands: +# pass +# else: + max_cmd_length = max([len(x) for x in self._subcommand_lookup.keys()]) + subcommands_help_text = 'the subcommand to run' + if self._use_subcommand_help: + subcommands_help_text = ':\n' + for command in sorted(self._subcommand_lookup.keys()): # Sorted... + subcommands_help_text += command.ljust(max_cmd_length + 2) + subcommands_help_text += self._subcommand_help[command] + subcommands_help_text += '\n' + + self.add_argument('cmd', choices=self._subcommand_lookup.keys(), help=subcommands_help_text, + metavar='subcommand') + + cargs_help_msg = 'arguments for the subcommand' if not self._use_subcommand_help else argparse.SUPPRESS + self.add_argument('cargs', nargs=argparse.REMAINDER, help=cargs_help_msg) + + # handle autocompletion if requested + if self._enable_autocompletion: + import argcomplete + argcomplete.autocomplete(self) + + # parse arguments + args = argparse.ArgumentParser.parse_args(self, argv) + + self._has_parse = True + + +# cargs_help_msg = 'arguments for the subcommand' if not self._use_subcommand_help else argparse.SUPPRESS +# self.add_argument('cargs', nargs=argparse.REMAINDER, help=cargs_help_msg) + + return args + + def run(self, argv=None, context_fxn=None): + """ + This method triggers a three step process: + + 1) Parse the arguments in `argv`. If not specified, `sys.argv` is + used. + + 2) Configure the logging level. This only happens if the + `set_logging_argument` was called. + + 3) Run the appropriate subcommand. This only happens if subcommands + are available and enabled. Prior to the subcommand being run, + the `context_fxn` is called. This function accepts one argument - + the namespace returned by a call to `parse_args`. + + The parsed arguments are all returned. + """ + # get the arguments + args = self.parse_args(argv) + + # # handle the logging argument + # if self._logging_argument: + # level = eval('args.%s' % self._logging_argument) + # + # # convert the level + # level = eval('logging.%s' % level) + # + # # call the logging config fxn + # self._logging_config_fxn(level, args) + + self.logging_handler(args) +# pedantic_handler(self, vars(args)) + + # generate the context + context = args + if context_fxn: + context = context_fxn(args) + + # create the sub command argument parser + scmd_parser = argparse.ArgumentParser(prog='%s %s' % (self.prog, args.cmd), add_help=True) + scmd_parser._log = self._log + + # handle the subcommands + self._subcommand_lookup[args.cmd](scmd_parser, context, args.cargs) + + return args # run() + + +class MyHelpAction(argparse.Action): + def __init__(self, + option_strings, + dest=argparse.SUPPRESS, + default=argparse.SUPPRESS, + help=None): + super(MyHelpAction, self).__init__( + option_strings=option_strings, + dest=dest, + default=default, + nargs=0, + help=help) + + def __call__(self, parser, namespace, values, option_string=None): + parser.print_help() + raise BaseException("Help was printed!") + + +class HelpAllAction(argparse.Action): + def __init__(self, option_strings, *args, **kwargs): + super(HelpAllAction, self).__init__(option_strings=option_strings, *args, **kwargs) + + def __call__(self, parser, args, values, option_string=None): + for cn in sorted(parser._subcommand_lookup.keys()): + # create the sub command argument parser + scmd_parser = argparse.ArgumentParser(prog='%s %s' % (parser.prog, cn), add_help=False) + scmd_parser.add_argument('-h', '--help', action=MyHelpAction, help="show %(prog)s's help message") + try: + print('\n') + a = parser._subcommand_lookup[cn](scmd_parser, args, ['--help']) + except: + pass + + exit(0) + setattr(args, self.dest, values) + + + + + + diff --git a/config/tests/test_validate.py b/config/tests/test_validate.py index 4840b9e..108b1d7 100644 --- a/config/tests/test_validate.py +++ b/config/tests/test_validate.py @@ -7,12 +7,25 @@ import sys from os import path + DIR=path.dirname( path.dirname( path.abspath(__file__) ) ) -sys.path.append( DIR ) +sys.path.append(DIR) +sys.path.append(path.join(DIR, 'config')) -from hilbert_cli_config import * from helpers import * +from hilbert_cli_config import * +from subcmdparser import * + +#from config.hilbert_cli_config import * +#from config.helpers import * +#from config.subcmdparser import * + + +# sys.path.append( DIR ) + +#from hilbert_cli_config import * +#from helpers import * import pytest # NOQA import os # NOQA diff --git a/tools/hilbert.py b/tools/hilbert.py index 90f53ac..828705c 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -1,9 +1,11 @@ -#!/usr/bin/env python2 +#! /usr/bin/env python3 # -*- coding: utf-8 -*- # encoding: utf-8 # coding: utf-8 +# PYTHON_ARGCOMPLETE_OK + from __future__ import absolute_import, print_function, unicode_literals assert __name__ == "__main__" @@ -11,107 +13,43 @@ import sys from os import path DIR=path.dirname(path.dirname(path.abspath(__file__))) + +sys.path.append(DIR) sys.path.append(path.join(DIR, 'config')) from helpers import * from hilbert_cli_config import * +from subcmdparser import * #from config.hilbert_cli_config import * #from config.helpers import * +#from config.subcmdparser import * -from arghandler import * # NOQA import argparse # NOQA import logging log = logging.getLogger(__name__) # -# level=logging.INFO!!! , datefmt='%Y.%m.%d %I:%M:%S %p' -logging.basicConfig(format='%(levelname)s [%(filename)s:%(lineno)d]: %(message)s', level=logging.DEBUG) -# %(name)s Name of the logger (logging channel) -# %(levelno)s Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL) -# %(levelname)s Text logging level for the message ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL") -# %(pathname)s Full pathname of the source file where the logging call was issued (if available) -# %(filename)s Filename portion of pathname -# %(module)s Module (name portion of filename) -# %(lineno)d Source line number where the logging call was issued (if available) -# %(funcName)s Function name -# %(created)f Time when the LogRecord was created (time.time() return value) -# %(asctime)s Textual time when the LogRecord was created -# %(msecs)d Millisecond portion of the creation time -# %(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded -# (typically at application startup time) -# %(thread)d Thread ID (if available) -# %(threadName)s Thread name (if available) -# %(process)d Process ID (if available) -# %(message)s The result of record.getMessage(), computed just as the record is emitted - -import traceback -def main_exception_handler(type, value, tb): - log.exception("Uncaught exception! Type: {0}, Value: {1}, TB: {2}".format(type, value, traceback.format_tb(tb))) - -# sys.excepthook = main_exception_handler # Install exception handler - -def _version(): - import platform - import dill - import ruamel.yaml as yaml - import semantic_version - log.info("Python version: {}".format(platform.python_version())) - log.info("ruamel.yaml version: {}".format(yaml.__version__)) - log.info("dill version: {}".format(dill.__version__)) - log.info("semantic_version version: {}".format(semantic_version.__version__)) -# log.info("Hilbert.Config version: {}".format(config.__version__)) # TODO! - - # arghandler version? dill version? etc? - - -def _load(f): - return load_yaml_file(f) # TODO: check that this is a dictionary! - +#import traceback +#def main_exception_handler(type, value, tb): +# log.exception("Uncaught exception! Type: {0}, Value: {1}, TB: {2}".format(type, value, traceback.format_tb(tb))) +##sys.excepthook = main_exception_handler # Install exception handler -# @subcmd('version', help='Display version info') # TODO: --version -def cmd_version(parser, context, args): - log.debug("Running '{}'".format('--version')) - _version() - log.debug("Done") - exit(0) - - -@subcmd('cfg_verify', help='Check correctness of a given general Hilbert configuration (YAML) file as far as possible') +@subcmd('cfg_verify', help='verify the correctness of Hilbert Configuration .YAML file') def cmd_verify(parser, context, args): - global PEDANTIC - global INPUT_DIRNAME - log.debug("Running '{}'".format('cfg_verify')) - # 2 input sources: .YAML or .PICKLE - parser.add_argument('-if', '--configfile', required=False, - help="specify input .YAML file (default: 'Hilbert.yml')") - - ctx = vars(context) - pedantic_handler(parser, ctx, args) + # TODO: optional due to default value? + parser.add_argument('configfile', help="input .YAML file, default: 'Hilbert.yml'", nargs='?') args = parser.parse_args(args) + cfg = input_handler(parser, vars(context), args) - # if 'configdump' in ctx: - # df = ctx['configdump'] - # if df is not None: - # log.error("Sorry: cannot verify a dump file.") - # exit(1) - - cfg = input_handler(parser, ctx, args) + assert cfg is not None log.debug("Done") - exit(0) - -def pedantic_handler(parser, ctx, args): - global PEDANTIC + return args - if 'pedantic' in ctx: - PEDANTIC = ctx['pedantic'] - - if PEDANTIC: - log.debug("PEDANTIC mode is ON!") def input_handler(parser, ctx, args): global INPUT_DIRNAME @@ -160,14 +98,13 @@ def input_handler(parser, ctx, args): if fn is not None: log.info("Loading '{}'...".format(fn)) try: - yml = _load(fn) - log.info("Input file is a valid YAML!") + yml = load_yaml_file(fn) + log.info("Input file is a correct YAML!") - os.chdir(INPUT_DIRNAME) log.info("Data Validation/Parsing: ") - cfg = parse_hilbert(yml) - + os.chdir(INPUT_DIRNAME) # NOTE: references relative to input file's location! + cfg = parse_hilbert(yml) # NOTE: checks that this is a proper dictionary... except: log.exception("ERROR: wrong input file: '{}'!".format(fn)) exit(1) @@ -189,8 +126,8 @@ def input_handler(parser, ctx, args): return cfg - def output_handler(parser, ctx, args): + global PEDANTIC args = vars(args) od = None @@ -207,10 +144,9 @@ def output_handler(parser, ctx, args): od = None return od + def cmd_list(parser, context, args, obj): - ctx = vars(context) - pedantic_handler(parser, ctx, args) - cfg = input_handler(parser, ctx, args) + cfg = input_handler(parser, vars(context), args) return cfg.query(obj) @@ -223,9 +159,11 @@ def cmd_query(parser, context, args): parser.add_argument('-od', '--outputdump', default=argparse.SUPPRESS, help="specify output dump file") - parser.add_argument('-if', '--configfile', required=False, - help="specify input .YAML file (default: 'Hilbert.yml')") - parser.add_argument('-id', '--configdump', required=False, + group = parser.add_mutually_exclusive_group(required=False) + + group.add_argument('--configfile', required=False, + help="specify input .YAML file (default: 'Hilbert.yml')") # NOTE: default! + group.add_argument('--configdump', required=False, help="specify input dump file") args = parser.parse_args(args) @@ -250,23 +188,27 @@ def cmd_query(parser, context, args): else: print(yaml_dump(obj)) - od = output_handler(parser, vars(context), args) + od = output_handler(parser, vars(context), args) if od is not None: log.info("Writing the configuration into '{}'...".format(od)) pickle_dump(od, obj) log.debug("Done") - exit(0) + return args + @subcmd('list_applications', help='list application IDs') def cmd_list_applications(parser, context, args): log.debug("Running '{}'" . format('list_applications')) - parser.add_argument('-if', '--configfile', required=False, + group = parser.add_mutually_exclusive_group() + + group.add_argument('--configfile', required=False, help="specify input .YAML file (default: 'Hilbert.yml')") - parser.add_argument('-id', '--configdump', required=False, + group.add_argument('--configdump', required=False, help="specify input dump file") + args = parser.parse_args(args) log.debug("Listing all Application ID...") @@ -287,16 +229,21 @@ def cmd_list_applications(parser, context, args): print(yaml_dump(obj)) log.debug("Done") - exit(0) + return args + + @subcmd('list_stations', help='list station IDs') def cmd_list_stations(parser, context, args): log.debug("Running '{}'" . format('list_stations')) - parser.add_argument('-if', '--configfile', required=False, + group = parser.add_mutually_exclusive_group() + + group.add_argument('--configfile', required=False, help="specify input .YAML file (default: 'Hilbert.yml')") - parser.add_argument('-id', '--configdump', required=False, + group.add_argument('--configdump', required=False, help="specify input dump file") + args = parser.parse_args(args) log.debug("Listing all Station ID...") @@ -316,17 +263,21 @@ def cmd_list_stations(parser, context, args): print(yaml_dump(obj)) log.debug("Done") - exit(0) + return args + @subcmd('list_profiles', help='list profile IDs') def cmd_list_profiles(parser, context, args): log.debug("Running '{}'" . format('list_profiles')) - parser.add_argument('-if', '--configfile', required=False, + group = parser.add_mutually_exclusive_group() + + group.add_argument('--configfile', required=False, help="specify input .YAML file (default: 'Hilbert.yml')") - parser.add_argument('-id', '--configdump', required=False, + group.add_argument('--configdump', required=False, help="specify input dump file") + args = parser.parse_args(args) log.debug("Listing all Profile ID...") @@ -346,17 +297,20 @@ def cmd_list_profiles(parser, context, args): print(yaml_dump(obj)) log.debug("Done") - exit(0) + return args @subcmd('list_groups', help='list (named) group IDs') def cmd_list_groups(parser, context, args): log.debug("Running '{}'" . format('list_groups')) - parser.add_argument('-if', '--configfile', required=False, + group = parser.add_mutually_exclusive_group() + + group.add_argument('--configfile', required=False, help="specify input .YAML file (default: 'Hilbert.yml')") - parser.add_argument('-id', '--configdump', required=False, + group.add_argument('--configdump', required=False, help="specify input dump file") + args = parser.parse_args(args) log.debug("Listing all Group ID...") @@ -376,17 +330,20 @@ def cmd_list_groups(parser, context, args): print(yaml_dump(obj)) log.debug("Done") - exit(0) + return args @subcmd('list_services', help='list service IDs') def cmd_list_services(parser, context, args): log.debug("Running '{}'" . format('list_services')) - parser.add_argument('-if', '--configfile', required=False, + group = parser.add_mutually_exclusive_group() + + group.add_argument('--configfile', required=False, help="specify input .YAML file (default: 'Hilbert.yml')") - parser.add_argument('-id', '--configdump', required=False, + group.add_argument('--configdump', required=False, help="specify input dump file") + args = parser.parse_args(args) log.debug("Listing all Service ID...") @@ -406,54 +363,58 @@ def cmd_list_services(parser, context, args): print(yaml_dump(obj)) log.debug("Done") - exit(0) + return args # NOTE: just a helper ATM def cmd_action(parser, context, args, stationId, action, action_args): stations = None + log.debug("Validating given StationID: '%s'...", stationId) try: + log.debug("Querying all stations in the Configuration...") stations = cmd_list(parser, context, args, 'Stations/all') except: log.exception("Sorry could not get the list of '{}' from the input file!".format('stations')) exit(1) assert stations is not None - assert stationId in stations.get_data() - station = stations.get_data()[stationId] + if stationId not in stations.get_data(): + log.error("Invalid StationID (%s)!", stationId) + exit(1) + station = stations.get_data()[stationId] assert station is not None -# if isinstance(station, Base): -# print(yaml_dump(station.data_dump())) -# else: -# print(yaml_dump(station)) - - log.debug("Trying to run '{0} {1}' on remote station '{2}'" . format(action, action_args, stationId)) + log.debug("StationID is valid according to the Configuration!") + log.debug("Running action: '{0} {1}' on station '{2}'" .format(action, str(action_args), stationId)) try: station.run_action(action, action_args) # NOTE: temporary API for now except: - log.exception("Could not run '{0} {1}' on remote station '{2}'" . format(action, action_args, stationId)) + log.exception("Could not run '{0} {1}' on station '{2}'" . format(action, str(action_args), stationId)) exit(1) - + return args @subcmd('poweron', help='poweron a station') def cmd_poweron(parser, context, args): log.debug("Running '{}'" . format('cmd_poweron')) - parser.add_argument('-if', '--configfile', required=False, + group = parser.add_mutually_exclusive_group() + + group.add_argument('--configfile', required=False, help="specify input .YAML file (default: 'Hilbert.yml')") - parser.add_argument('-id', '--configdump', required=False, + group.add_argument('--configdump', required=False, help="specify input dump file") - parser.add_argument('-s', '--station', required=True, help="specify the station") - parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments") + parser.add_argument('StationID', help="station to power-on via network") + parser.add_argument('action_args', nargs='?', help="optional arguments for poweron", metavar='args') args = parser.parse_args(args) _args = vars(args) - assert 'station' in _args - stationId = _args['station'] + + assert 'StationID' in _args + stationId = _args['StationID'] + log.debug("StationID: '%s'", stationId) action_args = None if 'action_args' in _args: @@ -462,25 +423,29 @@ def cmd_poweron(parser, context, args): cmd_action(parser, context, args, stationId, 'poweron', action_args) log.debug("Done") - exit(0) + return args @subcmd('shutdown', help='shutdown a station') def cmd_shutdown(parser, context, args): log.debug("Running '{}'" . format('cmd_shutdown')) - parser.add_argument('-if', '--configfile', required=False, + group = parser.add_mutually_exclusive_group() + + group.add_argument('--configfile', required=False, help="specify input .YAML file (default: 'Hilbert.yml')") - parser.add_argument('-id', '--configdump', required=False, + group.add_argument('--configdump', required=False, help="specify input dump file") - parser.add_argument('-s', '--station', required=True, help="specify the station") - parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments") + parser.add_argument('StationID', help="specify the station") + parser.add_argument('action_args', nargs='?', help="optional arguments for shutdown", metavar='args') args = parser.parse_args(args) _args = vars(args) - assert 'station' in _args - stationId = _args['station'] + + assert 'StationID' in _args + stationId = _args['StationID'] + log.debug("StationID: '%s'", stationId) action_args = None if 'action_args' in _args: @@ -489,24 +454,29 @@ def cmd_shutdown(parser, context, args): cmd_action(parser, context, args, stationId, 'shutdown', action_args) log.debug("Done") - exit(0) + return args + @subcmd('deploy', help='deploy local configuration to a station') def cmd_deploy(parser, context, args): log.debug("Running '{}'" . format('cmd_deploy')) - parser.add_argument('-if', '--configfile', required=False, + group = parser.add_mutually_exclusive_group() + + group.add_argument('--configfile', required=False, help="specify input .YAML file (default: 'Hilbert.yml')") - parser.add_argument('-id', '--configdump', required=False, + group.add_argument('--configdump', required=False, help="specify input dump file") - parser.add_argument('-s', '--station', required=True, help="specify the station") - parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments") + parser.add_argument('StationID', help="specify the station") + parser.add_argument('action_args', nargs='?', help="optional arguments for deploy", metavar='args') args = parser.parse_args(args) _args = vars(args) - assert 'station' in _args - stationId = _args['station'] + + assert 'StationID' in _args + stationId = _args['StationID'] + log.debug("StationID: '%s'", stationId) action_args = None if 'action_args' in _args: @@ -515,24 +485,29 @@ def cmd_deploy(parser, context, args): cmd_action(parser, context, args, stationId, 'deploy', action_args) log.debug("Done") - exit(0) + return args + @subcmd('start', help='start a service/application on a station') def cmd_start(parser, context, args): - log.debug("Running '{}'" . format('cmd_deploy')) + log.debug("Running '{}'" . format('cmd_start')) + + group = parser.add_mutually_exclusive_group() - parser.add_argument('-if', '--configfile', required=False, + group.add_argument('--configfile', required=False, help="specify input .YAML file (default: 'Hilbert.yml')") - parser.add_argument('-id', '--configdump', required=False, + group.add_argument('--configdump', required=False, help="specify input dump file") - parser.add_argument('-s', '--station', required=True, help="specify the station") - parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments (ApplicationID/ServiceID)") + parser.add_argument('StationID', help="specify the station") + parser.add_argument('action_args', nargs='?', help="optional argument for start: ApplicationID/ServiceID ", metavar='id') args = parser.parse_args(args) _args = vars(args) - assert 'station' in _args - stationId = _args['station'] + + assert 'StationID' in _args + stationId = _args['StationID'] + log.debug("StationID: '%s'", stationId) action_args = None if 'action_args' in _args: @@ -541,26 +516,29 @@ def cmd_start(parser, context, args): cmd_action(parser, context, args, stationId, 'start', action_args) log.debug("Done") - exit(0) + return args @subcmd('finish', help='finish a service/application on a station') def cmd_finish(parser, context, args): log.debug("Running '{}'" . format('cmd_finish')) - parser.add_argument('-if', '--configfile', required=False, + group = parser.add_mutually_exclusive_group() + + group.add_argument('--configfile', required=False, help="specify input .YAML file (default: 'Hilbert.yml')") - parser.add_argument('-id', '--configdump', required=False, + group.add_argument('--configdump', required=False, help="specify input dump file") - - parser.add_argument('-s', '--station', required=True, help="specify the station") - parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments (ApplicationID/ServiceID)") + parser.add_argument('StationID', help="specify the station") + parser.add_argument('action_args', nargs='?', help="optional argument for finish: ApplicationID/ServiceID ", metavar='id') args = parser.parse_args(args) _args = vars(args) - assert 'station' in _args - stationId = _args['station'] + + assert 'StationID' in _args + stationId = _args['StationID'] + log.debug("StationID: '%s'", stationId) action_args = None if 'action_args' in _args: @@ -569,25 +547,30 @@ def cmd_finish(parser, context, args): cmd_action(parser, context, args, stationId, 'finish', action_args) log.debug("Done") - exit(0) + return args -@subcmd('app_switch', help='app_switch switch top application on a station') +@subcmd('app_switch', help='switch top application on a station') def cmd_app_switch(parser, context, args): log.debug("Running '{}'" . format('cmd_app_switch')) - parser.add_argument('-if', '--configfile', required=False, + group = parser.add_mutually_exclusive_group() + + group.add_argument('--configfile', required=False, help="specify input .YAML file (default: 'Hilbert.yml')") - parser.add_argument('-id', '--configdump', required=False, + group.add_argument('--configdump', required=False, help="specify input dump file") - parser.add_argument('-s', '--station', required=True, help="specify the station") - parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments (new ApplicationID)") + parser.add_argument('StationID', help="specify the station") + parser.add_argument('action_args', nargs=1, help="new top Application", metavar='ApplicationID') + parser.add_argument('other_args', nargs='?', help="optional arguments for 'app_switch'", metavar='args') args = parser.parse_args(args) _args = vars(args) - assert 'station' in _args - stationId = _args['station'] + + assert 'StationID' in _args + stationId = _args['StationID'] + log.debug("StationID: '%s'", stationId) action_args = None if 'action_args' in _args: @@ -596,31 +579,37 @@ def cmd_app_switch(parser, context, args): cmd_action(parser, context, args, stationId, 'app_switch', action_args) log.debug("Done") - exit(0) + return args -# @subcmd('station_action', help='perform some action with one of stations') +# @subcmd('station_action', help=argparse.SUPPRESS) def cmd_station_action(parser, context, args): log.debug("Running '{}'" . format('station_action')) - parser.add_argument('-if', '--configfile', required=False, + group = parser.add_mutually_exclusive_group() + + group.add_argument('--configfile', required=False, help="specify input .YAML file (default: 'Hilbert.yml')") - parser.add_argument('-id', '--configdump', required=False, + group.add_argument('--configdump', required=False, help="specify input dump file") - parser.add_argument('-s', '--station', required=True, help="specify the station") - parser.add_argument('-a', '--action', required=True, help="specify the action") + # parser.add_argument('-a', '--action', required=True, help="specify the action") + + parser.add_argument('Action', help="specify the action") + parser.add_argument('StationID', help="specify the station") + parser.add_argument('-g', '--action_args', required=False, help="specify the action arguments") args = parser.parse_args(args) _args = vars(args) - assert 'station' in _args - assert 'action' in _args + assert 'StationID' in _args + stationId = _args['StationID'] + log.debug("StationID: '%s'", stationId) - stationId = _args['station'] - action = _args['action'] + assert 'Action' in _args + action = _args['Action'] action_args = None if 'action_args' in _args: @@ -629,24 +618,91 @@ def cmd_station_action(parser, context, args): cmd_action(parser, context, args, stationId, action, action_args) log.debug("Done") - exit(0) + return args +class PedanticModeAction(argparse.Action): + def __init__(self, option_strings, *args, **kwargs): + super(PedanticModeAction, self).__init__(option_strings=option_strings, *args, **kwargs) -def main(): -# handler = argparse.ArgumentParser() -# handler.parse_args() + def __call__(self, parser, args, values, option_string=None): + global PEDANTIC + args = parser.logging_handler(args) + PEDANTIC = True + if PEDANTIC: + log.debug("PEDANTIC mode is ON!") + + # print(self) + # print(args) + # print(values) +# print(self.dest) + + # setattr(args, self.dest, values) + + +def _version(): + import platform + import dill + import ruamel.yaml as yaml + import semantic_version - handler = ArgumentHandler(use_subcommand_help=True, enable_autocompletion=True, description="Hilbert - server tool: loads configuration and does something using it") + __version__ = '0.2.2-dev' # TODO: add git commit id? - # add_argument, set_logging_level, set_subcommands, -# handler.add_argument('-q', '--quiet', help='decrease verbosity', action='store_true') -# handler.add_argument('-v', '--verbose', help='increase verbosity', action='store_true') + log.debug("Running '{}'".format('version')) + + log.debug("Python version: {}".format(platform.python_version())) + log.debug("ruamel.yaml version: {}".format(yaml.__version__)) + log.debug("dill version: {}".format(dill.__version__)) + log.debug("semantic_version version: {}".format(semantic_version.__version__)) + log.info("Hilbert version: {}".format(__version__)) # TODO: this version?! + + log.debug("Done") -# handler.set_logging_argument('-l', '--log_level', default_level=logging.INFO) - # no arguments: 'store_const', 'store_true' or 'store_false' - handler.add_argument('-p', '--pedantic', required=False, action='store_true', - help="turn on pedantic mode") +class ListVersionsAction(argparse.Action): + def __init__(self, option_strings, *args, **kwargs): + super(ListVersionsAction, self).__init__(option_strings=option_strings, *args, **kwargs) + + def __call__(self, parser, args, values, option_string=None): + args = parser.logging_handler(args) + _version() + parser.exit(status=0) +# setattr(args, self.dest, values) + + +def main(): + # datefmt='%Y.%m.%d %I:%M:%S %p' + logging.basicConfig(format='%(levelname)s [%(filename)s:%(lineno)d]: %(message)s', level=logging.INFO) + log.setLevel(logging.INFO) + + # %(name)s Name of the logger (logging channel) + # %(levelno)s Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL) + # %(levelname)s Text logging level for the message ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL") + # %(pathname)s Full pathname of the source file where the logging call was issued (if available) + # %(filename)s Filename portion of pathname + # %(module)s Module (name portion of filename) + # %(lineno)d Source line number where the logging call was issued (if available) + # %(funcName)s Function name + # %(created)f Time when the LogRecord was created (time.time() return value) + # %(asctime)s Textual time when the LogRecord was created + # %(msecs)d Millisecond portion of the creation time + # %(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded + # (typically at application startup time) + # %(thread)d Thread ID (if available) + # %(threadName)s Thread name (if available) + # %(process)d Process ID (if available) + # %(message)s The result of record.getMessage(), computed just as the record is emitted + + handler = SubCommandHandler(use_subcommand_help=True, enable_autocompletion=True, log=log, + prog='hilbert', + description="Hilbert - server tool: loads configuration and does something using it") + + handler.add_argument('-p', '--pedantic', action=PedanticModeAction, + nargs=0, default=argparse.SUPPRESS, required=False, type=None, metavar=None, + help="turn on pedantic mode") + + handler.add_argument('-V', '--version', action=ListVersionsAction, + nargs=0, default=argparse.SUPPRESS, required=False, type=None, metavar=None, + help="show %(prog)s's version and exit") _argv = sys.argv[1:] @@ -654,9 +710,9 @@ def main(): if len(_argv) == 0: log.debug("No command arguments given => Showing usage help!") _argv = ['-h'] +# handler.print_help() -# args = handler.parse_args() - handler.run(_argv) - + args = handler.run(_argv) + handler.exit(status=0) main() From 9d4eba011cee6d04c6678f69578f2b3d6abaf181 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Fri, 25 Nov 2016 04:39:43 +0100 Subject: [PATCH 27/42] Moved tests to the top level + adaptation for searching for python library units Also updated related referencing files (Makefile, Doxyfile) --- .gitignore | 4 ++++ Doxyfile | 6 +++--- Makefile | 8 ++++---- {config/tests => tests}/__init__.py | 0 {config/tests => tests}/data/Hilbert.yml | 0 .../tests => tests}/data/Hilbert.yml.data.pickle | Bin {config/tests => tests}/data/dc.yml | 0 {config/tests => tests}/data/docker-compose.yml | 0 {config/tests => tests}/test_loadwarnings.py | 13 +++++++++++-- {config/tests => tests}/test_validate.py | 3 --- {config/tests => tests}/test_version.py | 13 ++++++++++--- 11 files changed, 32 insertions(+), 15 deletions(-) rename {config/tests => tests}/__init__.py (100%) rename {config/tests => tests}/data/Hilbert.yml (100%) rename {config/tests => tests}/data/Hilbert.yml.data.pickle (100%) rename {config/tests => tests}/data/dc.yml (100%) rename {config/tests => tests}/data/docker-compose.yml (100%) rename {config/tests => tests}/test_loadwarnings.py (82%) rename {config/tests => tests}/test_validate.py (99%) rename {config/tests => tests}/test_version.py (82%) diff --git a/.gitignore b/.gitignore index 5750fca..fe28c04 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,7 @@ STATIONS*/ templates/compose bashttpd.log lastapp.cfg +*~ +*.pyc +__pycache__ +.idea diff --git a/Doxyfile b/Doxyfile index d414da4..8771312 100644 --- a/Doxyfile +++ b/Doxyfile @@ -1,8 +1,8 @@ USE_MDFILE_AS_MAINPAGE = DOXYFILE_ENCODING = UTF-8 -PROJECT_NAME = hilbert-cli-config +PROJECT_NAME = Hilbert PROJECT_NUMBER = 0.0.1 -PROJECT_BRIEF = "Hilbert CLI Config" +PROJECT_BRIEF = "Hilbert CLI (server part)" PROJECT_LOGO = OUTPUT_DIRECTORY = doxydoc CREATE_SUBDIRS = NO @@ -83,7 +83,7 @@ WARN_IF_DOC_ERROR = YES WARN_NO_PARAMDOC = NO WARN_FORMAT = "$file:$line: $text" WARN_LOGFILE = -INPUT = config +INPUT = config tools INPUT_ENCODING = UTF-8 FILE_PATTERNS = "*.py" "*.md" RECURSIVE = YES diff --git a/Makefile b/Makefile index 464cc94..27ca6ed 100644 --- a/Makefile +++ b/Makefile @@ -3,8 +3,8 @@ # Simple Makefile used during development to check compliance with # pep8 and to generate documentation -SRC=config/hilbert-cli-config.py -NAME=hilbert-cli-config +SRC=config/*.py tools/*.py +NAME=hilbert .PHONY: usage pep8 apidocs clean pylint install build @@ -12,8 +12,8 @@ usage: # Print Targets @grep '^[^#[:space:]].*:' Makefile check: # Run the tests - /bin/bash -c 'cd config/tests/ && py.test -v test_*.py' - /bin/bash -c 'cd config/tests/ && py.test-3 -v test_*.py' + /bin/bash -c 'cd tests/ && py.test -v test_*.py' + /bin/bash -c 'cd tests/ && py.test-3 -v test_*.py' pep8: ${SRC} # Check for PEP8 compliance pep8 --first --show-source --show-pep8 ${SRC} diff --git a/config/tests/__init__.py b/tests/__init__.py similarity index 100% rename from config/tests/__init__.py rename to tests/__init__.py diff --git a/config/tests/data/Hilbert.yml b/tests/data/Hilbert.yml similarity index 100% rename from config/tests/data/Hilbert.yml rename to tests/data/Hilbert.yml diff --git a/config/tests/data/Hilbert.yml.data.pickle b/tests/data/Hilbert.yml.data.pickle similarity index 100% rename from config/tests/data/Hilbert.yml.data.pickle rename to tests/data/Hilbert.yml.data.pickle diff --git a/config/tests/data/dc.yml b/tests/data/dc.yml similarity index 100% rename from config/tests/data/dc.yml rename to tests/data/dc.yml diff --git a/config/tests/data/docker-compose.yml b/tests/data/docker-compose.yml similarity index 100% rename from config/tests/data/docker-compose.yml rename to tests/data/docker-compose.yml diff --git a/config/tests/test_loadwarnings.py b/tests/test_loadwarnings.py similarity index 82% rename from config/tests/test_loadwarnings.py rename to tests/test_loadwarnings.py index 2fa9ef8..0d1c374 100644 --- a/config/tests/test_loadwarnings.py +++ b/tests/test_loadwarnings.py @@ -4,8 +4,17 @@ from __future__ import absolute_import, print_function, unicode_literals # NOQA -from ..hilbert_cli_config import load_yaml -# from ..helpers import load_yaml +import sys +from os import path + +DIR=path.dirname( path.dirname( path.abspath(__file__) ) ) +sys.path.append(DIR) +sys.path.append(path.join(DIR, 'config')) + +from helpers import * +from hilbert_cli_config import * +from subcmdparser import * + import pytest # NOQA diff --git a/config/tests/test_validate.py b/tests/test_validate.py similarity index 99% rename from config/tests/test_validate.py rename to tests/test_validate.py index 108b1d7..e838d1f 100644 --- a/config/tests/test_validate.py +++ b/tests/test_validate.py @@ -6,10 +6,7 @@ import sys from os import path - - DIR=path.dirname( path.dirname( path.abspath(__file__) ) ) - sys.path.append(DIR) sys.path.append(path.join(DIR, 'config')) diff --git a/config/tests/test_version.py b/tests/test_version.py similarity index 82% rename from config/tests/test_version.py rename to tests/test_version.py index 29e747e..a1d623d 100644 --- a/config/tests/test_version.py +++ b/tests/test_version.py @@ -4,9 +4,16 @@ from __future__ import absolute_import, print_function, unicode_literals # NOQA -from ..hilbert_cli_config import SemanticVersion -from ..hilbert_cli_config import load_yaml -# helpers +import sys +from os import path + +DIR=path.dirname( path.dirname( path.abspath(__file__) ) ) +sys.path.append(DIR) +sys.path.append(path.join(DIR, 'config')) + +from helpers import * +from hilbert_cli_config import * +from subcmdparser import * import pytest # NOQA From 847647b3c7b718b30674014e744b6b10332f1999 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Fri, 25 Nov 2016 04:57:45 +0100 Subject: [PATCH 28/42] Added Config API ID to Validator objects NOTE: Config API ID should only depend on the changes to config/hilbert_cli_config.py! --- config/.gitattributes | 2 ++ config/hilbert_cli_config.py | 17 +++++++---------- tests/data/Hilbert.yml.data.pickle | Bin 10782 -> 10833 bytes tools/hilbert.py | 4 +--- 4 files changed, 10 insertions(+), 13 deletions(-) create mode 100644 config/.gitattributes diff --git a/config/.gitattributes b/config/.gitattributes new file mode 100644 index 0000000..c5200a6 --- /dev/null +++ b/config/.gitattributes @@ -0,0 +1,2 @@ +hilbert_cli_config.py ident + diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index e7a6696..0203f8a 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -211,7 +211,11 @@ def __init__(self, parent): # TODO: add tag? here or in some child? AbstractValidator.__init__(self) assert self._parent is None self._parent = parent + self.__API_VERSION_ID = "$Id$" + def get_api_version(self): + return self.__API_VERSION_ID + @classmethod def set_version(cls, v): """To be set once only for any Validator class!""" @@ -238,14 +242,6 @@ def get_data(self): if _d is None: _d = self._default_data -# if _d is None: -# return _d - -# while isinstance(_d, Base): -# _d = _d.get_data() -# if _d is None: -# return _d - return _d @classmethod @@ -276,11 +272,12 @@ def __repr__(self): def __eq__(self, other): assert isinstance(self, Base) - if not isinstance(other, Base): - return self.get_data() == other +# if not isinstance(other, Base): +# return self.get_data() == other assert isinstance(other, Base) + assert self.get_api_version() == other.get_api_version() # Same /config/hilbert_cli_config.py should be used! return self.get_data() == other.get_data() def __ne__(self, other): diff --git a/tests/data/Hilbert.yml.data.pickle b/tests/data/Hilbert.yml.data.pickle index d1b37e8505f128ddd87e09b16e9ba5aafad68d3b..8451d333da9361d9503a4690754587787e4f376c 100644 GIT binary patch literal 10833 zcmbVS34B|{@peK2LE#GbjR*l8z;^7!AvOe1ViTJrcCeg8(1Q9bJ!d6kNjp!Ff=eT-qd*;Blwzh2Ep0w(vTDG>UYU_P6 z2Z0x`wv{RqR!Psx%r}Bo&C>H-y>EMFU(oBMQm;CCzc^j%Oh->5p%*~m{;p26t9>#@ z>@j?Hn>Wxxg|QFF><59VU52L*j2)Ze34IU-J=oQUa8RxzoHLvCqRau{Weeq8sh+p9 zHEWwb)C}!&^kLL?c)Q`*JB^e+Vz26k2R0O(T0$QQrAN8?XevECqSUN(cpzJXls-ny zzf2#SnTvKU`Z&w1IlIPk>})o*X*j!Oa4bDMI+7h8(8p)GAhl#T-=Cc5$>sX`a@~_w z&)GR^!s=U*U(s#lR!-)6mMyndO|Dq6Y*}w_Z(nkWKEdq2F_@!IboEK9NX8C(5s-L&(-}@!OaL%jRUKfTsbtnVa?#!cotN4Q)+z3 z)oaXh#Gce^&DLRIS*vXC&;zqd1`Qf=-kS7O6HmcQj)ET*=WHHA-*1L~V8TrA@YZj#}k7aD?S> z1Oq2ksa#>E{alsudB(!q7z-{_#O39#&SG*{(z$B2(FjOAuU)0gbba^?t;ud4+Ymv} z&|qq8e9d5LoP1YXA&fl5vr2NaILbH8)rPiNz)TV_+uGGd(+aj%u)Ts=3oxsK*@`fm zf;p~0K#3Yaad%6up5g+yWtRtAruU|b74i6->R^tsVj4{1_ zjNzfR1yK)frk(iSQ&zcF$oWDEUBf)ML zi(RszN55!keZpXhfs&_!8SpAb+&Rq|LY@i0)ftGj>1zNU9Js_}XuHwX zFWCdsFKstiq$}%}84W{gI>xEt<(Y+MT8{C2n)MZ#Mc|BC<$Pr-IkYCpi4@A)^ec&4 z6aVPB*ocXeo%W6>N54ujO?kDeUqjuC)S=4c9j`UIf-L8CBaT|4!ZY>tJX7BgoT+bA z-U<39{{(%rcY-P$mCBroH!7Zivp)3}Gj1|HC-nOp`U88I z<%81-{15HT03V)aKJXDgihQ&sTExLMf}Aj9-wGps%+((!T+fKWHQyYvBd`s__HBqk zH@3#0PqZ@#ebNLWb(^a{h1v~H9UgZbe9?rXFsb>py8gdRlOgFd>ehz-EJM=uen>KD zPk_VE#SP&(W`Na%z8$N)!_}YXD&x|gV6Z#skY8vw?!SE^>pNxE(qD|z;*X!ucVYOu zUHv5v&+H`dc|V`i_i)%Rdl@-T3+C)!F`>&chtpU0u>IFE$6_4%EAWxrQjl8RDkXh| z{mGR6y2&Q1l^wPqVRY;o1s(m3xOsZvW21$(GE#$kG28oG{Y}o6*NdiReLv^=EicR3 zK9yA!r-mUAxNY=frNelV}Hlh-$m><6LjiG49b=5R_D}Yr895q@0qM= zvAR!Ptr%z-i%c?Ct3$4=zwd=ZXf~ni2fisf)IdFb0j zTaK1D+BH?ldr92G4gDJv6z?|yF>d#LNHld0o%<13-XwWSO3AwaM4%qj++S@68bT9zq%JwUaan}Px!Ih81j$C@Ad#P z5e_u}$?RqTvp*}s=r6ARD`CW2dv{+?XZOlgoqc_s-OKv)-+U0=?SqJSc2&sd?Xv#+ zjPXD`4j}8B^^1SR&Dh_&wMI7WyHG+u4(0!J^}o1lCq;J6_hvpkG>!cPJ?7u-#$$s^ z$ELBt3kS!>1_!bmQX}g&r`8SXC(X4PF7TAOH3yPS$)$eUw5eLH+TYdH-E(&5GW_rE zUxk1A8MB4K^9P*1=v%47YNbgXYW$XsqJI z!R55Ovs#}(Cej&tX#dLP-7=SA%m(&QBm1CfI&(^-E!dDC+(ixvna6>cmWMG^=96_K zShMp>kB@E~zBDzCH-oh7%XX%lw%}PUozWB?&nI zG7UKpC6A^jJj9#nSEa(MtQ>^4$m@d~4BAY_dxP-N&ci?sp(vN`Gi4DO<_)Xhc*r(# zhXzA>JUNW?(dcLHR$hkIlw!)^kQl+_?mz_b9w2aO@?ReuGv*N-gJC$*AV-1;&zGb4 zdygwer&M@81WH*}g*}82hIE9Hq zsZiUMkh4s;4wUAExW@xk5Y-8)P7cY9L>#6k^8Dm+-Ys2VDkLqk3>8=c@(n}`Ot8`_`PNv6GBLk@oqa%Ys-Xbe0z*n$f znnB(oXQM?uh8e9w#g#skoY8L1sGmgZDJ|!KJ8jbVDJv)Ef-+H{ySu-qr+@kK{uL|w zdwcs=u9Vem;`os5eAU8nCFg^PrVDZb7;3jGDg3sp2WQkn4OtWPpq{lLVsXGM zXk%(^kO;{D1RFAlk~f5h8*(A4#!|bz%MH$ESqGjgLnyge9KA&@zvc9mVe%ez+bUW@SA%CgzxfwOcljjs}*EVDNaA5ma0mMae^!#|H7y-AROW=F3hek8RmR zalVKyHp=|-HtHD{L!uQOW8}>q%8~{>V?tk%kwH#s=f@ zMbD=%C&T!3(eu_U8OB?So*zCB49^dXt!@_{uwp^TxZMOQuH;aLZkH#~%Z9RRM@KFkUT2<#Wjke<=k0AI$LwvF?0}$pQaz=f zR?igMK&)>o&cRP{E(?<$6`8{n_hYdD1u~PU^0C2n!|Cy{OR@v0@sy{0C#1~Vmm)OZ z|LC1BL_d1xi}2g*oma8N^UkYT^}O>MRA;^O#iXL%c`X^CcV0&-^v(t--#f2oL)1H` z$%uOA3>i`Hya9|D@1!5JQ%juGSHk}O5##gax=)tch#Vop2+`C1}YuFz3= z{P=aKxbk|G^kaUlMDl`scM5r9t`jLqXR1`N9C-sfc+Si{@SU0O8Z9>;c_W+YyKh3p zl{cddefKRSBL3m|!>ohQlYFP~@I32QhleTqTdAN4+HV6VfHr5>0_~f?YPHAP$%~vu z?*Kjh|H1n^(UEw67k-=ZeluG;Xyfp=Q^rW(9OlG@%JrQ=+;EaR@EJOJ@mLaf(lU~A`7-7BI?5x9ABE*B;5^GBy#;<1LRjF}@Z-wY zQF4I{F)a)9{|Z390TC|mUW%H?RIN?zl>0!Mi$?fCOuk7LKgwvyDqJ3LE0+7gvx7bO z7Kox5Pje6S>>h*x@7o-Miy9XzcLiQK?X_q+X8uv1XTpN zj{Grbo`SXi1R})CpFyajLN7bZM3+jvmPBTdJT2*cB|rr! zc+z~f=#=^F-UN<)soDp}eyF>$0A&;$`-2W9nxJ&E_xlqKt+@~)tq1x6;Dr`FkYjij zJqXoiiyjP)Z_z_27q#djws{sklvU57hoQPxiyBm!KP8gGIh=3JBT#qcNR&})9z{CV znn$y*Z_Q&&-(&s0fi;f<-Q?cKgAuy-2_RbR%PGXz_e74f1olmpcO{z+kI=f2d@O};r#M%|UgD5K^)h4ieiF9F%&>!*Sh`tNBVS}g8QJ+%1g93ryQ?Vv+zFJ*tv z+Gn8JZ0$3_@vVIp<)YT^V4G*{PF6i@ccHpBYlk|QaV(}Q<~6_=y&>IT@)RK7%bSe6 z_X_9#v4eSD?SY^%rT<3{vYZU_wCm^p-ZSh9vbp(b|6`=|f@2Pt5q0&5-@`xG&B!am z9>HmUb~tp9W*Na%fuNs8Inu|Wk%IK|cb+Tf;Mcp@Y{G{=yXMHb;KV*f28o{$OUP=- zHRL>$#%A8%Mauc?trj%o0#u5e*0kzrNQxBKKdowbSVP6^SLD02BWq3bwGA1dF!x|u z-Hw+uQk?d5k*Ox$(@@7BEHPE`|IE^?bsgoX9@)e^^CH;v9&TiYC__EVZvSjOY<{%-*Nw?PA`E;jwd*>3e z1X3f7vG&mPmBnxCm0nsi)ytY?o)pEzgEoSd^aTP;>H z&?1?pdQhE{ImYAF@=Enj_m&`J@kuheM*6hhD?H)&5 ztkRwmIW*}^WJ{I&Silvt%WC%2^nAQ`yOgVwu03s*Mfxl;dwR{D;cL{9{rNGh@yy7V z1sV;QV)m?>J-h0r=BdT(ax*WrG?Q&uZl;nQx96B8sYRLn{wkDmt~n*OBr_&Xw&G;U zle8i1dfs$uaVE4iAzIwR!e} z7L2Si3jwhUJ=@-HR+za4@LHWd9eN61>BB4IhM>AA3LF8N`g>yb;#vA*c1_K8xMsPz z$i(p<@^rSRm*8!|^x;BXyVk6MTpdETDF@bM{UizPO3jyk$h=9X1COAw~9JhKHx~Xl!32Q(Bs<6BB2zh zWEZ)IN;{p3Dd(;ez`&81y}V|xP`R_Y9K6o8S4K+ES9U82pCe|ks@bd4$3gNuf`m;( zzO)}*F}t;9x2e7mQGk&dNqZs(1(I%4=47y{nC-3EYxI4k?1W>tPZ?;SPgUo-Ccvj_ z`)8Xnnd}=<4ZAUWZO!h`C6_01iqwI~B?rO`?d%!JLhCzgc2Gw-2P;k~=h~rZb8*e? zQdc(lT+S)k-Lr|XC-3G*^TmASP|Ob3Y!ZICC=+O1#TYSH0*@O&4Gl~0Oqt74XCN9+ zOd>*!7M&*lwR;AQx@F$=MbL?^GrIxm4e+81;l>R*(%!V`C)}@ZhU*RKm=FF^E?X>@ z9Q&9^yFJ$Q!WnM#?BnR9>*x@f^m&In1XD-tMXo)47T(_1Kd`lTcqFrHxc8dg;o;t%%s^srdn&QL*E;EAR6M&k zeQE<|UvFY~WNU9?B$FB*u;bciDwWCZwQIZ9U)s42e_h?1@z0v{nT_N6dwMfFhf>Mj z%(m2Ua%kA*cg)o=6(-MYwE}0!B8}#pV)l?N>{ymwiWv^;xBI5jr!`EyEtMP@+Sz|Y zVx)g)Flmd5w$lDJ*`k}Z6FNt@&cr}6k=d3Q?y)7j{gkFjb|o{(-r+sH!?v702R)OB z8Wl&nIwz~6$a9@;6^>sj@6UE`+R$YutJTpN-?A!@52bhzcjH(LGk}#Qr*T^WQ_=1) zj8x540Lp&P9`J$ErW!{0gP|ud-&iMHvNKW4XI*>HtV~1DIrb1_VP*{6>G4yC#mAe| zUFaVySK`??(o-=MF5VHpw(3^mt)hpK@d;e!@fccPz4bJ%-{RRPYFxk7Aco)8ZZ=LC zMCK=%%^GH&Y%ZHNh>=e*S56tky{DSQv_Vv>nVxBbxb!sRhodReKWz|Lrp>^VL8y4T z@x#M2%5|V?mwcXQpHEHS zLYI62oFi-CEH7+wmKU`f$LuxZ#u$RO(Q$@*xA!MUhOf``Bt{aMU5SxC`{MK}=&SAK zzM-AH-r7!oKe#qPafdkLdAA~mI+)Ja+LxHZjyY!Elqs5tripzhX0{CtUemwbpZKL3 zFpe~_zt*+(WromZMh-!bNbFDW^7QgqBtukRYhPi?MxouBU|*@;oK%IzgAm^xPli5W zU)2QiSEuLUP1$koZ(h@c@7F56U+3A^`&w`FHxJ=FofCV@ojJ$8!K^ebsD9(rjK94} zN7dgR_vNy0CR({Q-9MT!qnV21Rx(-p76t6>o_(tV_H6|0+e5&1His30PMR1 zz`iE{?0W;izApgm`vbs!AOP$K1HgXhXaW1-X25>L2W);~vgp{4MgsO@3fPZ(_7hay z?F8&6L%@Ej39z4T0xTdF3n8`=$_WE%5TC*wTVsN>pHZiu(cx!_sv}|JbBf#%XdAn! z_@2B}s)#UkkRQCmi3)on>KfD+0xmyZj1d& z01ZMsO!)Pk+*hMAVNZE%pCdb&B}>SbcOt;v<=L+(8or)hjCqsgWWO7^D@uT4 zL>XfCzMB1>LIrXfB+qbLWWTRL_Xoh@a&tF!I!OC>12dOn4@7Ag9Wnc0gere(?!JjP8DB+RR|ZoO zJ>uEFs%8Gh2=(_cLj5C%Q2z`f)W3oV_3t1;{U?Y}{|zG4|NICgbLPU;HLJ>8RyDE8 zF|2BCm19vo%4j9Wfww7O$vjY6wlXrGG#+s1G_rs#sz?{!B@5Z+HAQfKkmDn!h>;fM z+HwMV%!8|MlSQa_vKS?`B`0!3fKE9{`xhzN9Bl5b$*CkWD>k^OoCe~wxvwUtqe5>hPylr}zotGXXMpI*nJ87_v&eJ5Cub|+ z0rQ|yH!(B5@d(flKPYgibcF)NfH%l;4ymu~9JF+Q+tt;*etq|b4c(Vq(!FtG_ohv9 zF1u(7#v?h8tx!jCHdmjIlLiVlqjElobP8FCiYIL-=^Br~HMn;sfV(;g;m%yi z?Np;*z#*-9iDL0uEWCq~ z)qKf`kn18;Jh>Pp<>K9ktU)8{`XjhsaHWHTH$_FUVE&kNf~6*FQPQM3Anre4f^{Ib zH)Lz+0-?Ym5NJIfo@^isg}DS3jWuDI4Wy8b%D0Jpx-{ZgIddfZbzE zHiN4sTTrTvd7mKNXmO7%myyiN7VOz4%TjT0TIa>1TuzRtg$Hvp7y0vF0nVCS$%*Rj zd=*;U+soA?x9krk5%z9HMLmH_^gTgqD+)9gZnna0N0IyBZJ-Sj*gdGUsG=970#^#X zUW11x+sR~B6sTpYw+~M}d4=i?7Si97(b@aaKg)V?n zCo2;NWdKdx5ixY>wpMn6d3tQC<9w55V8=q)oOdl*ak5Yr9<(7e5rb{elR?cM{=rG z;=70AxJ4+H9FgnDUB^S3ErxejH?49#+VoT<={Z4e04em0$Dr=XV^OMS+{iB93m!*W zL4mL4u1SWSbv)n1mSR_RT9YgZbvTZ)RfpdgT1SRop^mp4_*(GhaH0Tjdr|jfoJ_zQ zWhdSYIS3JjO9X84954f$0-7zb*+&v1F_0uhHW=B$Q=v?R-4ms8DWP#Bh?UV7LTnOs zPb|ttVTBw-grXw?B`*4!P*MRQ3MExC@lTbAIwRgcsA$xsKz0k#@Ya1d<* zgZD{RodHc(7)zzis+(QE<5(@EkzqLqxvmU2Zn+cQ8r zlJTF3zR>v3Lfw;RqihuFIpmnl_|FAHlkuMiLX`2JPsVd0TT^&&Q~aa)^ePpzg^_Q7Rf<#x5TXFDI=D4X|e%2Fgw}ypbHUq2WznfEuFG#+x}d zNE>fK-ILo6J2<><+jp|nV#aszz5Y(E_0yod8+~ReQsH}0@#MWIu_k}F_C7Sy zXG5?s4+bBr8b7wl`@s~I3LCyFGL?Ve(b>Y!H}XO7*5pGd85sEjq)&ZdFY;kD)i;9s z5BUfPQ3Ck7+U6(O25DmQQH;QfKZb`VA4jQ({sb!NlN(l>8^fm^-Pg${mGx6(RhF4A z7s0iGE1yPZ4n%v3B2s(b8 zmb;ELLz4}LoxL&nnhyVZIGlT5xf`u1O@uZ1M%bg<=5L~<+vabfqG5rSFy~DH5Uk;r zf(ILZ0+Mf|U7+sZ@I(+Sd=DO;+>25z{2f;G0yqS8PA{MILlkymp}E7$75T1?zYk?o zH2xk4M{A#$d>`Cy`l3c)HNUmNo$7D?fxh{Nt#AGj2nE8|t(u3zjU{=pW;$?iG9|M0 zWJ=9KM>LY^=*MUmXe|&;xx7z__mfBvaI60lJdcR+2gpevL$?p&;mJ?Q&d~Z0Dtf;Y zs#ZUm%frg`Gjgd4or7b=YR-|LgA$23^_Kn~|D^K^aMk3OD0OhY2Nv#SVqRhsa z2N5EEEL5m=1QK)}nkdRY*%!vDf3d+^i7*=fo5Sh0_(D(}b+KIb2EP-L|FB~j(DPqZ zJoz6=Kijm8xxr6L!ryFkj^Yz(Ec}6q%)tf~eRf^YQC701%6{9U&2fa$vhv9gDaBM zLjD9qCp;eHX)J`hW`(CKF_6sZkmm$cJXwUYo;4Svq2C4To}j-73VuZ*C!#wlcm%+Y z$w^>PC#%U4RG9)f1`$smfZS3vn;>^`I0O=%g1RTmP^w>^$}ZmvPa{o17&_1C>}>R= zGe~IkoijnG`%WR+Tc`uyTMA8{aTe%JcQI#!5dPf2_vGaqN=Js^=b-M%xf}!+L2%_lFzCTE%CJleMI2@|!B$0ZL8Qv9mF;c9B58o-X(~cs&W4`wMCUz%U+&_;r2eTIoto78v6y)IGTxrK%voF5ehiNoz93Hg+}|qlbh>WAu{HXpCz> zI7(w|2P>}IP^u*ToXR)GwX7bcF}R*bHO3CUq#pbS&}z}pPLk@@7-Xx_8bctoT4U9W tH6ATD?ZR;XAXA;Wt8_KN?nakc0BU%Ztkhvr7n3(|a-}9oJ+nI6`G0bIu6+Oi diff --git a/tools/hilbert.py b/tools/hilbert.py index 828705c..14c65d1 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -645,15 +645,13 @@ def _version(): import ruamel.yaml as yaml import semantic_version - __version__ = '0.2.2-dev' # TODO: add git commit id? - log.debug("Running '{}'".format('version')) log.debug("Python version: {}".format(platform.python_version())) log.debug("ruamel.yaml version: {}".format(yaml.__version__)) log.debug("dill version: {}".format(dill.__version__)) log.debug("semantic_version version: {}".format(semantic_version.__version__)) - log.info("Hilbert version: {}".format(__version__)) # TODO: this version?! + log.info("Hilbert Config API {}".format(Hilbert(None).get_api_version())) log.debug("Done") From f73ea7622f9c7e259b1d236d51de538a5b7524f0 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Fri, 25 Nov 2016 05:13:51 +0100 Subject: [PATCH 29/42] Enable using **previously checked** dump to check _compatible__ parsing result --- config/hilbert_cli_config.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index 0203f8a..a839dca 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -277,7 +277,7 @@ def __eq__(self, other): assert isinstance(other, Base) - assert self.get_api_version() == other.get_api_version() # Same /config/hilbert_cli_config.py should be used! +# assert self.get_api_version() == other.get_api_version() return self.get_data() == other.get_data() def __ne__(self, other): From 51ade4cc22a65ab86736049d6580522d1e23ba67 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Sat, 26 Nov 2016 05:39:30 +0100 Subject: [PATCH 30/42] Big internal changes to Validators to improve API + corrected tests due to API changes. Also: CLI changes due to https://github.com/hilbert/hilbert-cli/pull/34#issuecomment-262963376 --- config/hilbert_cli_config.py | 904 +++++++++++++++-------------- config/subcmdparser.py | 23 +- tests/data/Hilbert.yml.data.pickle | Bin 10833 -> 3379 bytes tests/test_validate.py | 20 +- tests/test_version.py | 66 ++- tools/hilbert.py | 243 ++++---- 6 files changed, 648 insertions(+), 608 deletions(-) diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index a839dca..cf8c8f7 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -4,32 +4,90 @@ from __future__ import absolute_import, print_function, unicode_literals +############################################################### +import ruamel.yaml as yaml +from ruamel.yaml.reader import Reader +from ruamel.yaml.scanner import RoundTripScanner # Scanner +from ruamel.yaml.parser import RoundTripParser # Parser, +from ruamel.yaml.composer import Composer +from ruamel.yaml.constructor import RoundTripConstructor # Constructor, SafeConstructor, +from ruamel.yaml.resolver import VersionedResolver # Resolver, +# from ruamel.yaml.nodes import MappingNode +from ruamel.yaml.compat import PY2, PY3, text_type, string_types, ordereddict + +import semantic_version # supports partial versions + import logging -log = logging.getLogger(__name__) +import collections +import sys +import os +import re, tokenize +import tempfile -# from .helpers import load_yaml, pprint +import pprint as PP +from abc import * ############################################################### -import pprint as PP +log = logging.getLogger(__name__) _pp = PP.PrettyPrinter(indent=4) -def pprint(cfg): -# print("## Validated/Parsed pretty Result: ") - global _pp - _pp.pprint(cfg) # TODO: use loggger? -# PP.pformat +############################################################### +# NOTE: Global variables +PEDANTIC = False # NOTE: to treat invalid values/keys as errors? +INPUT_DIRNAME = './' # NOTE: base location for external resources ############################################################### -# NOTE: Global variuables -PEDANTIC = False # NOTE: to treat invalid values/keys as errors? -INPUT_DIRNAME = './' -# OUTPUT_DIRNAME = INPUT_DIRNAME +if PY3 and (sys.version_info[1] >= 4): + class AbstractValidator(ABC): + """AbstractValidator is the root Base class for any concrete implementation of entities + appearing in the general configuration file""" + @abstractmethod + def validate(self, d): + pass +elif PY2 or PY3: + class AbstractValidator: + """AbstractValidator is the root Base class for any concrete implementation of entities + appearing in the general configuration file""" + __metaclass__ = ABCMeta + + @abstractmethod + def validate(self, d): + pass +# elif PY3: +# class AbstractValidator(metaclass=ABCMeta): +# """AbstractValidator is the root Base class for any concrete implementation of entities +# appearing in the general configuration file""" +# @abstractmethod +# def validate(self, d): +# pass +else: + raise NotImplementedError("Unsupported Python version: '{}'".format(sys.version_info)) ############################################################### -up_arrow = '↑' +if PY3: + from urllib.parse import urlparse + from urllib.request import urlopen +elif PY2: + from urlparse import urlparse + from urllib2 import urlopen +############################################################### +if PY3: + def is_valid_id(k): + return k.isidentifier() +elif PY2: + def is_valid_id(k): + return re.match(tokenize.Name + '$', k) + +############################################################### +def pprint(cfg): + global _pp + _pp.pprint(cfg) + + +############################################################### def _get_line_col(lc): if isinstance(lc, (list, tuple)): @@ -59,6 +117,11 @@ class ConfigurationError(Exception): def __init__(self, msg): self._msg = msg + +############################################################### +_up_arrow = '↑' + + def _key_error(key, value, lc, error_message, e='K'): (line, col) = _get_line_col(lc) @@ -66,9 +129,9 @@ def _key_error(key, value, lc, error_message, e='K'): key = '*' print('{}[line: {}, column: {}]: {}'.format(e, line + 1, col + 1, error_message.format(key))) - print('{}{}: {}'.format(' ' * col, key, value)) #! + print('{}{}: {}'.format(' ' * col, key, value)) # NOTE: !? # ! TODO: try to get access to original ruamel.yaml buffered lines...? - print('{}{}'.format(' ' * col, up_arrow)) + print('{}{}'.format(' ' * col, _up_arrow)) print('---') @@ -90,9 +153,9 @@ def _value_error(key, value, lc, error, e='E'): val_col = col + len(key) + 2 print('{}[line: {}, column: {}]: {}'.format(e, line + 1, val_col + 1, error.format(key))) - print('{}{}: {}'.format(' ' * col, key, value)) #! + print('{}{}: {}'.format(' ' * col, key, value)) # NOTE: !? # ! TODO: try to get access to original ruamel.yaml buffered lines...? - print('{}{}'.format(' ' * val_col, up_arrow)) + print('{}{}'.format(' ' * val_col, _up_arrow)) print('---') # Unused??? @@ -100,19 +163,6 @@ def _value_error(key, value, lc, error, e='E'): # _value_error(key, value, lc, error, e='W') -############################################################### -import collections -import ruamel.yaml as yaml - -from ruamel.yaml.reader import Reader -from ruamel.yaml.scanner import RoundTripScanner # Scanner -from ruamel.yaml.parser import RoundTripParser # Parser, -from ruamel.yaml.composer import Composer -from ruamel.yaml.constructor import RoundTripConstructor # Constructor, SafeConstructor, -from ruamel.yaml.resolver import VersionedResolver # Resolver, -# from ruamel.yaml.nodes import MappingNode - - ############################################################### class VerboseRoundTripConstructor(RoundTripConstructor): def construct_mapping(self, node, maptyp, deep=False): @@ -159,63 +209,49 @@ def __init__(self, stream, version=None, preserve_quotes=None): VerboseRoundTripConstructor.__init__(self, preserve_quotes=preserve_quotes) VersionedResolver.__init__(self, version) - -############################################################### -from ruamel.yaml.compat import PY2, PY3, text_type, string_types, ordereddict -from abc import * -import sys - -if PY3 and (sys.version_info[1] >= 4): - class AbstractValidator(ABC): - """AbstractValidator is the root Base class for any concrete implementation of entities - appearing in the general configuration file""" - - @abstractmethod - def validate(self, d): # TODO: FIXME: change API: return parsed value, throw exception if input is invalid! - pass -elif PY2 or PY3: - class AbstractValidator: - """AbstractValidator is the root Base class for any concrete implementation of entities - appearing in the general configuration file""" - __metaclass__ = ABCMeta - - @abstractmethod - def validate(self, d): - pass -# elif PY3: -# class AbstractValidator(metaclass=ABCMeta): -# """AbstractValidator is the root Base class for any concrete implementation of entities -# appearing in the general configuration file""" -# @abstractmethod -# def validate(self, d): -# pass -else: - raise NotImplementedError("Unsupported Python version: '{}'".format(sys.version_info)) - ############################################################### -class Base(AbstractValidator): +class BaseValidator(AbstractValidator): """Abstract Base Class for the Config entities""" - __version = [None] - - _parent = None + __version = [None] # NOTE: shared version among all Validator Classes! + _parent = None # NOTE: (for later) parent Validator + _data = None # NOTE: result of valid validation + _default_input_data = None # NOTE: Default input to the parser instead of None - _data = None - _default_data = None + def __init__(self, *args, **kwargs): + parent = kwargs.pop('parent', None) + parsed_result_is_data = kwargs.pop('parsed_result_is_data', False) - def get_parent(self): - return self._parent + # TODO: FIXME: assure *args, **kwargs are empty! + super(BaseValidator, self).__init__() - def __init__(self, parent): # TODO: add tag? here or in some child? - AbstractValidator.__init__(self) assert self._parent is None self._parent = parent + + # parsed_result_is_data default: + # - False => parsed result is self + # - True => get_data() + self._parsed_result_is_data = parsed_result_is_data + self.__API_VERSION_ID = "$Id$" + def get_parent(self): + return self._parent + def get_api_version(self): return self.__API_VERSION_ID - + + def set_data(self, d): + # assert self._data is None + # assert d is not None + self._data = d + + def get_data(self): + _d = self._data +# assert _d is not None + return _d + @classmethod def set_version(cls, v): """To be set once only for any Validator class!""" @@ -232,36 +268,35 @@ def get_version(cls, default=None): return default - def set_data(self, d): - # assert self._data is None - # assert d is not None - self._data = d - - def get_data(self): - _d = self._data - if _d is None: - _d = self._default_data - - return _d + @abstractmethod + def validate(self, d): # abstract... + pass @classmethod - def parse(cls, d, parent=None): - self = cls(parent) + def parse(cls, d, *args, **kwargs): + """ + return parsed value, throw exception if input is invalid! - if d is None: - d = self._default_data + :param d: + :param parent: + :return: + """ + self = cls(*args, **kwargs) - if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! - return self # .get_data() + if self.validate(d): # NOTE: validate should not **explicitly** throw exceptions!!! + if self._parsed_result_is_data: + return self.get_data() - # NOTE: .parse should! - raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) + return self + + # NOTE: .parse should throw exceptions in case of invalid input data! + raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{0}' in {1}!" .format(d, type(self)))) def __repr__(self): """Print using pretty formatter""" d = self.get_data() # vars(self) # ??? - return PP.pformat(d, indent=4, width=1) + return PP.pformat(d, indent=4, width=100) # def __str__(self): # """Convert to string""" @@ -270,12 +305,12 @@ def __repr__(self): # return str(d) def __eq__(self, other): - assert isinstance(self, Base) + assert isinstance(self, BaseValidator) -# if not isinstance(other, Base): -# return self.get_data() == other + if not isinstance(other, BaseValidator): + return self.data_dump() == other - assert isinstance(other, Base) + assert isinstance(other, BaseValidator) # assert self.get_api_version() == other.get_api_version() return self.get_data() == other.get_data() @@ -295,7 +330,7 @@ def data_dump(self): _dd = {} for k in _d: v = _d[k] - if isinstance(v, Base): + if isinstance(v, BaseValidator): v = v.data_dump() _dd[k] = v return _dd @@ -304,7 +339,7 @@ def data_dump(self): _dd = [] for idx, i in enumerate(_d): v = i - if isinstance(v, Base): + if isinstance(v, BaseValidator): v = v.data_dump() _dd.insert(idx, v) return _dd @@ -312,28 +347,38 @@ def data_dump(self): # if isinstance(_d, string_types): return _d - def query(self, what): - """Generic query for data subset about this object""" + """ + Generic query for data subset about this object + + A/B/C/(all|keys|data)? + + Get object under A/B/C and return + * it (if 'all') - default! + * its keys (if 'keys') + * its data dump (if 'data') + """ # NOTE: no data dumping here! Result may be a validator! log.debug("Querying '%s'", what) - if (what is None) or (what == ''): what = 'all' if what == 'all': return self + if what == 'data': + return self.data_dump() + _d = self.get_data() if what == 'keys': assert isinstance(_d, dict) - return _d.keys() + return [k for k in _d.keys()] - s = BaseString.parse(what, parent=self) + s = StringValidator.parse(what, parent=self) if s in _d: return _d[s] @@ -346,7 +391,7 @@ def query(self, what): if h in _d: d = _d[ss[0]] - if isinstance(d, Base): + if isinstance(d, BaseValidator): return d.query(t) # TODO: FIXME: avoid recursion... log.warning("Could not query an object. Ignoring the tail: %s", t) @@ -357,13 +402,14 @@ def query(self, what): ############################################################### -class BaseRecord(Base): - """Aggregation of data as a record with some fixed data memebers""" +class BaseRecordValidator(BaseValidator): + """Aggregation of data as a record with some fixed data members""" # TODO: turn _default_type into a class-member (by moving it here)...? - def __init__(self, parent): - Base.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(BaseRecordValidator, self).__init__(*args, **kwargs) + self._default_type = None # "default_base" self._types = {} self._create_optional = False # Instantiate missing optional keys @@ -383,6 +429,9 @@ def detect_extra_rule(self, key, value): return None def validate(self, d): + if d is None: + d = self._default_input_data + # ! TODO: assert that d is a mapping with lc! self._type = self.detect_type(d) @@ -408,7 +457,7 @@ def validate(self, d): _k = None _v = None try: - _k = BaseString.parse(k, parent=self) + _k = StringValidator.parse(k, parent=self) except ConfigurationError as err: _key_note(k, _lc, "Error: invalid _optional_ key field '{}' (type: '%s')" % self._type) pprint(err) @@ -437,7 +486,7 @@ def validate(self, d): if k in _rule: try: - _k = BaseString.parse(k, parent=self) + _k = StringValidator.parse(k, parent=self) except ConfigurationError as err: _key_error(k, v, lc, "Error: invalid key field '{}' (type: '%s')" % self._type) pprint(err) @@ -483,15 +532,19 @@ def validate(self, d): ############################################################### -class BaseScalar(Base): +class ScalarValidator(BaseValidator): """Single scalar value out of YAML scalars: strings, numbert etc.""" - def __init__(self, parent): - Base.__init__(self, parent) + def __init__(self, *args, **kwargs): + kwargs['parsed_result_is_data'] = kwargs.pop('parsed_result_is_data', True) + super(ScalarValidator, self).__init__(*args, **kwargs) def validate(self, d): """check that data is a scalar: not a sequence or mapping or set""" + if d is None: + d = self._default_input_data # ! + if d is not None: if isinstance(d, (list, dict, tuple, set)): # ! Check if data is not a container? print("ERROR: value: '{}' is not a scalar value!!" . format(d)) @@ -504,33 +557,23 @@ def validate(self, d): self.set_data(d) return True - @classmethod - def parse(cls, d, parent=None): - self = cls(parent) - - if d is None: - d = self._default_data - - if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! - return self.get_data() - - # NOTE: .parse should! - raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) - - ############################################################### -class BaseString(BaseScalar): +class StringValidator(ScalarValidator): """YAML String""" - def __init__(self, parent): - BaseScalar.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(StringValidator, self).__init__(*args, **kwargs) + self._default_data = '' def validate(self, d): """check whether data is a valid string. Note: should not care about format version""" + if d is None: + d = self._default_data + assert d is not None - s = BaseScalar.parse(d, parent=self) + s = ScalarValidator.parse(d, parent=self) if not isinstance(s, string_types): print("ERROR: value: '{}' is not a string!!" . format(d)) @@ -541,77 +584,81 @@ def validate(self, d): ############################################################### -# import semver -import semantic_version # supports partial versions - - -class SemanticVersion(BaseString): - def __init__(self, parent, partial=False): - BaseString.__init__(self, parent) +class SemanticVersionValidator(BaseValidator): + def __init__(self, *args, **kwargs): + partial = kwargs.pop('partial', False) +# kwargs['parsed_result_is_data'] = kwargs.pop('parsed_result_is_data', False) + super(SemanticVersionValidator, self).__init__(*args, **kwargs) +# self._parsed_result_is_data = False self._partial = partial def validate(self, d): - """check the string data to be a valid semantic verions""" + """check the string data to be a valid semantic version""" + + if d is None: + d = self._default_input_data - _t = BaseString.parse(d, parent=self) + _t = StringValidator.parse(d, parent=self, parsed_result_is_data=True) # self.get_version(None) # ??? _v = None try: _v = semantic_version.Version(_t, partial=self._partial) except: - print("ERROR: wrong version data: '{0}' (see: '{1}')" . format(d, sys.exc_info())) + log.exception("Wrong version data: '{0}' (see: '{1}')" . format(d, sys.exc_info())) return False self.set_data(_v) return True - @classmethod - def parse(cls, d, parent=None, partial=False): - self = cls(parent, partial=partial) - - assert d is not None -# d = self._default_data - - if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! - return self # keep the validator to handle some general actions via its API: e.g. data_dump - - # NOTE: .parse should! - raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) - def data_dump(self): return str(self.get_data()) + ############################################################### -class BaseUIString(BaseString): # visible to user => non empty! - def __init__(self, parent): - BaseString.__init__(self, parent) +class BaseUIString(StringValidator): + """String visible to users => non empty!""" + + def __init__(self, *args, **kwargs): + super(BaseUIString, self).__init__(*args, **kwargs) + self._default_data = None def validate(self, d): - """check whether data is a valid string""" - t = BaseString.parse(d, parent=self) + """check whether data is a valid (non-empty) string""" + + if d is None: + d = self._default_data - if bool(t): # Non-empty - self.set_data(t) + if not super(BaseUIString, self).validate(d): + self.set_data(None) + return False + + if bool(self.get_data()): # NOTE: Displayed string should not be empty! return True + self.set_data(None) return False ############################################################### -class BaseEnum(BaseString): # TODO: Generalize to not only strings...? +class BaseEnum(BaseValidator): # TODO: Generalize to not only strings...? """Enumeration/collection of several fixed strings""" - def __init__(self, parent): - BaseString.__init__(self, parent) + def __init__(self, *args, **kwargs): + kwargs['parsed_result_is_data'] = kwargs.pop('parsed_result_is_data', True) + super(BaseEnum, self).__init__(*args, **kwargs) + self._enum_list = [] # NOTE: will depend on the version... def validate(self, d): """check whether data is in the list of fixed strings (see ._enum_list)""" - t = BaseString.parse(d, parent=self) + if d is None: + d = self._default_input_data + + t = StringValidator.parse(d, parent=self, parsed_result_is_data=True) if not (t in self._enum_list): # check withing a list of possible string values print("ERROR: string value: '{}' is not among known enum items!!".format(d)) @@ -623,8 +670,8 @@ def validate(self, d): ############################################################### class ServiceType(BaseEnum): # Q: Is 'Service::type' mandatory? default: 'compose' - def __init__(self, parent): - BaseEnum.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(ServiceType, self).__init__(*args, **kwargs) compose = text_type('compose') self._enum_list = [compose] # NOTE: 'docker' and others may be possible later on @@ -633,8 +680,8 @@ def __init__(self, parent): ############################################################### class StationOMDTag(BaseEnum): # Q: Is 'Station::omd_tag' mandatory? default: 'standalone' - def __init__(self, parent): - BaseEnum.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(StationOMDTag, self).__init__(*args, **kwargs) _v = text_type('standalone') self._enum_list = [text_type('agent'), text_type('windows'), _v] # NOTE: possible values of omd_tag @@ -643,8 +690,9 @@ def __init__(self, parent): ############################################################### class StationPowerOnMethodType(BaseEnum): # Enum: [WOL], AMTvPRO, DockerMachine - def __init__(self, parent): - BaseEnum.__init__(self, parent) + + def __init__(self, *args, **kwargs): + super(StationPowerOnMethodType, self).__init__(*args, **kwargs) wol = text_type('WOL') # NOTE: the list of possible values of PowerOnMethod::type (will depend on format version) @@ -653,30 +701,25 @@ def __init__(self, parent): ############################################################### -import os - -if PY3: - from urllib.parse import urlparse - from urllib.request import urlopen -elif PY2: - from urlparse import urlparse - from urllib2 import urlopen - - -class URI(BaseString): +class URI(BaseValidator): """Location of external file, either URL or local absolute or local relative to the input config file""" - def __init__(self, parent): - BaseString.__init__(self, parent) + def __init__(self, *args, **kwargs): + kwargs['parsed_result_is_data'] = kwargs.pop('parsed_result_is_data', True) + super(URI, self).__init__(*args, **kwargs) + self._type = None def validate(self, d): """check whether data is a valid URI""" + if d is None: + d = self._default_input_data - v = BaseString.parse(d, parent=self) + v = StringValidator.parse(d, parent=self, parsed_result_is_data=True) _ret = True + # TODO: @classmethod def check_uri(v) if urlparse(v).scheme != '': self._type = text_type('url') try: @@ -704,42 +747,20 @@ def validate(self, d): return _ret - ## TODO: @classmethod check_uri() - - @classmethod - def parse(cls, d, parent=None): - self = cls(parent) - - if d is None: - d = self._default_data - - if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! - return self.get_data() # TODO: due to DockerComposeFile later on :-( - - # NOTE: .parse should! - raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) - -############################################################### -import re, tokenize - -if PY3: - def is_valid_id(k): - return k.isidentifier() -elif PY2: - def is_valid_id(k): - return re.match(tokenize.Name + '$', k) -else: - raise NotImplementedError("Unsupported Python version: '{}'".format(sys.version_info)) ############################################################### -class BaseID(BaseString): - def __init__(self, parent): - BaseString.__init__(self, parent) +class BaseID(BaseValidator): + def __init__(self, *args, **kwargs): + kwargs['parsed_result_is_data'] = kwargs.pop('parsed_result_is_data', True) + super(BaseID, self).__init__(*args, **kwargs) def validate(self, d): """check whether data is a valid ID string""" - v = BaseString.parse(d, parent=self) + if d is None: + d = self._default_input_data + + v = StringValidator.parse(d, parent=self, parsed_result_is_data=True) if not is_valid_id(v): print("ERROR: not a valid variable identifier! Input: '{}'" . format(d)) @@ -750,12 +771,15 @@ def validate(self, d): ############################################################### class ClientVariable(BaseID): # - def __init__(self, parent): - BaseID.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(ClientVariable, self).__init__(*args, **kwargs) def validate(self, d): """check whether data is a valid ID string""" + if d is None: + d = self._default_input_data + v = BaseID.parse(d, parent=self) # .get_data() _ret = True @@ -778,58 +802,67 @@ def validate(self, d): ############################################################### class ServiceID(BaseID): - def __init__(self, parent): - BaseID.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(ServiceID, self).__init__(*args, **kwargs) ############################################################### class ApplicationID(BaseID): - def __init__(self, parent): - BaseID.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(ApplicationID, self).__init__(*args, **kwargs) ############################################################### class GroupID(BaseID): - def __init__(self, parent): - BaseID.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(GroupID, self).__init__(*args, **kwargs) ############################################################### class StationID(BaseID): - def __init__(self, parent): - BaseID.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(StationID, self).__init__(*args, **kwargs) ############################################################### class ProfileID(BaseID): - def __init__(self, parent): - BaseID.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(ProfileID, self).__init__(*args, **kwargs) ############################################################### class PresetID(BaseID): - def __init__(self, parent): - BaseID.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(PresetID, self).__init__(*args, **kwargs) ############################################################### -import tempfile - -class AutoDetectionScript(BaseString): - def __init__(self, parent): - BaseString.__init__(self, parent) +class AutoDetectionScript(StringValidator): + def __init__(self, *args, **kwargs): + super(AutoDetectionScript, self).__init__(*args, **kwargs) self._default_data = '' def validate(self, d): """check whether data is a valid script""" + if d is None: + d = self._default_data + if (d is None) or (d == '') or (d == text_type('')): self.set_data(text_type('')) return True - script = BaseString.parse(d, parent=self) + script = '' + try: + script = StringValidator.parse(d, parent=self, parsed_result_is_data=True) + + if not bool(script): # NOTE: empty script is also fine! + self.set_data(script) + return True + except: + log.error("Wrong input to AutoDetectionScript::validate: {}". format(d)) + return False - assert bool(script) # NOTE: trying to check the BASH script: shellcheck & bash -n 'string': fd, path = tempfile.mkstemp() @@ -866,58 +899,74 @@ def validate(self, d): ############################################################### -class DockerComposeServiceName(BaseString): - def __init__(self, parent): - BaseString.__init__(self, parent) +class DockerComposeServiceName(StringValidator): # TODO: any special checks here? + + def __init__(self, *args, **kwargs): + super(DockerComposeServiceName, self).__init__(*args, **kwargs) def validate(self, d): """check whether data is a valid service name in file due to DockerComposeRef""" + if d is None: + d = self._default_data - n = BaseString.parse(d, parent=self) - - self.set_data(n) - return True + try: + n = StringValidator.parse(d, parent=self, parsed_result_is_data=True) + self.set_data(n) + return True + except: + log.error("Wrong input to DockerComposeServiceName::validate: '{}'". format(d)) + return False ############################################################### class DockerComposeRef(URI): - def __init__(self, parent): - URI.__init__(self, parent) + + def __init__(self, *args, **kwargs): + super(DockerComposeRef, self).__init__(*args, **kwargs) + self._default_data = text_type('docker-compose.yml') def validate(self, d): """check whether data is a valid docker-compose file name""" + if d is None: + d = self._default_data # TODO: call docker-compose on the referenced file! Currently in DockerService!? - return URI.validate(self, d) + return super(DockerComposeRef, self).validate(d) ############################################################### class Icon(URI): - def __init__(self, parent): - URI.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(Icon, self).__init__(*args, **kwargs) def validate(self, d): """check whether data is a valid icon file name""" + if d is None: + d = self._default_input_data + # TODO: FIXME: check the file contents (or extention) - return URI.validate(self, d) + return super(Icon, self).validate(d) ############################################################### import subprocess # , shlex # import paramiko -class HostAddress(BaseString): +class HostAddress(StringValidator): """SSH alias""" - def __init__(self, parent): - BaseString.__init__(self, parent) + def __init__(self, *args, **kwargs): + kwargs['parsed_result_is_data'] = kwargs.pop('parsed_result_is_data', False) + super(HostAddress, self).__init__(*args, **kwargs) def validate(self, d): """check whether data is a valid ssh alias?""" + if d is None: + d = self._default_data - _h = BaseString.parse(d, parent=self) + _h = StringValidator.parse(d, parent=self) if not self.check_ssh_alias(_h): if PEDANTIC: @@ -926,6 +975,11 @@ def validate(self, d): self.set_data(_h) return True + def recheck(self): + return self.check_ssh_alias(self.set_data()) + + ## SSH call? + @classmethod def check_ssh_alias(cls, _h): """Check for ssh alias""" @@ -947,30 +1001,20 @@ def check_ssh_alias(cls, _h): return False - @classmethod - def parse(cls, d, parent=None): - self = cls(parent) - - if d is None: - d = self._default_data - - if self.validate(d): # TODO: FIXME: NOTE: validate should not **explicitly** throw exceptions!!! - return self # .get_data() - - # NOTE: .parse should! - raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!" .format(d))) - ############################################################### -class HostMACAddress(BaseString): +class HostMACAddress(StringValidator): """MAC Address of the station""" - def __init__(self, parent): - BaseString.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(HostMACAddress, self).__init__(*args, **kwargs) def validate(self, d): """check whether data is a valid ssh alias?""" - v = BaseString.parse(d, parent=self) + if d is None: + d = self._default_data + + v = StringValidator.parse(d, parent=self) if not re.match("[0-9a-f]{2}([-:])[0-9a-f]{2}(\\1[0-9a-f]{2}){4}$", v.lower()): _value_error(None, d, d.lc, "ERROR: Wrong MAC Address: [{}]") @@ -981,13 +1025,16 @@ def validate(self, d): return True ############################################################### -class BaseBool(BaseScalar): - def __init__(self, parent): - BaseScalar.__init__(self, parent) +class BoolValidator(ScalarValidator): + def __init__(self, *args, **kwargs): + super(BoolValidator, self).__init__(*args, **kwargs) def validate(self, d): """check whether data is a valid string""" + if d is None: + d = self._default_input_data + if not isinstance(d, bool): print("ERROR: not a boolean value: '{}'" . format(d)) return False @@ -996,24 +1043,25 @@ def validate(self, d): return True -class StationVisibility(BaseBool): ## "hidden": True / [False] - def __init__(self, parent): - BaseBool.__init__(self, parent) +class StationVisibility(BoolValidator): ## "hidden": True / [False] + def __init__(self, *args, **kwargs): + super(StationVisibility, self).__init__(*args, **kwargs) self._default_data = False -class AutoTurnon(BaseBool): # Bool, False - def __init__(self, parent): - BaseBool.__init__(self, parent) +class AutoTurnon(BoolValidator): # Bool, False + def __init__(self, *args, **kwargs): + super(AutoTurnon, self).__init__(*args, **kwargs) self._default_data = False # no powering on by default!? ############################################################### -class VariadicRecordWrapper(Base): +class VariadicRecordWrapper(BaseValidator): """VariadicRecordWrapper record. Type is determined by the given 'type' field.""" - def __init__(self, parent): - Base.__init__(self, parent) + def __init__(self, *args, **kwargs): + kwargs['parsed_result_is_data'] = kwargs.pop('parsed_result_is_data', True) + super(VariadicRecordWrapper, self).__init__(*args, **kwargs) self._type_tag = text_type('type') self._type_cls = None @@ -1021,23 +1069,13 @@ def __init__(self, parent): self._default_type = None self._types = {} - # TODO: FIXME: make sure to use this .parse instead of .validate due to substitution in Wrapper objects!!! - - @classmethod - def parse(cls, d, parent=None): - """Will return a Validator of a different class""" - - self = cls(parent) # temporary wrapper object - - if d is None: - d = self._default_data - - if self.validate(d): - return self.get_data() - + # TODO: make sure to use its .parse instead of .validate due to substitution in Wrapper objects! def validate(self, d): """determine the type of variadic data for the format version""" + if d is None: + d = self._default_input_data + _ret = True assert isinstance(d, dict) @@ -1054,7 +1092,12 @@ def validate(self, d): _key_error(self._type_tag, d, _lc, "ERROR: Missing mandatory key `{}`") return False - t = self._type_cls.parse(d[self._type_tag], parent=self.get_parent()) ### ???? + t = None + try: + t = self._type_cls.parse(d[self._type_tag], parent=self.get_parent()) # parsed_result_is_data=True? + except: + log.exception("Wrong type data: {}".format(d[self._type_tag])) + return False if t not in _rule: _lc = d.lc # start of the current mapping @@ -1076,8 +1119,8 @@ def validate(self, d): class StationPowerOnMethodWrapper(VariadicRecordWrapper): """StationPowerOnMethod :: Wrapper""" - def __init__(self, parent): - VariadicRecordWrapper.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(StationPowerOnMethodWrapper, self).__init__(*args, **kwargs) T = StationPowerOnMethodType self._type_cls = T @@ -1091,8 +1134,8 @@ def __init__(self, parent): class ServiceWrapper(VariadicRecordWrapper): """Service :: Wrapper""" - def __init__(self, parent): - VariadicRecordWrapper.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(ServiceWrapper, self).__init__(*args, **kwargs) T = ServiceType self._type_cls = T @@ -1106,23 +1149,23 @@ def __init__(self, parent): class ApplicationWrapper(ServiceWrapper): """Application :: Wrapper""" - def __init__(self, parent): - ServiceWrapper.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(ApplicationWrapper, self).__init__(*args, **kwargs) - T = ServiceType # same for docker-compose Services and Applications! - self._type_cls = T - _dc = {T.parse("compose"): DockerComposeApplication} + t = ServiceType # NOTE: same for docker-compose Services and Applications! + self._type_cls = t + _dc = {t.parse("compose"): DockerComposeApplication} self._default_type = "default_docker_compose_application_wrapper" self._types[self._default_type] = _dc ############################################################### -class DockerMachine(BaseRecord): +class DockerMachine(BaseRecordValidator): """DockerMachine :: StationPowerOnMethod""" - def __init__(self, parent): - BaseRecord.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(DockerMachine, self).__init__(*args, **kwargs) self._type_tag = text_type('type') @@ -1131,7 +1174,7 @@ def __init__(self, parent): DM_rule = { self._type_tag: (True, StationPowerOnMethodType), # Mandatory! text_type('auto_turnon'): (False, AutoTurnon), - text_type('vm_name'): (True, BaseString), + text_type('vm_name'): (True, StringValidator), text_type('vm_host_address'): (True, HostAddress) } @@ -1145,11 +1188,11 @@ def run_action(self, action, action_args): raise NotImplementedError("Running 'docker-machine start' action is not supported yet... Sorry!") -class WOL(BaseRecord): +class WOL(BaseRecordValidator): """WOL :: StationPowerOnMethod""" - def __init__(self, parent): - BaseRecord.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(WOL, self).__init__(*args, **kwargs) self._type_tag = text_type('type') self._default_type = 'WOL' @@ -1170,11 +1213,11 @@ def run_action(self, action, action_args): ############################################################### -class DockerComposeService(BaseRecord): +class DockerComposeService(BaseRecordValidator): """DockerCompose :: Service data type""" - def __init__(self, parent): - BaseRecord.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(DockerComposeService, self).__init__(*args, **kwargs) self._type_tag = text_type('type') self._hook_tag = text_type('auto_detections') @@ -1194,7 +1237,10 @@ def __init__(self, parent): self._create_optional = True def validate(self, d): - if not BaseRecord.validate(self, d): + if d is None: + d = self._default_input_data + + if not BaseRecordValidator.validate(self, d): assert self.get_data() is None return False @@ -1203,11 +1249,11 @@ def validate(self, d): # TODO: remove Validators (BaseString) from strings used as dict keys! _f = _d[self._file_tag] - while isinstance(_f, Base): + while isinstance(_f, BaseValidator): _f = _f.get_data() _n = _d[self._name_tag] - while isinstance(_n, Base): + while isinstance(_n, BaseValidator): _n = _n.get_data() if not os.path.exists(_f): # TODO: FIXME: use URI::check() instead?? @@ -1255,8 +1301,8 @@ def validate(self, d): class DockerComposeApplication(DockerComposeService): """DockerCompose :: Application""" - def __init__(self, parent): - DockerComposeService.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(DockerComposeApplication, self).__init__(*args, **kwargs) _compose_rule = (self._types[self._default_type]).copy() @@ -1272,11 +1318,11 @@ def __init__(self, parent): # TODO: FIXME: add application to compatibleStations! ############################################################### -class Profile(BaseRecord): +class Profile(BaseRecordValidator): """Profile""" - def __init__(self, parent): - BaseRecord.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(Profile, self).__init__(*args, **kwargs) self._default_type = "default_profile" @@ -1294,42 +1340,45 @@ def __init__(self, parent): ############################################################### -class StationSSHOptions(BaseRecord): # optional: "Station::ssh_options" # record: user, port, key, key_ref +class StationSSHOptions(BaseRecordValidator): # optional: "Station::ssh_options" # record: user, port, key, key_ref """StationSSHOptions""" - def __init__(self, parent): - BaseRecord.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(StationSSHOptions, self).__init__(*args, **kwargs) self._default_type = "default_station_ssh_options" default_rule = { - text_type('user'): (False, BaseString), - text_type('key'): (False, BaseString), - text_type('port'): (False, BaseString), + text_type('user'): (False, StringValidator), + text_type('key'): (False, StringValidator), + text_type('port'): (False, StringValidator), # TODO: BaseInt?? http://stackoverflow.com/questions/4187185/how-can-i-check-if-my-python-object-is-a-number text_type('key_ref'): (False, URI), } self._types = {self._default_type: default_rule} - def validate(self, data): + def validate(self, d): """check whether data is a valid ssh connection options""" - _ret = BaseRecord.validate(self, data) + if d is None: + d = self._default_input_data + + _ret = super(StationSSHOptions, self).validate(d) # TODO: Check for ssh connection: Use some Python SSH Wrapper (2/3) return _ret ############################################################### -class Station(BaseRecord): # Wrapper +class Station(BaseRecordValidator): # Wrapper? """Station""" _extends_tag = text_type('extends') _client_settings_tag = text_type('client_settings') - def __init__(self, parent): - BaseRecord.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(Station, self).__init__(*args, **kwargs) self._poweron_tag = text_type('poweron_settings') self._ssh_options_tag = text_type('ssh_options') @@ -1359,12 +1408,10 @@ def is_hidden(self): _d = self.get_data() assert _d is not None - _h = None + _h = _d.get(self._ishidden_tag, None) - if self._ishidden_tag in _d: - _h = _d[self._ishidden_tag] - else: - _h = StationVisibility.parse(None, parent=self) + if _h is None: + _h = StationVisibility.parse(None, parent=self, parsed_result_is_data=True) return _h @@ -1372,14 +1419,7 @@ def get_address(self): _d = self.get_data() assert _d is not None - _h = None - - if self._address_tag in _d: - _h = _d[self._address_tag] - else: - _h = StationVisibility.parse(None, parent=self) - - return _h + return _d.get(self._address_tag, None) def shutdown(self, action_args): ### ssh address subprocess @@ -1452,7 +1492,7 @@ def get_base(self): _b = _d.get(self._extends_tag, None) # StationID (validated...) # if _b is not None: -# if isinstance(_b, Base): +# if isinstance(_b, BaseValidator): # _b = _b.get_data() return _b @@ -1462,9 +1502,10 @@ def extend(delta, base): # delta == self! assert base.get_base() is None # NOTE: at early stage there may be no parent data... - if delta.get_parent().get_data() is not None: - assert delta.get_base() in delta.get_parent().get_data() - assert delta.get_parent().get_data().get(delta.get_base(), None) == base + if delta.get_parent() is not None: + if delta.get_parent().get_data() is not None: + assert delta.get_base() in delta.get_parent().get_data() + assert delta.get_parent().get_data().get(delta.get_base(), None) == base _d = delta.get_data() _b = base.get_data() @@ -1482,7 +1523,7 @@ def extend(delta, base): # delta == self! if bb is not None: dd = _d.get(k, None) if dd is None: - dd = StationClientSettings.parse(None, parent=delta.get_parent()) + dd = StationClientSettings.parse(None, parent=delta) assert isinstance(dd, StationClientSettings) assert isinstance(bb, StationClientSettings) @@ -1504,11 +1545,12 @@ def extend(delta, base): # delta == self! ############################################################### -class BaseIDMap(Base): +class BaseIDMap(BaseValidator): """Mapping: SomeTypeID -> AnyType""" - def __init__(self, parent): - Base.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(BaseIDMap, self).__init__(*args, **kwargs) + self._default_type = None self._types = {} # type -> (TypeID, Type) @@ -1521,6 +1563,9 @@ def detect_type(self, d): return self._default_type def validate(self, d): + if d is None: + d = self._default_input_data + assert isinstance(d, dict) self._type = self.detect_type(d) @@ -1572,8 +1617,9 @@ def validate(self, d): ############################################################### class GlobalServices(BaseIDMap): - def __init__(self, parent): - BaseIDMap.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(GlobalServices, self).__init__(*args, **kwargs) + self._default_type = "default_global_services" self._types = {self._default_type: (ServiceID, ServiceWrapper)} @@ -1586,11 +1632,12 @@ def __init__(self, parent): ############################################################### # "client_settings": (False, StationClientSettings) # IDMap : (BaseID, BaseString) class StationClientSettings(BaseIDMap): - def __init__(self, parent): - BaseIDMap.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(StationClientSettings, self).__init__(*args, **kwargs) + self._default_type = "default_station_client_settings" self._types = { - self._default_type: (ClientVariable, BaseScalar) + self._default_type: (ClientVariable, ScalarValidator) } # ! TODO: only strings for now! More scalar types?! BaseScalar? # TODO: FIXME: check for default hilbert applicationId! @@ -1613,15 +1660,17 @@ def extend(delta, base): ############################################################### class GlobalApplications(BaseIDMap): - def __init__(self, parent): - BaseIDMap.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(GlobalApplications, self).__init__(*args, **kwargs) + self._default_type = "default_global_applications" self._types = {self._default_type: (ApplicationID, ApplicationWrapper)} ############################################################### class GlobalProfiles(BaseIDMap): - def __init__(self, parent): - BaseIDMap.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(GlobalProfiles, self).__init__(*args, **kwargs) + self._default_type = "default_global_profiles" self._types = {self._default_type: (ProfileID, Profile)} @@ -1635,14 +1684,18 @@ def __init__(self, parent): class GlobalStations(BaseIDMap): """Global mapping of station IDs to Station's""" - def __init__(self, parent): - BaseIDMap.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(GlobalStations, self).__init__(*args, **kwargs) + self._default_type = "default_global_stations" self._types = {self._default_type: (StationID, Station)} # NOTE: {StationID -> Station} def validate(self, d): """Extension mechanism on top of the usual ID Mapping parsing""" + if d is None: + d = self._default_input_data + if not BaseIDMap.validate(self, d): return False @@ -1697,16 +1750,19 @@ def validate(self, d): ############################################################### -class BaseList(Base): +class BaseList(BaseValidator): """List of entities of the same type""" - def __init__(self, parent): - Base.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(BaseList, self).__init__(*args, **kwargs) self._default_type = None self._types = {} def validate(self, d): + if d is None: + d = self._default_input_data + assert self._default_type is not None assert len(self._types) > 0 @@ -1718,7 +1774,7 @@ def validate(self, d): if (not isinstance(d, (list, dict, tuple, set))) and isinstance(d, string_types): try: - _d = [self._type.parse(BaseString.parse(d, parent=self))] + _d = [self._type.parse(StringValidator.parse(d, parent=self))] self.get_data(_d) return True except: @@ -1748,8 +1804,8 @@ def validate(self, d): class GroupIDList(BaseList): """List of GroupIDs or a single GroupID!""" - def __init__(self, parent): - BaseList.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(GroupIDList, self).__init__(*args, **kwargs) self._default_type = "default_GroupID_list" self._types = {self._default_type: GroupID} @@ -1759,8 +1815,8 @@ def __init__(self, parent): class ServiceList(BaseList): """List of ServiceIDs or a single ServiceID!""" - def __init__(self, parent): - BaseList.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(ServiceList, self).__init__(*args, **kwargs) self._default_type = "default_ServiceID_list" self._types = {self._default_type: ServiceID} @@ -1770,19 +1826,19 @@ def __init__(self, parent): class ServiceTypeList(BaseList): """List of ServiceType's or a single ServiceType!""" - def __init__(self, parent): - BaseList.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(ServiceTypeList, self).__init__(*args, **kwargs) self._default_type = "default_ServiceType_list" self._types = {self._default_type: ServiceType} ############################################################### -class Group(BaseRecord): # ? TODO: GroupSet & its .parent? +class Group(BaseRecordValidator): # ? TODO: GroupSet & its .parent? """Group""" - def __init__(self, parent): - BaseRecord.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(Group, self).__init__(*args, **kwargs) self._default_type = "default_group" @@ -1806,12 +1862,15 @@ def __init__(self, parent): def detect_extra_rule(self, key, value): # Any extra unlisted keys in the mapping? if value is None: # Set item! - return GroupID, BaseScalar + return GroupID, ScalarValidator return None def validate(self, d): - _ret = BaseRecord.validate(self, d) + if d is None: + d = self._default_input_data + + _ret = BaseRecordValidator.validate(self, d) # TODO: FIXME: Add extra keys into include! @@ -1821,50 +1880,55 @@ def validate(self, d): ############################################################### class GlobalGroups(BaseIDMap): - def __init__(self, parent): - BaseIDMap.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(GlobalGroups, self).__init__(*args, **kwargs) + self._default_type = "default_global_groups" self._types = {self._default_type: (GroupID, Group)} ############################################################### -class Preset(BaseRecord): +class Preset(BaseRecordValidator): """Preset""" - def __init__(self, parent): - BaseRecord.__init__(self, parent) + def __init__(self, *args, **kwargs): + super(Preset, self).__init__(*args, **kwargs) self._default_type = "default_preset" - # self.__tag = "Version" default_rule = { # self.__tag: (True , ??), # Mandatory # self.__tag: (False, ??), # Optional } - self._types = {self._default_type: default_rule} - raise NotImplementedError("Presets are not supported yet!") ############################################################### class GlobalPresets(BaseIDMap): # Dummy for now! - def __init__(self, parent): - BaseIDMap.__init__(self, parent) + + def __init__(self, *args, **kwargs): + super(GlobalPresets, self).__init__(*args, **kwargs) + self._default_type = "default_global_presets" self._types = {self._default_type: (PresetID, Preset)} - def validate(self, data): + def validate(self, d): + if d is None: + d = self._default_input_data + print("WARNING: Presets are not supported yet!") # raise NotImplementedError("Presets are not supported yet!") return True ############################################################### -class Hilbert(BaseRecord): +class Hilbert(BaseRecordValidator): """General Hilbert Configuration format""" - def __init__(self, parent): - BaseRecord.__init__(self, parent) # This is the Main Root! + def __init__(self, *args, **kwargs): + kwargs['parsed_result_is_data'] = kwargs.pop('parsed_result_is_data', False) + + super(Hilbert, self).__init__(*args, **kwargs) # This is the Main Root of all Validators! self._default_type = "default_global" @@ -1877,7 +1941,7 @@ def __init__(self, parent): ### explicit (optional) Type? default_rule = { - self._version_tag: (True, SemanticVersion), # Mandatory, specifies supported Types of Config's Entity + self._version_tag: (True, SemanticVersionValidator), # Mandatory, specifies supported Types of Config's Entity self._services_tag: (True, GlobalServices), self._applications_tag: (True, GlobalApplications), self._profiles_tag: (True, GlobalProfiles), @@ -1891,33 +1955,39 @@ def __init__(self, parent): self._default_data = None @classmethod - def parse(cls, d, parent=None): - self = cls(parent) - - if d is None: - d = self._default_data + def parse(cls, d, *args, **kwargs): + self = cls(*args, **kwargs) if self._version_tag not in d: _key_note(self._version_tag, d.lc, "ERROR: Missing mandatory '{}' key field!") raise ConfigurationError(u"{}: {}".format("ERROR:", "Missing version tag '{0}' in the input: '{1}'!".format(self._version_tag, d))) try: - _v = SemanticVersion.parse(d[self._version_tag], parent=self, partial=True) + _v = SemanticVersionValidator.parse(d[self._version_tag], parent=self, partial=True) except: _value_error(self._version_tag, d, d.lc, "Wrong value of global '{}' specification!") raise self.set_version(_v) # NOTE: globally available now! - if self.validate(d): - return self.get_data() + if self.validate(d): # NOTE: validate should not **explicitly** throw exceptions!!! + if self._parsed_result_is_data: + return self.get_data() - return None + return self - def validate(self, data): - _ret = BaseRecord.validate(self, data) + # NOTE: .parse should! + raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!".format(d))) + + def validate(self, d): + if d is None: + d = self._default_data - for offset, k in enumerate(data): + assert isinstance(d, dict) + + _ret = BaseRecordValidator.validate(self, d) + + for offset, k in enumerate(d): if k == self._version_tag: if offset != 0: print("Note: '{}' specified correctly but not ahead of everything else (offset: {})!".format( @@ -1926,8 +1996,8 @@ def validate(self, data): break # NOTE: check uniqueness of keys among (Services/Applications): - _services = data.get(self._services_tag) # Rely on the above and use get_data? - _applications = data.get(self._applications_tag) + _services = d.get(self._services_tag) # Rely on the above and use get_data? + _applications = d.get(self._applications_tag) for p, k in enumerate(_services): _lc = _services.lc.key(k) @@ -1960,13 +2030,7 @@ def load_yaml_file(filename): ############################################################### def parse_hilbert(d, parent=None): assert d is not None - - cfg = Hilbert(parent) - if not cfg.validate(d): - raise ConfigurationError(u"{}: {}".format("ERROR:", "Cannot parse given configuration!")) - - return cfg -# return Hilbert.parse(d, parent=parent) + return Hilbert.parse(d, parent=parent, parsed_result_is_data=False) ############################################################### diff --git a/config/subcmdparser.py b/config/subcmdparser.py index 822523a..abe5332 100644 --- a/config/subcmdparser.py +++ b/config/subcmdparser.py @@ -40,8 +40,9 @@ def subcmd_fxn(cmd_fxn, name, kwargs): ######################### class SortingHelpFormatter(argparse.RawTextHelpFormatter): def __init__(self, *args, **kwargs): - argparse.RawTextHelpFormatter.__init__(self, indent_increment=1, max_help_position=17, - *args, **kwargs) + kwargs['indent_increment'] = 1 + kwargs['max_help_position'] = 17 + super(SortingHelpFormatter, self).__init__(*args, **kwargs) # def add_arguments(self, actions): # actions = sorted(actions, key=attrgetter('help')) # super(SortingHelpFormatter, self).add_arguments(actions) @@ -84,9 +85,9 @@ def __init__(self, *args, **kwargs): # setup the class if self._use_subcommand_help: - argparse.ArgumentParser.__init__(self, formatter_class=SortingHelpFormatter, *args, **kwargs) - else: - argparse.ArgumentParser.__init__(self, *args, **kwargs) + kwargs['formatter_class']=SortingHelpFormatter + + super(SubCommandHandler, self).__init__(*args, **kwargs) def add_argument(self, *args, **kwargs): """ @@ -97,7 +98,7 @@ def add_argument(self, *args, **kwargs): assert not(self._ignore_remainder and 'nargs' in kwargs and kwargs['nargs'] == argparse.REMAINDER) # self._use_subcommands = False - return argparse.ArgumentParser.add_argument(self, *args, **kwargs) + return super(SubCommandHandler, self).add_argument(*args, **kwargs) def set_subcommands(self, subcommand_lookup): """ @@ -219,7 +220,7 @@ def parse_args(self, argv=None): argcomplete.autocomplete(self) # parse arguments - args = argparse.ArgumentParser.parse_args(self, argv) + args = super(SubCommandHandler, self).parse_args(argv) self._has_parse = True @@ -310,11 +311,5 @@ def __call__(self, parser, args, values, option_string=None): except: pass - exit(0) + parser.exit(0) setattr(args, self.dest, values) - - - - - - diff --git a/tests/data/Hilbert.yml.data.pickle b/tests/data/Hilbert.yml.data.pickle index 8451d333da9361d9503a4690754587787e4f376c..1a3b74b705497f4b4b42763891edbd66b869e7a5 100644 GIT binary patch literal 3379 zcmb7G_j}W35Dued6v~E{4%9-y1uVw_0&z=QB{4}Lv4iD+pmkNn{t~I!l20R}R4v`1 zd+)vX-h2ODz3=29*=e7r$uEBN-FNriz3<(3XBPU<5mQ!lbaY77YS}1iu3?!DEbw8W zvIM{C{jpzBTrOGP2p?R*Q zmYBwV z6hU@@4;RMB!Z9jUjJY{O=WM1}_DT#cD!|3cLhi|iOEh%06n{4oz0`*-0Yy{eYK;$7 z1Hp&OVpQK^* zOKP8#>xV1wWMk-V-j}*( zyQ{8Z+Ec?brWmQh+ zj-_+3Te$>Js*~9_Wpf?T> zd|8`?#F6F7hEUjuDxs6kbl0t>5{YEjez6n(lc@vv2T6}AWK~M4t4%_eat^xDCXpf7 z)9jPI6#bZCyPj4SYFwuT-Zg>*`$#OhQ7SPLy3e-BdOsD98zbRDn->WV5C*MOvYF#R zk8(a@NcMDz$?gMUPmh@F?12=SRBem8;Ht1ZuU1y0ebt&~wq-VTbv3J2(-TKJB8~%Tt9{wbp`n4maYotlA0QoOPcb_IS$(IzE2_QGkoJx? zwU?t>$n`c6Wby!VSakWhHqnjINC}Laify=oV-d|ApPz9hqPi1->Vo(u17^97xOS3o zy$?48daE~6L0OKKzy>x;TG>K5+}O-YC12D)Nw_JTi`L#ix8*H4z`n$M>9L%y#&~a2vHur`Roa!tKF3 zjOsLs%z-mL+z}%_P>yh?4|jzYqPxjUeIdH1u{zvKKDd50lTE{Y`f7cRzD&6kL)I1` zoJFDSr#_i{m%+9(Pc=1yBS2e6xR;#6RR2-}6=ZN(obJArl- z5k8$a%g+k%d6SAST48({P3)@zeC-8v1+)DdAHHpe`5jH+tXZBFCM>)54mGCm_wxez yp#VQd%KcNQ+&_n7{u0IXYXN=>75n#=V*k_6#V{k?|2=%9k^{mnej6aNA4dFf=eT-qd*;Blwzh2Ep0w(vTDG>UYU_P6 z2Z0x`wv{RqR!Psx%r}Bo&C>H-y>EMFU(oBMQm;CCzc^j%Oh->5p%*~m{;p26t9>#@ z>@j?Hn>Wxxg|QFF><59VU52L*j2)Ze34IU-J=oQUa8RxzoHLvCqRau{Weeq8sh+p9 zHEWwb)C}!&^kLL?c)Q`*JB^e+Vz26k2R0O(T0$QQrAN8?XevECqSUN(cpzJXls-ny zzf2#SnTvKU`Z&w1IlIPk>})o*X*j!Oa4bDMI+7h8(8p)GAhl#T-=Cc5$>sX`a@~_w z&)GR^!s=U*U(s#lR!-)6mMyndO|Dq6Y*}w_Z(nkWKEdq2F_@!IboEK9NX8C(5s-L&(-}@!OaL%jRUKfTsbtnVa?#!cotN4Q)+z3 z)oaXh#Gce^&DLRIS*vXC&;zqd1`Qf=-kS7O6HmcQj)ET*=WHHA-*1L~V8TrA@YZj#}k7aD?S> z1Oq2ksa#>E{alsudB(!q7z-{_#O39#&SG*{(z$B2(FjOAuU)0gbba^?t;ud4+Ymv} z&|qq8e9d5LoP1YXA&fl5vr2NaILbH8)rPiNz)TV_+uGGd(+aj%u)Ts=3oxsK*@`fm zf;p~0K#3Yaad%6up5g+yWtRtAruU|b74i6->R^tsVj4{1_ zjNzfR1yK)frk(iSQ&zcF$oWDEUBf)ML zi(RszN55!keZpXhfs&_!8SpAb+&Rq|LY@i0)ftGj>1zNU9Js_}XuHwX zFWCdsFKstiq$}%}84W{gI>xEt<(Y+MT8{C2n)MZ#Mc|BC<$Pr-IkYCpi4@A)^ec&4 z6aVPB*ocXeo%W6>N54ujO?kDeUqjuC)S=4c9j`UIf-L8CBaT|4!ZY>tJX7BgoT+bA z-U<39{{(%rcY-P$mCBroH!7Zivp)3}Gj1|HC-nOp`U88I z<%81-{15HT03V)aKJXDgihQ&sTExLMf}Aj9-wGps%+((!T+fKWHQyYvBd`s__HBqk zH@3#0PqZ@#ebNLWb(^a{h1v~H9UgZbe9?rXFsb>py8gdRlOgFd>ehz-EJM=uen>KD zPk_VE#SP&(W`Na%z8$N)!_}YXD&x|gV6Z#skY8vw?!SE^>pNxE(qD|z;*X!ucVYOu zUHv5v&+H`dc|V`i_i)%Rdl@-T3+C)!F`>&chtpU0u>IFE$6_4%EAWxrQjl8RDkXh| z{mGR6y2&Q1l^wPqVRY;o1s(m3xOsZvW21$(GE#$kG28oG{Y}o6*NdiReLv^=EicR3 zK9yA!r-mUAxNY=frNelV}Hlh-$m><6LjiG49b=5R_D}Yr895q@0qM= zvAR!Ptr%z-i%c?Ct3$4=zwd=ZXf~ni2fisf)IdFb0j zTaK1D+BH?ldr92G4gDJv6z?|yF>d#LNHld0o%<13-XwWSO3AwaM4%qj++S@68bT9zq%JwUaan}Px!Ih81j$C@Ad#P z5e_u}$?RqTvp*}s=r6ARD`CW2dv{+?XZOlgoqc_s-OKv)-+U0=?SqJSc2&sd?Xv#+ zjPXD`4j}8B^^1SR&Dh_&wMI7WyHG+u4(0!J^}o1lCq;J6_hvpkG>!cPJ?7u-#$$s^ z$ELBt3kS!>1_!bmQX}g&r`8SXC(X4PF7TAOH3yPS$)$eUw5eLH+TYdH-E(&5GW_rE zUxk1A8MB4K^9P*1=v%47YNbgXYW$XsqJI z!R55Ovs#}(Cej&tX#dLP-7=SA%m(&QBm1CfI&(^-E!dDC+(ixvna6>cmWMG^=96_K zShMp>kB@E~zBDzCH-oh7%XX%lw%}PUozWB?&nI zG7UKpC6A^jJj9#nSEa(MtQ>^4$m@d~4BAY_dxP-N&ci?sp(vN`Gi4DO<_)Xhc*r(# zhXzA>JUNW?(dcLHR$hkIlw!)^kQl+_?mz_b9w2aO@?ReuGv*N-gJC$*AV-1;&zGb4 zdygwer&M@81WH*}g*}82hIE9Hq zsZiUMkh4s;4wUAExW@xk5Y-8)P7cY9L>#6k^8Dm+-Ys2VDkLqk3>8=c@(n}`Ot8`_`PNv6GBLk@oqa%Ys-Xbe0z*n$f znnB(oXQM?uh8e9w#g#skoY8L1sGmgZDJ|!KJ8jbVDJv)Ef-+H{ySu-qr+@kK{uL|w zdwcs=u9Vem;`os5eAU8nCFg^PrVDZb7;3jGDg3sp2WQkn4OtWPpq{lLVsXGM zXk%(^kO;{D1RFAlk~f5h8*(A4#!|bz%MH$ESqGjgLnyge9KA&@zvc9mVe%ez+bUW@SA%CgzxfwOcljjs}*EVDNaA5ma0mMae^!#|H7y-AROW=F3hek8RmR zalVKyHp=|-HtHD{L!uQOW8}>q%8~{>V?tk%kwH#s=f@ zMbD=%C&T!3(eu_U8OB?So*zCB49^dXt!@_{uwp^TxZMOQuH;aLZkH#~%Z9RRM@KFkUT2<#Wjke<=k0AI$LwvF?0}$pQaz=f zR?igMK&)>o&cRP{E(?<$6`8{n_hYdD1u~PU^0C2n!|Cy{OR@v0@sy{0C#1~Vmm)OZ z|LC1BL_d1xi}2g*oma8N^UkYT^}O>MRA;^O#iXL%c`X^CcV0&-^v(t--#f2oL)1H` z$%uOA3>i`Hya9|D@1!5JQ%juGSHk}O5##gax=)tch#Vop2+`C1}YuFz3= z{P=aKxbk|G^kaUlMDl`scM5r9t`jLqXR1`N9C-sfc+Si{@SU0O8Z9>;c_W+YyKh3p zl{cddefKRSBL3m|!>ohQlYFP~@I32QhleTqTdAN4+HV6VfHr5>0_~f?YPHAP$%~vu z?*Kjh|H1n^(UEw67k-=ZeluG;Xyfp=Q^rW(9OlG@%JrQ=+;EaR@EJOJ@mLaf(lU~A`7-7BI?5x9ABE*B;5^GBy#;<1LRjF}@Z-wY zQF4I{F)a)9{|Z390TC|mUW%H?RIN?zl>0!Mi$?fCOuk7LKgwvyDqJ3LE0+7gvx7bO z7Kox5Pje6S>>h*x@7o-Miy9XzcLiQK?X_q+X8uv1XTpN zj{Grbo`SXi1R})CpFyajLN7bZM3+jvmPBTdJT2*cB|rr! zc+z~f=#=^F-UN<)soDp}eyF>$0A&;$`-2W9nxJ&E_xlqKt+@~)tq1x6;Dr`FkYjij zJqXoiiyjP)Z_z_27q#djws{sklvU57hoQPxiyBm!KP8gGIh=3JBT#qcNR&})9z{CV znn$y*Z_Q&&-(&s0fi;f<-Q?cKgAuy-2_RbR%PGXz_e74f1olmpcO{z+kI=f2d@O};r#M%|UgD5K^)h4ieiF9F%&>!*Sh`tNBVS}g8QJ+%1g93ryQ?Vv+zFJ*tv z+Gn8JZ0$3_@vVIp<)YT^V4G*{PF6i@ccHpBYlk|QaV(}Q<~6_=y&>IT@)RK7%bSe6 z_X_9#v4eSD?SY^%rT<3{vYZU_wCm^p-ZSh9vbp(b|6`=|f@2Pt5q0&5-@`xG&B!am z9>HmUb~tp9W*Na%fuNs8Inu|Wk%IK|cb+Tf;Mcp@Y{G{=yXMHb;KV*f28o{$OUP=- zHRL>$#%A8%Mauc?trj%o0#u5e*0kzrNQxBKKdowbSVP6^SLD02BWq3bwGA1dF!x|u z-Hw+uQk?d5k*Ox$(@@7BEHPE`|IE^?bsgoX9@)e^^CH;v9&TiYC__E Date: Sat, 26 Nov 2016 18:38:00 +0100 Subject: [PATCH 31/42] Added Requirements + removed some unnecessary imports --- requirements.txt | 18 ++++++++++++++++++ tests/__init__.py | 25 ++++++++++++------------- 2 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 requirements.txt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..910a8b0 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,18 @@ +dill >= 0.2.5 +semantic_version >= 2.6.0 +argparse >= 1.4.0 +argcomplete >= 1.6.0 +ruamel.yaml >= 0.12.15 +# logging; python_version < 2.8 + +#pprint +##tempfile # ? +#urllib +#urllib2 +#urlparse + +#unittest +#unittest2; python_version < 2.7 +#mock ; python_version < 2.7 +#tox +#pytest diff --git a/tests/__init__.py b/tests/__init__.py index 1ac1b21..7f75e2e 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,14 +1,13 @@ -from __future__ import absolute_import -from __future__ import unicode_literals +from __future__ import absolute_import, unicode_literals -import sys - -if sys.version_info >= (2, 7): - import unittest # NOQA -else: - import unittest2 as unittest # NOQA - -try: - from unittest import mock -except ImportError: - import mock # NOQA +#import sys +# +#if sys.version_info >= (2, 7): +# import unittest # NOQA +#else: +# import unittest2 as unittest # NOQA +# +#try: +# from unittest import mock +#except ImportError: +# import mock # NOQA From 056ab1e49f25bc1c31b21f31c711f11dd5457743 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Sat, 26 Nov 2016 18:54:04 +0100 Subject: [PATCH 32/42] Looking for a minimal CLI: no app_start/app_stop ATM --- tools/hilbert.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/tools/hilbert.py b/tools/hilbert.py index 2d941e2..d4c443c 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -495,7 +495,7 @@ def cmd_cfg_deploy(parser, context, args): return args -@subcmd('app_start', help='start an application on a station') +# @subcmd('app_start', help='start an application on a station') def cmd_app_start(parser, context, args): action = 'app_start' log.debug("Running 'cmd_{}'" . format(action)) @@ -516,8 +516,7 @@ def cmd_app_start(parser, context, args): log.debug("Done") return args - -@subcmd('app_stop', help='stop an application on a station') +# @subcmd('app_stop', help='stop the current application on a station') def cmd_app_stop(parser, context, args): action = 'app_stop' log.debug("Running 'cmd_{}'" . format(action)) @@ -530,7 +529,7 @@ def cmd_app_stop(parser, context, args): help="specify input dump file") parser.add_argument('StationID', help="specify the station") - parser.add_argument('ApplicationID', help="specify the application to stop") +# parser.add_argument('ApplicationID', help="specify the application to stop") # parser.add_argument('action_args', nargs='?', help="optional argument for finish: ApplicationID/ServiceID ", metavar='id') cmd_action(parser, context, args, Action=action, appIdRequired=True) From a3b3800d8ee6e28909fd9c0cbe65c37859df287f Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Sat, 26 Nov 2016 22:06:19 +0100 Subject: [PATCH 33/42] Better automated doc generation + source verification (pep8/pylint) NOTE: output to docs/ --- Doxyfile | 2 +- Makefile | 18 +-- docs/.gitignore | 4 + rcfile.pylint | 345 +++++++++++++++++++++++++++++++++++++++++++++++ tools/hilbert.py | 5 +- 5 files changed, 362 insertions(+), 12 deletions(-) create mode 100644 docs/.gitignore create mode 100644 rcfile.pylint diff --git a/Doxyfile b/Doxyfile index 8771312..c382bee 100644 --- a/Doxyfile +++ b/Doxyfile @@ -4,7 +4,7 @@ PROJECT_NAME = Hilbert PROJECT_NUMBER = 0.0.1 PROJECT_BRIEF = "Hilbert CLI (server part)" PROJECT_LOGO = -OUTPUT_DIRECTORY = doxydoc +OUTPUT_DIRECTORY = docs/doxy CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English BRIEF_MEMBER_DESC = YES diff --git a/Makefile b/Makefile index 27ca6ed..810826e 100644 --- a/Makefile +++ b/Makefile @@ -6,7 +6,7 @@ SRC=config/*.py tools/*.py NAME=hilbert -.PHONY: usage pep8 apidocs clean pylint install build +.PHONY: usage pep8 apidocs clean pylint install build all_docs usage: # Print Targets @grep '^[^#[:space:]].*:' Makefile @@ -16,17 +16,19 @@ check: # Run the tests /bin/bash -c 'cd tests/ && py.test-3 -v test_*.py' pep8: ${SRC} # Check for PEP8 compliance - pep8 --first --show-source --show-pep8 ${SRC} + pep8 --first --show-source --show-pep8 --statistics --max-line-length=100 --format=pylint ${SRC} > docs/pep8.report.txt 2>&1 || echo $? -pylint: # Analyse Source - pylint -f html --files-output=y ${SRC} +pylint: # Analyse Source + pylint --rcfile=rcfile.pylint -f html --comment=y --files-output=y ${SRC} 2>&1 || echo $? # --full-documentation + mv pylint_*.html docs/ + +all_docs: apidocs epydoc pep8 pylint apidocs: ${SRC} # Build API Documentation with doxygen - doxygen Doxyfile + doxygen Doxyfile 2>&1 || echo $? epydoc: ${SRC} # Build API Documentation with epydoc - epydoc --html --inheritance=listed --graph=all ${SRC} + epydoc --html -o docs/epydoc --inheritance=listed --show-imports --graph=all ${SRC} 2>&1 || echo $? clean: # Clean Project - rm -rf doxydoc *~ -# python3 distribute_setup.py clean + rm -rf *~ docs/doxy docs/epydoc docs/pylint_*.html docs/pep8.report.txt diff --git a/docs/.gitignore b/docs/.gitignore new file mode 100644 index 0000000..9536646 --- /dev/null +++ b/docs/.gitignore @@ -0,0 +1,4 @@ +doxy/ +epydoc/ +pep8.report.txt +pylint_*.html diff --git a/rcfile.pylint b/rcfile.pylint new file mode 100644 index 0000000..f5c623d --- /dev/null +++ b/rcfile.pylint @@ -0,0 +1,345 @@ +[MASTER] + +# Specify a configuration file. +#rcfile= + +# Python code to execute, usually for sys.path manipulation such as +# pygtk.require(). +#init-hook= + +# Profiled execution. +profile=no + +# Add files or directories to the blacklist. They should be base names, not +# paths. +ignore=.git + +# Pickle collected data for later comparisons. +persistent=yes + +# List of plugins (as comma separated values of python modules names) to load, +# usually to register additional checkers. +load-plugins= + +# DEPRECATED +include-ids=no + +# DEPRECATED +symbols=no + +# Allow loading of arbitrary C extensions. Extensions are imported into the +# active Python interpreter and may run arbitrary code. +unsafe-load-any-extension=no + +# A comma-separated list of package or module names from where C extensions may +# be loaded. Extensions are loading into the active Python interpreter and may +# run arbitrary code +extension-pkg-whitelist= + + +[MESSAGES CONTROL] + +# Enable the message, report, category or checker with the given id(s). You can +# either give multiple identifier separated by comma (,) or put this option +# multiple time. See also the "--disable" option for examples. +#enable= + +# Disable the message, report, category or checker with the given id(s). You +# can either give multiple identifiers separated by comma (,) or put this +# option multiple times (only on the command line, not in the configuration +# file where it should appear only once).You can also use "--disable=all" to +# disable everything first and then reenable specific checks. For example, if +# you want to run only the similarities checker, you can use "--disable=all +# --enable=similarities". If you want to run only the classes checker, but have +# no Warning level messages displayed, use"--disable=all --enable=classes +# --disable=W" +#disable= + + +[REPORTS] + +# Set the output format. Available formats are text, parseable, colorized, msvs +# (visual studio) and html. You can also give a reporter class, eg +# mypackage.mymodule.MyReporterClass. +output-format=html + +# Put messages in a separate file for each module / package specified on the +# command line instead of printing them on stdout. Reports (if any) will be +# written in a file name "pylint_global.[txt|html]". +files-output=yes + +# Tells whether to display a full report or only the messages +reports=yes + +# Python expression which should return a note less than 10 (10 is the highest +# note). You have access to the variables errors warning, statement which +# respectively contain the number of errors / warnings messages and the total +# number of statements analyzed. This is used by the global evaluation report +# (RP0004). +evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) + +# Add a comment according to your evaluation note. This is used by the global +# evaluation report (RP0004). +comment=yes + +# Template used to display messages. This is a python new-style format string +# used to format the message information. See doc for all details +#msg-template= + + +[TYPECHECK] + +# Tells whether missing members accessed in mixin class should be ignored. A +# mixin class is detected if its name ends with "mixin" (case insensitive). +ignore-mixin-members=yes + +# List of module names for which member attributes should not be checked +# (useful for modules/projects where namespaces are manipulated during runtime +# and thus existing member attributes cannot be deduced by static analysis +ignored-modules= + +# List of classes names for which member attributes should not be checked +# (useful for classes with attributes dynamically set). +#ignored-classes=SQLObject + +# When zope mode is activated, add a predefined set of Zope acquired attributes +# to generated-members. +zope=no + +# List of members which are set dynamically and missed by pylint inference +# system, and so shouldn't trigger E0201 when accessed. Python regular +# expressions are accepted. +generated-members=REQUEST,acl_users,aq_parent + + +[SIMILARITIES] + +# Minimum lines number of a similarity. +min-similarity-lines=4 + +# Ignore comments when computing similarities. +ignore-comments=yes + +# Ignore docstrings when computing similarities. +ignore-docstrings=yes + +# Ignore imports when computing similarities. +ignore-imports=no + + +[MISCELLANEOUS] + +# List of note tags to take in consideration, separated by a comma. +notes=FIXME,XXX,TODO + + +[VARIABLES] + +# Tells whether we should check for unused import in __init__ files. +init-import=no + +# A regular expression matching the name of dummy variables (i.e. expectedly +# not used). +dummy-variables-rgx=_$|dummy + +# List of additional names supposed to be defined in builtins. Remember that +# you should avoid to define new builtins when possible. +additional-builtins= + + +[FORMAT] + +# Maximum number of characters on a single line. +max-line-length=80 + +# Regexp for a line that is allowed to be longer than the limit. +ignore-long-lines=^\s*(# )??$ + +# Allow the body of an if to be on the same line as the test if there is no +# else. +single-line-if-stmt=no + +# List of optional constructs for which whitespace checking is disabled +no-space-check=trailing-comma,dict-separator + +# Maximum number of lines in a module +max-module-lines=1000 + +# String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 +# tab). +indent-string=' ' + +# Number of spaces of indent required inside a hanging or continued line. +indent-after-paren=4 + + +[LOGGING] + +# Logging modules to check that the string format arguments are in logging +# function parameter format +logging-modules=logging + + +[BASIC] + +# Required attributes for module, separated by a comma +required-attributes= + +# List of builtins function names that should not be used, separated by a comma +bad-functions=map,filter,apply,input,file + +# Good variable names which should always be accepted, separated by a comma +good-names=i,j,k,ex,Run,_ + +# Bad variable names which should always be refused, separated by a comma +bad-names=foo,bar,baz,toto,tutu,tata + +# Colon-delimited sets of names that determine each other's naming style when +# the name regexes allow several styles. +name-group= + +# Include a hint for the correct naming format with invalid-name +include-naming-hint=no + +# Regular expression matching correct function names +function-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for function names +function-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct variable names +variable-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for variable names +variable-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct constant names +const-rgx=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Naming hint for constant names +const-name-hint=(([A-Z_][A-Z0-9_]*)|(__.*__))$ + +# Regular expression matching correct attribute names +attr-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for attribute names +attr-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct argument names +argument-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for argument names +argument-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression matching correct class attribute names +class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Naming hint for class attribute names +class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ + +# Regular expression matching correct inline iteration names +inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ + +# Naming hint for inline iteration names +inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ + +# Regular expression matching correct class names +class-rgx=[A-Z_][a-zA-Z0-9]+$ + +# Naming hint for class names +class-name-hint=[A-Z_][a-zA-Z0-9]+$ + +# Regular expression matching correct module names +module-rgx=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Naming hint for module names +module-name-hint=(([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ + +# Regular expression matching correct method names +method-rgx=[a-z_][a-z0-9_]{2,30}$ + +# Naming hint for method names +method-name-hint=[a-z_][a-z0-9_]{2,30}$ + +# Regular expression which should only match function or class names that do +# not require a docstring. +no-docstring-rgx=__.*__ + +# Minimum line length for functions/classes that require docstrings, shorter +# ones are exempt. +docstring-min-length=-1 + + +[DESIGN] + +# Maximum number of arguments for function / method +max-args=5 + +# Argument names that match this expression will be ignored. Default to name +# with leading underscore +ignored-argument-names=_.* + +# Maximum number of locals for function / method body +max-locals=15 + +# Maximum number of return / yield for function / method body +max-returns=6 + +# Maximum number of branch for function / method body +max-branches=12 + +# Maximum number of statements in function / method body +max-statements=50 + +# Maximum number of parents for a class (see R0901). +max-parents=7 + +# Maximum number of attributes for a class (see R0902). +max-attributes=7 + +# Minimum number of public methods for a class (see R0903). +min-public-methods=2 + +# Maximum number of public methods for a class (see R0904). +max-public-methods=20 + + +[IMPORTS] + +# Deprecated modules which should not be used, separated by a comma +deprecated-modules=regsub,TERMIOS,Bastion,rexec + +# Create a graph of every (i.e. internal and external) dependencies in the +# given file (report RP0402 must not be disabled) +import-graph= + +# Create a graph of external dependencies in the given file (report RP0402 must +# not be disabled) +ext-import-graph= + +# Create a graph of internal dependencies in the given file (report RP0402 must +# not be disabled) +int-import-graph= + + +[CLASSES] + +# List of interface methods to ignore, separated by a comma. This is used for +# instance to not check methods defines in Zope's Interface base class. +ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by + +# List of method names used to declare (i.e. assign) instance attributes. +defining-attr-methods=__init__,__new__,setUp + +# List of valid names for the first argument in a class method. +valid-classmethod-first-arg=cls + +# List of valid names for the first argument in a metaclass class method. +valid-metaclass-classmethod-first-arg=mcs + + +[EXCEPTIONS] + +# Exceptions that will emit a warning when being caught. Defaults to +# "Exception" +overgeneral-exceptions=Exception diff --git a/tools/hilbert.py b/tools/hilbert.py index d4c443c..e66adfc 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -8,8 +8,6 @@ from __future__ import absolute_import, print_function, unicode_literals -assert __name__ == "__main__" - import sys from os import path DIR=path.dirname(path.dirname(path.abspath(__file__))) @@ -669,4 +667,5 @@ def main(): args = handler.run(_argv) handler.exit(status=0) -main() +if __name__ == "__main__": + main() From 8d43978e90acbee0f4ac664390e7bca8d186b307 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Sun, 27 Nov 2016 05:05:30 +0100 Subject: [PATCH 34/42] Added simple initial setup.py and tox.ini NOTE: run `make tox` (or simply `tox`), provided Python2.7 and Python3.4 are available --- Makefile | 9 ++++++--- setup.py | 30 ++++++++++++++++++++++++++++++ tox.ini | 12 +++++++++--- 3 files changed, 45 insertions(+), 6 deletions(-) create mode 100644 setup.py diff --git a/Makefile b/Makefile index 810826e..c2de52d 100644 --- a/Makefile +++ b/Makefile @@ -12,9 +12,12 @@ usage: # Print Targets @grep '^[^#[:space:]].*:' Makefile check: # Run the tests - /bin/bash -c 'cd tests/ && py.test -v test_*.py' - /bin/bash -c 'cd tests/ && py.test-3 -v test_*.py' - + /bin/bash -c 'py.test -v -l --tb=auto --full-trace --color=auto tests/test_*.py' + /bin/bash -c 'py.test-3 -v -l --tb=auto --full-trace --color=auto tests/test_*.py' + +tox: tox.ini setup.py # Run clean testing via tox + tox + pep8: ${SRC} # Check for PEP8 compliance pep8 --first --show-source --show-pep8 --statistics --max-line-length=100 --format=pylint ${SRC} > docs/pep8.report.txt 2>&1 || echo $? diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..7a7e809 --- /dev/null +++ b/setup.py @@ -0,0 +1,30 @@ +from distutils.core import setup + +setup(name='Hilbert', + version='0.2.2', + description='Hilbert tool (server part)', + url='https://github.com/hilbert/hilbert-cli', + author='Oleksandr Motsak', + author_email='http://goo.gl/mcpzY', + packages=['config'], + package_dir={'config': 'config'}, # package_data={'...': ['data/*.dat']}, + # py_modules=['tools/hilbert.py'], + scripts=['tools/hilbert', 'tools/hilbert.py'], + license='', + classifiers=[''], + platforms=[''], # data_files=[('config/templates', ['docker-compose.yml'])], + install_requires=[ + 'dill>=0.2.5', + 'semantic_version>=2.6.0', + 'argparse>=1.4.0', + 'argcomplete>=1.6.0', + 'ruamel.yaml>=0.12.15', + ], + extras_require={ + ':python_version == "2.7"': [ + 'logging', # TODO: check whether this is really required!?! + ], + }, + ) # TODO: add testing!? +# glob.glob(os.path.join('mydir', 'subdir', '*.html')) +# os.listdir(os.path.join('mydir', 'subdir')) diff --git a/tox.ini b/tox.ini index 0e53be8..6329e28 100644 --- a/tox.ini +++ b/tox.ini @@ -1,14 +1,20 @@ [tox] # envlist = pep8,py35,py27,py34,py33,py26,pypy,jython #envlist = py35,py27,py34,py33,py26,pypy,jython -envlist = pep8,py35,py27,pypy +envlist = py34,py27 [testenv] commands = - /bin/bash -c 'py.test config/tests/test_*.py' + /bin/bash -c 'py.test -v -l --tb=auto --full-trace --color=auto tests/test_*.py' deps = + dill>=0.2.5 + semantic_version>=2.6.0 + argparse>=1.4.0 + argcomplete>=1.6.0 + ruamel.yaml>=0.12.15 + py27: logging pytest [pytest] -norecursedirs = config/tests/data +norecursedirs = tests/data From fd0fefb705fbb5587f34f7dd9859af3e8502826e Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Sun, 27 Nov 2016 05:12:56 +0100 Subject: [PATCH 35/42] Initial configuration for testing via TravisCI --- .travis.yml | 27 +++++++++++++++++++++++++++ .travis/install.sh | 1 + 2 files changed, 28 insertions(+) create mode 100644 .travis.yml create mode 100755 .travis/install.sh diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..318dbe0 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,27 @@ +language: python +sudo: false + +cache: + directories: + - $HOME/.cache/pip + +matrix: + include: + - python: 2.7 + env: TOXENV=py27 + - python: 3.4 + env: TOXENV=py34 + +install: + - ./.travis/install.sh + +script: + - source ~/.venv/bin/activate + - tox + +notifications: + email: + recipients: + - malex984+travis.cli@gmail.com + on_success: never + on_failure: always diff --git a/.travis/install.sh b/.travis/install.sh new file mode 100755 index 0000000..bfe0181 --- /dev/null +++ b/.travis/install.sh @@ -0,0 +1 @@ +pip install --upgrade tox From 31c32f5296d72ccbe4a6f70da6d2d5d2bff01b00 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Sun, 27 Nov 2016 05:16:56 +0100 Subject: [PATCH 36/42] More .gitignore + fix a few minor warnings due to PEP8 --- .gitignore | 3 +++ config/__init__.py | 2 +- config/subcmdparser.py | 2 -- tools/hilbert.py | 4 ++-- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/.gitignore b/.gitignore index fe28c04..b21007f 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,6 @@ lastapp.cfg *.pyc __pycache__ .idea +.tox/ +.cache/ +MANIFEST diff --git a/config/__init__.py b/config/__init__.py index f1d5b34..6ef28b2 100644 --- a/config/__init__.py +++ b/config/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import from __future__ import unicode_literals -__version__ = '0.2.2-dev' # TODO: add git commit id? +# __version__ = '0.2.2-dev' # TODO: add git commit id? # from hilbert_cli_config import * diff --git a/config/subcmdparser.py b/config/subcmdparser.py index abe5332..0d6b0ce 100644 --- a/config/subcmdparser.py +++ b/config/subcmdparser.py @@ -162,8 +162,6 @@ def logging_handler(parser, args): parser._logging_handler_done = True - - def parse_args(self, argv=None): """ Works the same as `argparse.ArgumentParser.parse_args`. diff --git a/tools/hilbert.py b/tools/hilbert.py index e66adfc..169fb5a 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -528,7 +528,8 @@ def cmd_app_stop(parser, context, args): parser.add_argument('StationID', help="specify the station") # parser.add_argument('ApplicationID', help="specify the application to stop") -# parser.add_argument('action_args', nargs='?', help="optional argument for finish: ApplicationID/ServiceID ", metavar='id') +# parser.add_argument('action_args', nargs='?', +# help="optional argument for finish: ApplicationID/ServiceID ", metavar='id') cmd_action(parser, context, args, Action=action, appIdRequired=True) @@ -558,7 +559,6 @@ def cmd_app_change(parser, context, args): return args - # @subcmd('run_action', help='run specified action on given station with given arguments...') def cmd_run_action(parser, context, args): log.debug("Running 'cmd_{}'" . format('run_action')) From 78a5169a5c5b2f9c408d61c2edc3b80394984206 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Thu, 1 Dec 2016 06:25:12 +0100 Subject: [PATCH 37/42] Added remote execution via ssh/scp + Dummy client script --- .gitattributes | 4 + config/.gitattributes | 2 - config/hilbert_cli_config.py | 697 ++++++++++++++++++++++++++++------- tools/hilbert-station | 24 ++ tools/hilbert.py | 3 + 5 files changed, 585 insertions(+), 145 deletions(-) create mode 100644 .gitattributes delete mode 100644 config/.gitattributes create mode 100755 tools/hilbert-station diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..848ccf3 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +config/hilbert_cli_config.py ident +tools/hilbert.py ident +tools/hilbert-station ident + diff --git a/config/.gitattributes b/config/.gitattributes deleted file mode 100644 index c5200a6..0000000 --- a/config/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -hilbert_cli_config.py ident - diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index cf8c8f7..4a0b2cc 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -23,12 +23,18 @@ import os import re, tokenize import tempfile +import subprocess, shlex +# import paramiko + import pprint as PP from abc import * ############################################################### +logging.basicConfig(format='%(levelname)s [%(filename)s:%(lineno)d]: %(message)s', level=logging.DEBUG) log = logging.getLogger(__name__) +log.setLevel(logging.DEBUG) + _pp = PP.PrettyPrinter(indent=4) ############################################################### @@ -81,12 +87,46 @@ def is_valid_id(k): def is_valid_id(k): return re.match(tokenize.Name + '$', k) + ############################################################### def pprint(cfg): global _pp _pp.pprint(cfg) +############################################################### +def _execute(_cmd, timeout=None, shell=False, stdout=None, stderr=None): # True??? Try several times? Overall timeout? + global PEDANTIC + __cmd = ' '.join(_cmd) + # stdout = tmp, stderr = open("/dev/null", 'w') + # stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) + log.debug("Executing shell command: '{}'...".format(__cmd)) + + retcode = None + with subprocess.Popen(_cmd, shell=shell, stdout=stdout, stderr=stderr) as p: + try: + retcode = p.wait(timeout=timeout) # ? + except: + p.kill() + p.wait() + log.exception("Could not execute '{0}'! Exception: {1}".format(__cmd, sys.exc_info())) + raise + + assert retcode is not None + log.debug("Exit code: '{}'".format(retcode)) + + if retcode: + if not PEDANTIC: # Bad error code [{0}] while + log.warning("Error exit code {0}, while executing '{1}'!".format(retcode, __cmd)) + else: # Pedantic mode? + log.error("Error exit code {0}, while executing '{1}'!".format(retcode, __cmd)) + raise Exception("Error exit code {0}, while executing '{1}'".format(retcode, __cmd)) + else: + log.debug("Successful command '{}' execution!".format(__cmd)) + + return retcode + + ############################################################### def _get_line_col(lc): @@ -236,8 +276,30 @@ def __init__(self, *args, **kwargs): self.__API_VERSION_ID = "$Id$" - def get_parent(self): - return self._parent + def get_parent(self, cls=None): + if cls is None: + return self._parent + + if self._parent is None: + return None + + _p = self._parent + while isinstance(_p, BaseValidator): + if isinstance(_p, cls): + break + _t = _p._parent + if _t is None: + break + _p = _t + + assert _p is not None + if isinstance(_p, cls): + return _p + + log.error("Sorry: could not find parent of specified class ({0})!" + "Found top is of type: {1}".format(cls, type(_p))) + return None + def get_api_version(self): return self.__API_VERSION_ID @@ -712,6 +774,8 @@ def __init__(self, *args, **kwargs): def validate(self, d): """check whether data is a valid URI""" + global PEDANTIC + if d is None: d = self._default_input_data @@ -842,27 +906,14 @@ def __init__(self, *args, **kwargs): super(AutoDetectionScript, self).__init__(*args, **kwargs) self._default_data = '' - def validate(self, d): - """check whether data is a valid script""" - - if d is None: - d = self._default_data - - if (d is None) or (d == '') or (d == text_type('')): - self.set_data(text_type('')) - return True - script = '' - try: - script = StringValidator.parse(d, parent=self, parsed_result_is_data=True) + def check_script(self, script): + global PEDANTIC - if not bool(script): # NOTE: empty script is also fine! - self.set_data(script) - return True - except: - log.error("Wrong input to AutoDetectionScript::validate: {}". format(d)) - return False + assert script is not None + _ret = True + log.debug('Checking auto-detection script: {}'.format(script)) # NOTE: trying to check the BASH script: shellcheck & bash -n 'string': fd, path = tempfile.mkstemp() @@ -873,28 +924,66 @@ def validate(self, d): _cmd = ["bash", "-n", path] try: # NOTE: Check for valid bash script - subprocess.check_call(_cmd) # stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) - _ret = True + retcode = _execute(_cmd) except: - print("WARNING: error running 'bash -n' to check '{0}' (exit code: {1})!" . format(text_type(script), sys.exc_info())) - _ret = not PEDANTIC # TODO: add a special switch? + log.exception("Error while running '{}' to check auto-detection script!".format(' '.join(_cmd))) + return False # if PEDANTIC: # TODO: add a special switch? + + if retcode != 0: + log.error("Error while running '{0}' to check auto-detection script: {1}!".format(' '.join(_cmd), retcode)) + return False # NOTE: additionall tool: shellcheck (haskell!) + # FIXME: what if this tool is missing!? TODO: Check for it once! _cmd = ["shellcheck", "-s", "bash", path] try: # NOTE: Check for valid bash script - subprocess.check_call(_cmd) # stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w')) - _ret = True + retcode = _execute(_cmd) except: - print("WARNING: error running 'shellcheck' to check '{0}' (exit code: {1})!".format(text_type(script), sys.exc_info())) - _ret = not PEDANTIC # TODO: add a special switch? + log.exception("Error while running '{}' to check auto-detection script!".format(' '.join(_cmd))) + return False + + if retcode != 0: + log.error("Error while running '{0}' to check auto-detection script: {1}!".format(' '.join(_cmd), retcode)) + return False finally: os.remove(path) - if _ret: - self.set_data(script) + return True + + def validate(self, d): + """check whether data is a valid script""" + + global PEDANTIC + + if d is None: + d = self._default_data + + if (d is None) or (d == '') or (d == text_type('')): + self.set_data(text_type('')) + return True + + script = '' + try: + script = StringValidator.parse(d, parent=self, parsed_result_is_data=True) + + if not bool(script): # NOTE: empty script is also fine! + self.set_data(script) + return True + except: + log.exception("Wrong input to AutoDetectionScript::validate: {}". format(d)) + return False + + + if not self.check_script(script): + if PEDANTIC: + log.error("Bad script: {0}".format(script)) + return False + else: + log.warning("Bad script: {0}".format(script)) + self.set_data(script) return True @@ -951,9 +1040,6 @@ def validate(self, d): ############################################################### -import subprocess # , shlex -# import paramiko - class HostAddress(StringValidator): """SSH alias""" @@ -963,43 +1049,118 @@ def __init__(self, *args, **kwargs): def validate(self, d): """check whether data is a valid ssh alias?""" + global PEDANTIC + if d is None: d = self._default_data - _h = StringValidator.parse(d, parent=self) + _h = StringValidator.parse(d, parent=self, parsed_result_is_data=True) - if not self.check_ssh_alias(_h): - if PEDANTIC: + if _h.startswith("'") and _h.endswith("'"): + _h = _h[1:-1] + if _h.startswith('"') and _h.endswith('"'): + _h = _h[1:-1] + + if PEDANTIC: + if not self.check_ssh_alias(_h, shell=False, timeout=2): return False self.set_data(_h) return True + def get_ip_address(self): + pass + + def get_address(self): + return self.get_data() + def recheck(self): - return self.check_ssh_alias(self.set_data()) + return self.check_ssh_alias(self.get_address()) + + # TODO: check/use SSH/SCP calls! + def scp(self, source, target, **kwargs): + global PEDANTIC + + assert self.recheck() + _h = self.get_address() # 'jabberwocky' # + + _cmd = shlex.split("scp -q -F {3} {0} {1}:{2}".format(source, _h, target, os.path.join(os.environ['HOME'], ".ssh", "config"))) + __cmd = ' '.join(_cmd) + + # client = paramiko.SSHClient() + # client.load_system_host_keys() + try: + retcode = _execute(_cmd, **kwargs) + except: + log.exception("Could not execute '{0}'! Exception: {1}".format(__cmd, sys.exc_info())) + if not PEDANTIC: + return + raise + + assert retcode is not None + if not retcode: + log.debug("Command ({}) execution success!".format(__cmd)) + return + else: + log.error("Could not run scp command: '{0}'! Return code: {1}".format(__cmd, retcode)) + if PEDANTIC: + raise Exception("Could not run scp command: '{0}'! Exception: {1}".format(__cmd, sys.exc_info())) + + def ssh(self, cmd, **kwargs): + global PEDANTIC + + assert self.recheck() + _h = self.get_address() # 'jabberwocky' + + # TODO: maybe respect SSH Settings for the parent station!? + + _cmd = shlex.split("ssh -q -F {2} {0} {1}".format(_h, ' '.join(cmd), os.path.join(os.environ['HOME'], ".ssh", "config"))) + __cmd = ' '.join(_cmd) + + # client = paramiko.SSHClient() + # client.load_system_host_keys() + try: + retcode = _execute(_cmd, **kwargs) + except: + log.exception("Could not execute '{0}'! Exception: {1}".format(__cmd, sys.exc_info())) + raise + + assert retcode is not None + if not retcode: + log.debug("Command ({}) execution success!".format(__cmd)) + return + else: + log.error("Could not run remote ssh command: '{0}'! Return code: {1}".format(__cmd, retcode)) +# if PEDANTIC: + raise Exception("Could not run remote ssh command: '{0}'! Exception: {1}".format(__cmd, sys.exc_info())) - ## SSH call? @classmethod - def check_ssh_alias(cls, _h): + def check_ssh_alias(cls, _h, **kwargs): """Check for ssh alias""" + global PEDANTIC log.debug("Checking ssh alias: '{0}'...".format(text_type(_h))) try: # client = paramiko.SSHClient() # client.load_system_host_keys() - _cmd = ["ssh", "-o", "ConnectTimeout=1", _h, "exit 0"] - subprocess.check_call(_cmd, stdout=open("/dev/null", 'w')) # , stderr=open("/dev/null", 'w') - log.debug("Ssh alias '{0}' is functional!" . format(text_type(_h))) + _cmd = ["ssh", "-q", "-F", os.path.join(os.environ['HOME'], ".ssh", "config"), "-o", "ConnectTimeout=1", _h, "exit 0"] + retcode = _execute(_cmd, **kwargs) # , stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w') - return True - except subprocess.CalledProcessError as err: - log.warning("Non-functional ssh alias: '{0}' => exit code: {1}!" . format(text_type(_h), err.returncode)) - except: # Any other exception is wrong... - log.warning("Non-functional ssh alias: '{0}'. Moreover: Unexpected error: {1}" . format(text_type(_h), sys.exc_info())) + if retcode: + log.warning("Non-functional ssh alias: '{0}' => exit code: {1}!".format(text_type(_h), retcode)) + else: + log.debug("Ssh alias '{0}' is functional!" . format(text_type(_h))) + + return retcode == 0 + except: + log.exception("Non-functional ssh alias: '{0}'. Moreover: Unexpected error: {1}" . format(text_type(_h), sys.exc_info())) + if PEDANTIC: + raise + + return False - return False ############################################################### class HostMACAddress(StringValidator): @@ -1082,7 +1243,7 @@ def validate(self, d): assert self._default_type is not None assert self._default_type in self._types - _rule = self._types[self._default_type] # Version dependent! + _rule = self._types[self._default_type] # Version dependent! assert _rule is not None assert self._type_cls is not None @@ -1094,7 +1255,7 @@ def validate(self, d): t = None try: - t = self._type_cls.parse(d[self._type_tag], parent=self.get_parent()) # parsed_result_is_data=True? + t = self._type_cls.parse(d[self._type_tag], parent=self.get_parent(), parsed_result_is_data=True) except: log.exception("Wrong type data: {}".format(d[self._type_tag])) return False @@ -1104,7 +1265,7 @@ def validate(self, d): _key_error(self._type_tag, t, _lc, "ERROR: unsupported/wrong variadic type: '{}'") return False - tt = _rule[t](self) + tt = _rule[t](parent=self.get_parent()) if not tt.validate(d): _lc = d.lc.key(self._type_tag) @@ -1123,11 +1284,12 @@ def __init__(self, *args, **kwargs): super(StationPowerOnMethodWrapper, self).__init__(*args, **kwargs) T = StationPowerOnMethodType + self._type_cls = T - _wol = {T.parse("WOL"): WOL, T.parse("DockerMachine"): DockerMachine} + _wol_dm = {T.parse("WOL", parsed_result_is_data=True): WOL, T.parse("DockerMachine", parsed_result_is_data=True): DockerMachine} - self._default_type = "default_WOL_poweron_method_wrapper" - self._types[self._default_type] = _wol + self._default_type = "default_poweron_wrapper" + self._types[self._default_type] = _wol_dm ############################################################### @@ -1139,7 +1301,7 @@ def __init__(self, *args, **kwargs): T = ServiceType self._type_cls = T - _dc = {T.parse("compose"): DockerComposeService} + _dc = {T.parse("compose", parsed_result_is_data=True): DockerComposeService} self._default_type = "default_docker_compose_service_wrapper" self._types[self._default_type] = _dc @@ -1154,7 +1316,7 @@ def __init__(self, *args, **kwargs): t = ServiceType # NOTE: same for docker-compose Services and Applications! self._type_cls = t - _dc = {t.parse("compose"): DockerComposeApplication} + _dc = {t.parse("compose", parsed_result_is_data=True): DockerComposeApplication} self._default_type = "default_docker_compose_application_wrapper" self._types[self._default_type] = _dc @@ -1164,58 +1326,158 @@ def __init__(self, *args, **kwargs): class DockerMachine(BaseRecordValidator): """DockerMachine :: StationPowerOnMethod""" + # _DM = 'docker-machine' + _HILBERT_STATION = '~/bin/hilbert-station' # TODO: look at station for this..? + def __init__(self, *args, **kwargs): super(DockerMachine, self).__init__(*args, **kwargs) self._type_tag = text_type('type') + self._vm_host_address_tag = text_type('vm_host_address') + self._vm_name_tag = text_type('vm_name') self._default_type = 'DockerMachine' DM_rule = { self._type_tag: (True, StationPowerOnMethodType), # Mandatory! text_type('auto_turnon'): (False, AutoTurnon), - text_type('vm_name'): (True, StringValidator), - text_type('vm_host_address'): (True, HostAddress) + self._vm_name_tag: (True, StringValidator), + self._vm_host_address_tag: (True, HostAddress) } self._types = {self._default_type: DM_rule} # ! NOTE: AMT - maybe later... + def get_vm_name(self): + _d = self.get_data() + assert _d is not None + _a = _d.get(self._vm_name_tag, None) + if (_a is None) or (not bool(_a)): + log.error('Missing vm_name!') + raise Exception('Missing vm_name!') - def run_action(self, action, action_args): - assert action == 'poweron' + if _a.startswith("'") and _a.endswith("'"): + _a = _a[1:-1] + if _a.startswith('"') and _a.endswith('"'): + _a = _a[1:-1] + + return _a + + + def get_vm_host_address(self): + _d = self.get_data() + assert _d is not None + _a = _d.get(self._vm_host_address_tag, None) + if (_a is None) or (not bool(_a)): + log.error('Missing vm_host_address!') + raise Exception('Missing vm_host_address!') + + return _a + + def start(self): # , action, action_args): + global PEDANTIC + + _a = self.get_vm_host_address() + assert _a is not None + assert isinstance(_a, HostAddress) + + _n = self.get_vm_name() + + # DISPLAY =:0 + _cmd = [self._HILBERT_STATION, 'dm_start', _n] # self._DM + try: + _ret = _a.ssh(_cmd, shell=True) + except: + s = "Could not power-on virtual station {0} (at {1})".format(_n, _a) + if not PEDANTIC: + log.warning(s) + return False + else: + log.exception(s) + raise + + return _ret # process call: ssh to vm_host + docker-machione start vm_id - raise NotImplementedError("Running 'docker-machine start' action is not supported yet... Sorry!") +# raise NotImplementedError("Running 'docker-machine start' action is not supported yet... Sorry!") class WOL(BaseRecordValidator): """WOL :: StationPowerOnMethod""" + _WOL = 'wakeonlan' + def __init__(self, *args, **kwargs): super(WOL, self).__init__(*args, **kwargs) self._type_tag = text_type('type') self._default_type = 'WOL' + self._MAC_tag = text_type('mac') WOL_rule = { self._type_tag: (True, StationPowerOnMethodType), # Mandatory! text_type('auto_turnon'): (False, AutoTurnon), - text_type('mac'): (True, HostMACAddress) + self._MAC_tag: (True, HostMACAddress) } self._types = {self._default_type: WOL_rule} - def run_action(self, action, action_args): - assert action == 'poweron' + def get_MAC(self): + _d = self.get_data() + assert _d is not None + _MAC = _d.get(self._MAC_tag, None) + assert _MAC is not None + assert _MAC != '' + return _MAC + + + + def start(self): # , action, action_args): + global PEDANTIC + + _address = None + _parent = self.get_parent(cls=Station) - # process call: wakeonlan + mac + IP address (get from parent's ssh alias!?) - raise NotImplementedError("Running 'WOL' action is not supported yet... Sorry!") + if _parent is not None: + if isinstance(_parent, Station): + _address = _parent.get_address() + assert _address is not None + assert isinstance(_address, HostAddress) + _address = _address.get_address() + + _MAC = self.get_MAC() + + if (_address is None) or (_address == ''): + log.warning("Sorry: could not get station's address for this WOL MethodObject!") + _cmd = [self._WOL, _MAC] + if PEDANTIC: + raise Exception("Sorry: could not get station's address for this WOL MethodObject!") + else: + _cmd = [self._WOL, "-i", _address, _MAC] # IP? + + __cmd = ' '.join(_cmd) + try: + retcode = _execute(_cmd, shell=False) + assert retcode is not None + if not retcode: + log.debug("Command ({}) execution success!".format(__cmd)) + return + else: + log.error("Could not poweron via '{0}'! Return code: {1}".format(__cmd, retcode)) + if PEDANTIC: + raise Exception("Could not execute '{0}'! Exception: {1}".format(__cmd, sys.exc_info())) + except: + log.exception("Could not execute '{0}'! Exception: {1}".format(__cmd, sys.exc_info())) + if not PEDANTIC: + return + raise ############################################################### class DockerComposeService(BaseRecordValidator): """DockerCompose :: Service data type""" + _DC = "docker-compose" + def __init__(self, *args, **kwargs): super(DockerComposeService, self).__init__(*args, **kwargs) @@ -1236,11 +1498,47 @@ def __init__(self, *args, **kwargs): self._create_optional = True + def check_service(self, _f, _n): + global PEDANTIC + + # TODO: Check the corresponding file for such a service -> Service in DockerService! + fd, path = tempfile.mkstemp() + try: + with os.fdopen(fd, 'w') as tmp: + _cmd = [self._DC, "-f", _f, "config"] # TODO: use '--services'? + try: + retcode = _execute(_cmd, shell=False, stdout=tmp, stderr=open("/dev/null", 'w')) + except: + log.exception("Exception while running '{}'!".format(' '.join(_cmd))) + return False +# _ret = not PEDANTIC # TODO: add a special switch? + + if retcode: + return False + + with open(path, 'r') as tmp: + dc = load_yaml(tmp) # NOTE: loading external Docker-Compose's YML file using our validating loader! + ss = None + for k in dc['services']: + if k == _n: + ss = dc['services'][k] + break + + if ss is None: + log.error("missing service/application '{}' in file '{}' !".format(_n, _f)) + return False + finally: + os.remove(path) + + return True + def validate(self, d): + global PEDANTIC + if d is None: d = self._default_input_data - if not BaseRecordValidator.validate(self, d): + if not BaseRecordValidator.validate(self, d): # TODO: use .parse? assert self.get_data() is None return False @@ -1263,38 +1561,14 @@ def validate(self, d): log.warning("Missing file with docker-compose configuration: '{0}'. Cannot check the service reference id: '{1}'" .format(_f, _n)) return True + if not self.check_service(_f, _n): + if PEDANTIC: + log.error("Bad service {0} in {1}".format(_n, _f)) + return False + else: + log.warning("Bad service {0} in {1}".format(_n, _f)) - # TODO: Check the corresponding file for such a service -> Service in DockerService! - - DC = "docker-compose" - - fd, path = tempfile.mkstemp() - try: - with os.fdopen(fd, 'w') as tmp: - _cmd = [DC, "-f", _f, "config"] # TODO: use '--services'? - try: - subprocess.check_call(_cmd, stdout=tmp, stderr=open("/dev/null", 'w')) - _ret = True - except: - print("WARNING: error running '{}' to check '{}' (exit code: {})!".format(DC, _f, sys.exc_info())) - _ret = not PEDANTIC # TODO: add a special switch? - - with open(path, 'r') as tmp: - dc = load_yaml(tmp) # NOTE: loading external Docker-Compose's YML file using our validating loader! - ss = None - for k in dc['services']: - if k == _n: - ss = dc['services'][k] - break - - if ss is None: - print("ERROR: missing service/application '{}' in file '{}' !".format(_n, _f)) - _ret = False - finally: -# print(path) - os.remove(path) - - return _ret + return True # _ret ############################################################### @@ -1377,6 +1651,8 @@ class Station(BaseRecordValidator): # Wrapper? _extends_tag = text_type('extends') _client_settings_tag = text_type('client_settings') + _HILBERT_STATION = '~/bin/hilbert-station' + def __init__(self, *args, **kwargs): super(Station, self).__init__(*args, **kwargs) @@ -1384,26 +1660,29 @@ def __init__(self, *args, **kwargs): self._ssh_options_tag = text_type('ssh_options') self._address_tag = text_type('address') self._ishidden_tag = text_type('hidden') + self._profile_tag = text_type('profile') self._default_type = "default_station" default_rule = { - self._extends_tag: (False, StationID), + Station._extends_tag: (False, StationID), text_type('name'): (True, BaseUIString), text_type('description'): (True, BaseUIString), text_type('icon'): (False, Icon), - text_type('profile'): (True, ProfileID), + self._profile_tag: (True, ProfileID), self._address_tag: (True, HostAddress), self._poweron_tag: (False, StationPowerOnMethodWrapper), # !! variadic, PowerOnType... self._ssh_options_tag: (False, StationSSHOptions), # !!! record: user, port, key, key_ref text_type('omd_tag'): (True, StationOMDTag), # ! like ServiceType: e.g. agent. Q: Is this mandatory? self._ishidden_tag: (False, StationVisibility), # Q: Is this mandatory? - self._client_settings_tag: (False, StationClientSettings) # IDMap : (BaseID, BaseString) + Station._client_settings_tag: (False, StationClientSettings) # IDMap : (BaseID, BaseString) } # text_type('type'): (False, StationType), # TODO: ASAP!!! self._types = {self._default_type: default_rule} self._compatible_applications = None # TODO: FIXME! + self._HILBERT_STATION = '~/bin/hilbert-station' + def is_hidden(self): _d = self.get_data() assert _d is not None @@ -1415,43 +1694,173 @@ def is_hidden(self): return _h - def get_address(self): + def get_profile(self): _d = self.get_data() assert _d is not None + _profile_id = _d.get(self._profile_tag, None) + + assert _profile_id is not None + assert _profile_id != '' - return _d.get(self._address_tag, None) + _parent = self.get_parent(cls=Hilbert) + assert isinstance(_parent, Hilbert) - def shutdown(self, action_args): - ### ssh address subprocess - raise NotImplementedError("Cannot shutdown this station!") + _profile = _parent.query('Profiles/{}/all' . format(_profile_id)) + assert _profile is not None + assert isinstance(_profile, Profile) + return _profile - def deploy(self, action_args): - ### see existing deploy.sh!? - raise NotImplementedError("Cannot deploy local configuration to this station!") + def get_address(self): # TODO: IP? + _d = self.get_data() + assert _d is not None + _a = _d.get(self._address_tag, None) + if (_a is None) or (not bool(_a)): + log.error('Missing station address!') + raise Exception('Missing station address!') - def start_service(self, action_args): - raise NotImplementedError("Cannot start a service/application on this station!") + assert isinstance(_a, HostAddress) - def finish_service(self, action_args): - raise NotImplementedError("Cannot finish a service/application on this station!") + log.debug('HostAddress: {}'.format(_a)) + return _a - def app_switch(self, action_args): - raise NotImplementedError("Cannot switch an application on this station!") + def shutdown(self): + global PEDANTIC + + _a = self.get_address() + + assert _a is not None + assert isinstance(_a, HostAddress) + + try: + _ret = _a.ssh([self._HILBERT_STATION, "stop"], shell=False) + except: + s = "Could not shutdown station {}".format(_a) + if not PEDANTIC: + log.warning(s) + return False + else: + log.exception(s) + raise - def poweron(self, action_args): + return _ret + + def deploy(self): + global PEDANTIC + + + # TODO: get_client_settings() _d = self.get_data() - assert _d is not None + _settings = _d.get(self._client_settings_tag, None) + + if _settings is None: + if not PEDANTIC: + log.warning('Missing client settings for this station. Nothing to deploy!') + else: + log.error('Missing client settings for this station. Nothing to deploy!') + raise Exception('Missing client settings for this station. Nothing to deploy!') + + if isinstance(_settings, BaseValidator): + _settings = _settings.get_data() + + default_app_id = _settings.get('hilbert_station_default_application', None) + # check default_app_id! + + _profile = self.get_profile() + if isinstance(_profile, BaseValidator): + _profile = _profile.get_data() + + # All supported applications??!? + _services = _profile.get(text_type('services'), []) + assert _services is not None + if isinstance(_services, BaseValidator): + _services = _services.get_data() + + assert isinstance(_services, list) + + _a = self.get_address() + + assert _a is not None + assert isinstance(_a, HostAddress) + + fd, path = tempfile.mkstemp() + try: + with os.fdopen(fd, 'w') as tmp: + tmp.write("hilbert_station_profile_services=({})\n".format(' '.join(_services))) + for k in _settings: + tmp.write("{0}='{1}'\n".format(k, str(_settings.get(k, '')))) + +# _cmd = ["scp", path, "{0}:/tmp/{1}".format(_a, os.path.basename(path))] # self._HILBERT_STATION, 'deploy' + + try: + _a.scp(path, "/tmp/{}".format(os.path.basename(path)), shell=False) + except: + s = "Could not deploy new local settings to {}".format(_a) + if not PEDANTIC: + log.warning(s) + return False + else: + log.exception(s) + raise + finally: + os.remove(path) + + _cmd = [self._HILBERT_STATION, "prepare", os.path.join("/tmp", os.path.basename(path))] + try: + _a.ssh(_cmd, shell=False) + except: + s = "Could not prepare the station using the new configuration file with {}".format(' '.join(_cmd)) + if not PEDANTIC: + log.warning(s) + return False + else: + log.exception(s) + raise + + # ### see existing deploy.sh!? + # TODO: what about other external resources? docker-compose*.yml etc...? + # TODO: restart hilbert-station? + +# raise NotImplementedError("Cannot deploy local configuration to this station!") - if not self._poweron_tag in _d: - log.error("Cannot Power-On this station since the corresponding method is missing!") - raise NotImplementedError("Cannot Power-On this station!") +# def start_service(self, action_args): +# raise NotImplementedError("Cannot start a service/application on this station!") + +# def finish_service(self, action_args): +# raise NotImplementedError("Cannot finish a service/application on this station!") + + def app_switch(self, app_id): + global PEDANTIC + + _a = self.get_address() + + assert _a is not None + assert isinstance(_a, HostAddress) + + try: + _ret = _a.ssh([self._HILBERT_STATION, "app_switch", app_id], shell=False) + except: + s = "Could not change top application on the station '{0}' to '{1}'".format(_a, app_id) + if not PEDANTIC: + log.warning(s) + return False + else: + log.exception(s) + raise + + return _ret + +# raise NotImplementedError("Cannot switch to a different application on this station!") + + def poweron(self): + _d = self.get_data() + assert _d is not None - poweron = _d[self._poweron_tag] + poweron = _d.get(self._poweron_tag, None) if poweron is None: - log.error("Cannot Power-On this station since the corresponding method was not specified properly!") - raise NotImplementedError("Cannot Power-On this station!") + log.error("Missing/wrong Power-On Method configuration for this station!") + raise Exception("Missing/wrong Power-On Method configuration for this station!") - poweron.run_action('poweron', action_args) # ???? + poweron.start() # , action_args???? def run_action(self, action, action_args): """ @@ -1459,31 +1868,33 @@ def run_action(self, action, action_args): :param action_args: arguments to the action :param action: - poweron [] - shutdown [] - deploy [] - start [] - finish [] - app_switch + start (poweron) + stop (shutdown) + cfg_deploy + app_change +# start [] +# finish [] :return: nothing. """ - if action == 'poweron': - self.poweron(action_args) - elif action == 'shutdown': - self.shutdown(action_args) - elif action == 'deploy': - self.deploy(action_args) - elif action == 'start': - self.start_service(action_args) - elif action == 'finish': - self.finish_service(action_args) - elif action == 'app_switch': - self.app_switch(action_args) + if action not in ['start', 'stop', 'cfg_deploy', 'app_change']: + raise Exception("Running action '{0}({1})' is not supported!" . format(action, action_args)) # Run 'ssh address hilbert-station action action_args'?! - raise NotImplementedError("Running action '{0} {1}' is not supported yet... Sorry!" . format(action, action_args)) + if action == 'start': + self.poweron() # action_args + elif action == 'cfg_deploy': + self.deploy() # action_args + elif action == 'stop': + self.shutdown() # action_args + elif action == 'app_change': + self.app_switch(action_args) # ApplicationID + +# elif action == 'start': +# self.start_service(action_args) +# elif action == 'finish': +# self.finish_service(action_args) def get_base(self): diff --git a/tools/hilbert-station b/tools/hilbert-station new file mode 100755 index 0000000..18f3ec5 --- /dev/null +++ b/tools/hilbert-station @@ -0,0 +1,24 @@ +#! /usr/bin/env bash + +TOOL=$(basename "$0") + +CONFIG_DIR="${CONFIG_DIR:-${HOME}/.config/${TOOL}}" +mkdir -p "${CONFIG_DIR}" + +CLI_VERSION_ID="\$Id$" + +echo "DEBUG [${TOOL}]: This tool: [$0]" +echo "DEBUG [${TOOL}]: Version: [${CLI_VERSION_ID}]" + +echo "DEBUG [${TOOL}]: Workdir: [${PWD}]" +echo "DEBUG [${TOOL}]: Config Dir: [${CONFIG_DIR}]" +echo "DEBUG [${TOOL}]: Configs: ($(ls ${CONFIG_DIR} | xargs))" + + +echo "DEBUG [${TOOL}]: Host: [`hostname`]" +echo "DEBUG [${TOOL}]: System: [`uname -a`]" + +echo "DEBUG [${TOOL}]: Input args: ($@)" +echo "ERROR [${TOOL}]: not yet implemented!" +exit 2 + diff --git a/tools/hilbert.py b/tools/hilbert.py index 169fb5a..cd8e492 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -28,6 +28,9 @@ import logging log = logging.getLogger(__name__) # +__CLI_VERSION_ID = "$Id$" + + #import traceback #def main_exception_handler(type, value, tb): # log.exception("Uncaught exception! Type: {0}, Value: {1}, TB: {2}".format(type, value, traceback.format_tb(tb))) From fc5a172d4072e8d2752a588b39f06039796e64dc Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Thu, 1 Dec 2016 19:31:24 +0100 Subject: [PATCH 38/42] Added dummy CLI to the client side tool Usage output: hilbert-station - Station part for Linux systems Usage: hilbert-station -h Display this help message. hilbert-station -v Increase verbosity hilbert-station -q Decrease verbosity hilbert-station -p Pedantic mode hilbert-station -V Display version info. hilbert-station start Start everything hilbert-station stop Stop everything and shutdown hilbert-station prepare Install a new local configuration hilbert-station app_switch Change the currently running top application to specified one hilbert-station dm_start Start a VM using docker-machine --- tools/hilbert-station | 154 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 143 insertions(+), 11 deletions(-) diff --git a/tools/hilbert-station b/tools/hilbert-station index 18f3ec5..1157dc1 100755 --- a/tools/hilbert-station +++ b/tools/hilbert-station @@ -1,24 +1,156 @@ #! /usr/bin/env bash TOOL=$(basename "$0") +LOGLEVEL=0 -CONFIG_DIR="${CONFIG_DIR:-${HOME}/.config/${TOOL}}" -mkdir -p "${CONFIG_DIR}" +HILBERT_CONFIG_DIR="${HILBERT_CONFIG_DIR:-${HOME}/.config/${TOOL}}" +mkdir -p "${HILBERT_CONFIG_DIR}" CLI_VERSION_ID="\$Id$" -echo "DEBUG [${TOOL}]: This tool: [$0]" -echo "DEBUG [${TOOL}]: Version: [${CLI_VERSION_ID}]" +usage () { + echo "${TOOL} - Station part for Linux systems" + echo "Usage: " + echo " ${TOOL} -h Display this help message." + echo " ${TOOL} -v Increase verbosity" + echo " ${TOOL} -q Decrease verbosity" + echo " ${TOOL} -p Pedantic mode" + echo " ${TOOL} -V Display version info." + echo " ${TOOL} start Start everything" + echo " ${TOOL} stop Stop everything and shutdown" + echo " ${TOOL} prepare Install a new local configuration" + echo " ${TOOL} app_switch Change the currently running top application to specified one" + echo " ${TOOL} dm_start Start a VM using docker-machine" # on the VM host system +} -echo "DEBUG [${TOOL}]: Workdir: [${PWD}]" -echo "DEBUG [${TOOL}]: Config Dir: [${CONFIG_DIR}]" -echo "DEBUG [${TOOL}]: Configs: ($(ls ${CONFIG_DIR} | xargs))" +version () { + echo "DEBUG [${TOOL}]: This tool: [$0]" + echo "DEBUG [${TOOL}]: Version: [${CLI_VERSION_ID}]" + echo "DEBUG [${TOOL}]: Workdir: [${PWD}]" + echo "DEBUG [${TOOL}]: Config Dir: [${HILBERT_CONFIG_DIR}]" + echo "DEBUG [${TOOL}]: Configs: ($(ls ${HILBERT_CONFIG_DIR} | xargs))" + + echo "DEBUG [${TOOL}]: Host: [`hostname`]" + echo "DEBUG [${TOOL}]: System: [`uname -a`]" +} + + +cmd_prepare () { + subcommand="prepare" + arg=$1; shift + + if [[ -z ${arg} ]]; then + echo "ERROR [${TOOL}]: Wrong argument '${arg}' to '${subcommand}'!" 1>&2 + usage + exit 1 + fi + + echo "ERROR [${TOOL}]: Sorry '${subcommand} ${arg} [$*]' not yet implemented!" + exit 2 +} +cmd_app_change () { + subcommand="app_change" + arg=$1; shift + + if [[ -z ${arg} ]]; then + echo "ERROR [${TOOL}]: Wrong argument '${arg}' to '${subcommand}'!" 1>&2 + usage + exit 1 + fi + + echo "ERROR [${TOOL}]: Sorry '${subcommand} ${arg} [$*]' not yet implemented!" + exit 2 +} + +cmd_dm_start () { + subcommand="dm_start" + arg=$1; shift + + if [[ -z ${arg} ]]; then + echo "ERROR [${TOOL}]: Wrong argument '${arg}' to '${subcommand}'!" 1>&2 + usage + exit 1 + fi + + echo "ERROR [${TOOL}]: Sorry '${subcommand} ${arg} [$*]' not yet implemented!" + exit 2 +} + +cmd_start () { + subcommand="start" + echo "ERROR [${TOOL}]: Sorry '$subcommand [$*]' not yet implemented!" + exit 2 +} + +cmd_stop () { + subcommand="stop" + echo "ERROR [${TOOL}]: Sorry '$subcommand [$*]' not yet implemented!" + exit 2 +} -echo "DEBUG [${TOOL}]: Host: [`hostname`]" -echo "DEBUG [${TOOL}]: System: [`uname -a`]" echo "DEBUG [${TOOL}]: Input args: ($@)" -echo "ERROR [${TOOL}]: not yet implemented!" -exit 2 + +while getopts ":hqvpV" opt; do + case ${opt} in + h ) + usage + exit 0 + ;; + V ) + version + exit 0 + ;; + p ) + set -e + ;; + v ) + set -v + set -x + ;; + q ) + set +v + set +x + ;; + \? ) + echo "Invalid Option: -$OPTARG" 1>&2 + exit 1 + ;; + esac +done + +shift $((OPTIND -1)) +subcommand=$1; shift + +echo "DEBUG [${TOOL}]: subcommand to run: '$subcommand'" + +case "$subcommand" in + prepare) + cmd_prepare "$@" + ;; + app_switch|app_change) + cmd_app_change "$@" + ;; + dm_start) + cmd_dm_start "$@" + ;; + stop) + cmd_stop "$@" + ;; + start) + cmd_start "$@" + ;; +esac + +if [[ -z "${subcommand}" ]]; then + usage +else + echo "ERROR [${TOOL}]: Invalid sub-command: '$subcommand'" 1>&2 + exit 1 +fi + +echo "DEBUG [${TOOL}]: Done" + +exit 0 From 7131db82c1bd5d058b164afdf053e56412a68b0f Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Tue, 6 Dec 2016 05:41:39 +0100 Subject: [PATCH 39/42] Improved hilbert tool (Server-side) = changes in config/hilbert_cli_config.py: * _execute, + Host::ssh/Host::scp + Station::type: StationType: [hidden, server, standard?, standalone?] * fixes / logging = extended Hilbert::parse testing (test_validate.py): singleHostHilbert.yml --- config/hilbert_cli_config.py | 193 +++++++++++++------ tests/data/Hilbert.yml.data.pickle | Bin 3379 -> 3379 bytes tests/data/Hilbert.yml.pickle | Bin 0 -> 10610 bytes tests/data/miniHilbert.yml | 6 + tests/data/miniHilbert.yml.data.pickle | Bin 0 -> 124 bytes tests/data/miniHilbert.yml.pickle | Bin 0 -> 1868 bytes tests/data/singleHostHilbert.yml | 104 ++++++++++ tests/data/singleHostHilbert.yml.data.pickle | Bin 0 -> 3839 bytes tests/data/singleHostHilbert.yml.pickle | Bin 0 -> 11387 bytes tests/test_validate.py | 66 ++++--- tools/hilbert.py | 2 +- 11 files changed, 283 insertions(+), 88 deletions(-) create mode 100644 tests/data/Hilbert.yml.pickle create mode 100644 tests/data/miniHilbert.yml create mode 100644 tests/data/miniHilbert.yml.data.pickle create mode 100644 tests/data/miniHilbert.yml.pickle create mode 100644 tests/data/singleHostHilbert.yml create mode 100644 tests/data/singleHostHilbert.yml.data.pickle create mode 100644 tests/data/singleHostHilbert.yml.pickle diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index 4a0b2cc..b16d9f2 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -318,7 +318,7 @@ def get_data(self): def set_version(cls, v): """To be set once only for any Validator class!""" assert len(cls.__version) == 1 - assert cls.__version[0] is None +# assert cls.__version[0] is None # NOTE: bad for testing! cls.__version[0] = v @classmethod @@ -345,6 +345,8 @@ def parse(cls, d, *args, **kwargs): """ self = cls(*args, **kwargs) + log.debug("{1}::parse( input type: {0} )".format(type(d), type(self))) + if self.validate(d): # NOTE: validate should not **explicitly** throw exceptions!!! if self._parsed_result_is_data: return self.get_data() @@ -609,7 +611,7 @@ def validate(self, d): if d is not None: if isinstance(d, (list, dict, tuple, set)): # ! Check if data is not a container? - print("ERROR: value: '{}' is not a scalar value!!" . format(d)) + log.error("value: '{}' is not a scalar value!!" . format(d)) return False if isinstance(d, string_types): @@ -625,20 +627,20 @@ class StringValidator(ScalarValidator): def __init__(self, *args, **kwargs): super(StringValidator, self).__init__(*args, **kwargs) - self._default_data = '' + self._default_input_data = '' def validate(self, d): """check whether data is a valid string. Note: should not care about format version""" if d is None: - d = self._default_data + d = self._default_input_data assert d is not None s = ScalarValidator.parse(d, parent=self) if not isinstance(s, string_types): - print("ERROR: value: '{}' is not a string!!" . format(d)) + log.error("value: '{}' is not a string!!" . format(d)) return False self.set_data(text_type(d)) @@ -648,12 +650,13 @@ def validate(self, d): ############################################################### class SemanticVersionValidator(BaseValidator): def __init__(self, *args, **kwargs): - partial = kwargs.pop('partial', False) + partial = kwargs.pop('partial', True) # kwargs['parsed_result_is_data'] = kwargs.pop('parsed_result_is_data', False) super(SemanticVersionValidator, self).__init__(*args, **kwargs) # self._parsed_result_is_data = False self._partial = partial + self._default_input_data = '0.0.0' def validate(self, d): """check the string data to be a valid semantic version""" @@ -661,7 +664,19 @@ def validate(self, d): if d is None: d = self._default_input_data - _t = StringValidator.parse(d, parent=self, parsed_result_is_data=True) + log.debug("{1}::validate( input type: {0} )".format(type(d), type(self))) +# log.debug("SemanticVersionValidator::validate( input data: {0} )".format(str(d))) + + try: + _t = StringValidator.parse(d, parent=self, parsed_result_is_data=True) + except: + log.warning("Input is not a string: {}".format(d)) + try: + _t = StringValidator.parse(str(d), parent=self, parsed_result_is_data=True) + except: + log.error("Input cannot be converted into a version string: {}".format(d)) + return False + # self.get_version(None) # ??? _v = None @@ -685,13 +700,13 @@ class BaseUIString(StringValidator): def __init__(self, *args, **kwargs): super(BaseUIString, self).__init__(*args, **kwargs) - self._default_data = None + self._default_input_data = None def validate(self, d): """check whether data is a valid (non-empty) string""" if d is None: - d = self._default_data + d = self._default_input_data if not super(BaseUIString, self).validate(d): self.set_data(None) @@ -723,7 +738,7 @@ def validate(self, d): t = StringValidator.parse(d, parent=self, parsed_result_is_data=True) if not (t in self._enum_list): # check withing a list of possible string values - print("ERROR: string value: '{}' is not among known enum items!!".format(d)) + log.error("string value: '{}' is not among known enum items!!".format(d)) return False self.set_data(t) @@ -737,7 +752,7 @@ def __init__(self, *args, **kwargs): compose = text_type('compose') self._enum_list = [compose] # NOTE: 'docker' and others may be possible later on - self._default_data = compose + self._default_input_data = compose ############################################################### @@ -747,7 +762,7 @@ def __init__(self, *args, **kwargs): _v = text_type('standalone') self._enum_list = [text_type('agent'), text_type('windows'), _v] # NOTE: possible values of omd_tag - self._default_data = _v + self._default_input_data = _v ############################################################### @@ -759,7 +774,7 @@ def __init__(self, *args, **kwargs): wol = text_type('WOL') # NOTE: the list of possible values of PowerOnMethod::type (will depend on format version) self._enum_list = [wol, text_type('DockerMachine')] # NOTE: 'AMTvPRO' and others may be possible later on - self._default_data = wol + self._default_input_data = wol ############################################################### @@ -789,7 +804,7 @@ def validate(self, d): try: urlopen(v).close() except: - print("WARNING: URL: '{}' is not accessible!".format(v)) + log.warning("URL: '{}' is not accessible!".format(v)) _ret = not PEDANTIC # TODO: FIXME: base location should be the input file's dirname??? @@ -803,7 +818,7 @@ def validate(self, d): self._type = text_type('dir') if not _ret: - print("WARNING: missing/unsupported resource location: {}".format(v)) + log.warning("missing/unsupported resource location: {}".format(v)) _ret = (not PEDANTIC) if _ret: @@ -827,7 +842,7 @@ def validate(self, d): v = StringValidator.parse(d, parent=self, parsed_result_is_data=True) if not is_valid_id(v): - print("ERROR: not a valid variable identifier! Input: '{}'" . format(d)) + log.error("not a valid variable identifier! Input: '{}'" . format(d)) return False self.set_data(v) @@ -849,12 +864,12 @@ def validate(self, d): _ret = True if not (v == v.lower() or v == v.upper()): # ! Variables are all lower or upper case! - print("ERROR: a variable must be either in lower or upper case! Input: '{}'" . format(d)) + log.error("a variable must be either in lower or upper case! Input: '{}'" . format(d)) _ret = False # NOTE: starting with hilbert_ or HILBERT_ with letters, digits and '_'?? if not re.match('^hilbert(_[a-z0-9]+)+$', v.lower()): - print("ERROR: variable must start with HILBERT/hilbert and contain words separated by underscores!" + log.error("variable must start with HILBERT/hilbert and contain words separated by underscores!" " Input: '{}" .format(d)) _ret = False @@ -904,7 +919,7 @@ def __init__(self, *args, **kwargs): class AutoDetectionScript(StringValidator): def __init__(self, *args, **kwargs): super(AutoDetectionScript, self).__init__(*args, **kwargs) - self._default_data = '' + self._default_input_data = '' def check_script(self, script): @@ -958,7 +973,7 @@ def validate(self, d): global PEDANTIC if d is None: - d = self._default_data + d = self._default_input_data if (d is None) or (d == '') or (d == text_type('')): self.set_data(text_type('')) @@ -996,7 +1011,7 @@ def __init__(self, *args, **kwargs): def validate(self, d): """check whether data is a valid service name in file due to DockerComposeRef""" if d is None: - d = self._default_data + d = self._default_input_data try: n = StringValidator.parse(d, parent=self, parsed_result_is_data=True) @@ -1012,12 +1027,12 @@ class DockerComposeRef(URI): def __init__(self, *args, **kwargs): super(DockerComposeRef, self).__init__(*args, **kwargs) - self._default_data = text_type('docker-compose.yml') + self._default_input_data = text_type('docker-compose.yml') def validate(self, d): """check whether data is a valid docker-compose file name""" if d is None: - d = self._default_data + d = self._default_input_data # TODO: call docker-compose on the referenced file! Currently in DockerService!? @@ -1052,7 +1067,7 @@ def validate(self, d): global PEDANTIC if d is None: - d = self._default_data + d = self._default_input_data _h = StringValidator.parse(d, parent=self, parsed_result_is_data=True) @@ -1173,7 +1188,7 @@ def validate(self, d): """check whether data is a valid ssh alias?""" if d is None: - d = self._default_data + d = self._default_input_data v = StringValidator.parse(d, parent=self) @@ -1197,7 +1212,7 @@ def validate(self, d): d = self._default_input_data if not isinstance(d, bool): - print("ERROR: not a boolean value: '{}'" . format(d)) + log.error("not a boolean value: '{}'" . format(d)) return False self.set_data(d) @@ -1207,13 +1222,13 @@ def validate(self, d): class StationVisibility(BoolValidator): ## "hidden": True / [False] def __init__(self, *args, **kwargs): super(StationVisibility, self).__init__(*args, **kwargs) - self._default_data = False + self._default_input_data = False class AutoTurnon(BoolValidator): # Bool, False def __init__(self, *args, **kwargs): super(AutoTurnon, self).__init__(*args, **kwargs) - self._default_data = False # no powering on by default!? + self._default_input_data = False # no powering on by default!? ############################################################### @@ -1643,6 +1658,21 @@ def validate(self, d): # TODO: Check for ssh connection: Use some Python SSH Wrapper (2/3) return _ret +############################################################### +class StationType(BaseEnum): + """Type of station defines the set of required data fields!""" + + def __init__(self, *args, **kwargs): + super(StationType, self).__init__(*args, **kwargs) + + # NOTE: the list of possible values of Station::type (will depend on format version) + self._default_input_data = text_type('hidden') # NOTE: nothing is required. For extension only! + self._enum_list = [self._default_input_data, + text_type('standalone'), # No remote control via SSH & Hilbert client... + text_type('server'), # Linux with Hilbert client part installed but no remote control! + text_type('standard') # Linux with Hilbert client part installed! + ] # ,text_type('special') + ############################################################### class Station(BaseRecordValidator): # Wrapper? @@ -1650,6 +1680,7 @@ class Station(BaseRecordValidator): # Wrapper? _extends_tag = text_type('extends') _client_settings_tag = text_type('client_settings') + _type_tag = text_type('type') _HILBERT_STATION = '~/bin/hilbert-station' @@ -1659,7 +1690,7 @@ def __init__(self, *args, **kwargs): self._poweron_tag = text_type('poweron_settings') self._ssh_options_tag = text_type('ssh_options') self._address_tag = text_type('address') - self._ishidden_tag = text_type('hidden') + self._ishidden_tag = text_type('hidden') # TODO: deprecate with "fake" station type? self._profile_tag = text_type('profile') self._default_type = "default_station" @@ -1674,8 +1705,9 @@ def __init__(self, *args, **kwargs): self._ssh_options_tag: (False, StationSSHOptions), # !!! record: user, port, key, key_ref text_type('omd_tag'): (True, StationOMDTag), # ! like ServiceType: e.g. agent. Q: Is this mandatory? self._ishidden_tag: (False, StationVisibility), # Q: Is this mandatory? - Station._client_settings_tag: (False, StationClientSettings) # IDMap : (BaseID, BaseString) - } # text_type('type'): (False, StationType), # TODO: ASAP!!! + Station._client_settings_tag: (False, StationClientSettings), # IDMap : (BaseID, BaseString) + Station._type_tag: (False, StationType) + } # self._types = {self._default_type: default_rule} @@ -1763,19 +1795,20 @@ def deploy(self): _settings = _settings.get_data() default_app_id = _settings.get('hilbert_station_default_application', None) - # check default_app_id! + # TODO: check default_app_id! + # TODO: all compatible applications!? _profile = self.get_profile() if isinstance(_profile, BaseValidator): _profile = _profile.get_data() # All supported applications??!? - _services = _profile.get(text_type('services'), []) - assert _services is not None - if isinstance(_services, BaseValidator): - _services = _services.get_data() + _serviceIDs = _profile.get(text_type('services'), []) # TODO: profile.get_services() + assert _serviceIDs is not None + assert isinstance(_serviceIDs, ServiceList) # list of ServiceID - assert isinstance(_services, list) + _serviceIDs = _serviceIDs.get_data() + assert isinstance(_serviceIDs, list) # list of strings (with ServiceIDs)? _a = self.get_address() @@ -1785,11 +1818,22 @@ def deploy(self): fd, path = tempfile.mkstemp() try: with os.fdopen(fd, 'w') as tmp: - tmp.write("hilbert_station_profile_services=({})\n".format(' '.join(_services))) + # TODO: FIXME: list references into docker-compose.yml??? + # TODO: use bash array to serialize all Services/Applications! + # NOTE: Only handles (IDs) are to be used below: + # NOTE: ATM only compose && Application/ServiceIDs == refs to the same docker-compose.yml! + # TODO: NOTE: may differ depending on Station::type! + tmp.write("hilbert_station_profile_services=\"{}\"\n".format(' '.join(_serviceIDs))) for k in _settings: - tmp.write("{0}='{1}'\n".format(k, str(_settings.get(k, '')))) + tmp.write("{0}=\"{1}\"\n".format(k, str(_settings.get(k, '')))) + tmp.write("background_services=\"${hilbert_station_profile_services}\"\n") + tmp.write("default_app=\"${hilbert_station_default_application}\"\n") + # TODO: collect all compatible applications! + tmp.write("possible_apps=\"${default_app}\"\n") + + # TODO: add also all further necessary resources (docker-compose.yml etc) and tar.gz it for deployment?! + # _cmd = ["scp", path, "{0}:/tmp/{1}".format(_a, os.path.basename(path))] # self._HILBERT_STATION, 'deploy' -# _cmd = ["scp", path, "{0}:/tmp/{1}".format(_a, os.path.basename(path))] # self._HILBERT_STATION, 'deploy' try: _a.scp(path, "/tmp/{}".format(os.path.basename(path)), shell=False) @@ -1802,7 +1846,12 @@ def deploy(self): log.exception(s) raise finally: - os.remove(path) + log.debug("Temporary Station Configuration File: {}".format(path)) +# s = '' +# with os.open(path, 'r') as tmp: +# s += tmp.readline() + '\n' +# log.debug("New Station Configuration: {}".format(s)) +# os.remove(path) _cmd = [self._HILBERT_STATION, "prepare", os.path.join("/tmp", os.path.basename(path))] try: @@ -1965,6 +2014,8 @@ def __init__(self, *args, **kwargs): self._default_type = None self._types = {} # type -> (TypeID, Type) + self._default_input_data = {} + def detect_type(self, d): """determine the type of variadic data for the format version""" @@ -1986,7 +2037,12 @@ def validate(self, d): (_id_rule, _rule) = self._types[self._type] - _lc = d.lc # starting position? + try: + _lc = d.lc # starting position? + except: + log.warning("Input data bears no ruamel.yaml line/column data!") + _lc = (0, 0) + (s, c) = _get_line_col(_lc) _d = {} @@ -2157,6 +2213,8 @@ def validate(self, d): # if _ret: # self.set_data(_processed) + # TODO: FIXME: check for required fields after extension only!!! + return _ret @@ -2328,7 +2386,7 @@ def validate(self, d): if d is None: d = self._default_input_data - print("WARNING: Presets are not supported yet!") + log.warning("Presets are not supported yet!") # raise NotImplementedError("Presets are not supported yet!") return True @@ -2363,7 +2421,7 @@ def __init__(self, *args, **kwargs): self._types = {self._default_type: default_rule} - self._default_data = None + self._default_input_data = None @classmethod def parse(cls, d, *args, **kwargs): @@ -2391,8 +2449,9 @@ def parse(cls, d, *args, **kwargs): raise ConfigurationError(u"{}: {}".format("ERROR:", "Invalid data: '{}'!".format(d))) def validate(self, d): + global PEDANTIC if d is None: - d = self._default_data + d = self._default_input_data assert isinstance(d, dict) @@ -2401,27 +2460,45 @@ def validate(self, d): for offset, k in enumerate(d): if k == self._version_tag: if offset != 0: - print("Note: '{}' specified correctly but not ahead of everything else (offset: {})!".format( - self._version_tag, offset)) - _ret = False + if not PEDANTIC: + log.warning("'{}' specified correctly but not ahead of everything else (offset: {})!" + .format(self._version_tag, offset)) + else: + log.error("'{}' specified correctly but not ahead of everything else (offset: {})!" + .format(self._version_tag, offset)) + _ret = False break + if not _ret: + log.error("Wrong Hilbert configuration!") + return _ret + + _d = self.get_data() # NOTE: check uniqueness of keys among (Services/Applications): - _services = d.get(self._services_tag) # Rely on the above and use get_data? - _applications = d.get(self._applications_tag) - for p, k in enumerate(_services): - _lc = _services.lc.key(k) + # TODO: add get_service(s) and get_application(s)? + _services = self.query("{0}/{1}".format(self._services_tag, 'data')) + _applications = self.query("{0}/{1}".format(self._applications_tag, 'data')) # _d.get() + + assert _services is not None + assert _applications is not None + + if (len(_services) > 0) and (len(_applications) > 0): + for p, k in enumerate(_services): + if k in _applications: + log.error("'{}' is both a ServiceID and an ApplicationID:".format(k)) - if k in _applications: - print("Error: '{}' is both a ServiceID and an ApplicationID:".format(k)) - _key_error(k, _services[k], _lc, "Service key: {}") + __services = d.get(self._services_tag) # Rely on the above and use get_data? + __applications = d.get(self._applications_tag) - _alc = _applications.lc.key(k) - _key_error(k, _applications[k], _alc, "Application key: {}") + _key_error(k, __services[k], __services.lc.key(k), "Service key: {}") + _key_error(k, __applications[k], __applications.lc.key(k), "Application key: {}") + + _ret = False # ! TODO: check Uniqueness of keys among (Profiles/Stations/Groups) !!!! - # ! TODO: check for GroupID <-> StationID <-> ProfileID + # ! TODO: check for GroupID <-> StationID <-!=-> ProfileID + return _ret ############################################################### diff --git a/tests/data/Hilbert.yml.data.pickle b/tests/data/Hilbert.yml.data.pickle index 1a3b74b705497f4b4b42763891edbd66b869e7a5..114f28be0dc5e7ba477f123e2b82c7d4b288f1f0 100644 GIT binary patch literal 3379 zcmb7H_j}W35Dt6qRVYIg3U0wl93T+4v{e!l2NFA24t&tMs$zeMRBXwokx{Ca?$EvW z-h1!8|E``+QEb_1pQp($w!YJS@4a{L-TA^?4_abuaZ5{!%&jrK$ZeS8!Q2>|hmXuk z3Fdh)KloN=)U;tnr5x@p+3jBUrKe4=Vvj*uPbIlB9Ny05=0mCGymO&OH( zX%CjWYzbNsj!|wnu)>3tHI%CwPFHJ-v^p4TA~4o!%h;aUmFX^JDA!+iYdR(6@?9w@ z??3loo$Cg4IcflSy$2g&Y&m)u8&nXTU!(Dhs8GhPb81vAM7TF;d@fQEGgYmt_LnZ zF^6re^VmHk=d%NSXQg~!HY39x;=>r*ua<2U_Oi`&rs=+(lroSVl2c0eP)^R~AcoF% z)#1jNe4;R_5!EeYoYiVsFVZu(f=Z;8t}BVm5a3`gbu5+3rFxWpDbqV7^`>ASn~SbX z9QLzybtt-r24zJ~xo^b%*gf(RQocGR!eG*>NBNqRUqMM&>xT z5ZX*uT0LlsQNG41iiYV>!a_;V3o~BC%7`fsRgO9eN7w>%tCGGt={E9}q}pjJH@^S-FB?Wcu95CRyeMqAT+FFZI8BB+o$c1cn``<>CR@3 z_4NkcPp}>T0n{c&TA^RtrR~<@8Wx}5fWrh2)Fn7mOK_GrnPE=|c!j~BavMZt!$}Wv zkp#=p1m~$O3|i)JnO9JJMNyX1qEyyZ8-^lTKE;+II=sLrsbv$3_;gdI8B3r^#&iT# zusF86X*fb$IPPKr2EA68R=hAHuQRh&z*!Hjk6|9y6YV}nb<|^Sn<=}Y5n`dn+l|!8 z8W99N2$Vn4l4Y~P1vxKedZhkrCKc)jZl*G5YEAE5XlU4Vo1p-6i-Lz_|$?xzMo{z-wZQEZg})VDAfF+c zJO1B7aVITKK2j71YD5kfi@Q9yn;cgrM=jH>!aW(=wQ2c4HTfHY4flF*UyLRbSTNl`{gp)ZzE~hy|KEF@7jk$l?gJ&AT zdA0!0%?j}O0=&?K=tXu2^VG}nV!bG2xHE2A{$2YCmgzbIb|PVq5KK<|fc;;fc_+e4 zHJ~py0(-@+U(8?&AL>_vAF)mNlkF6@Y=1TWi6&c{*deyT&t%x^ tE69dlJouF?LrwkW!S6vEp5C+n$j~{TD3)DZv;Hi=U!lJKR$bc_{{az&3_}0_ literal 3379 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 literal 0 HcmV?d00001 diff --git a/tests/data/miniHilbert.yml b/tests/data/miniHilbert.yml new file mode 100644 index 0000000..58218ac --- /dev/null +++ b/tests/data/miniHilbert.yml @@ -0,0 +1,6 @@ +Version: 0.1 +Services: +Profiles: +Stations: +Groups: +Applications: diff --git a/tests/data/miniHilbert.yml.data.pickle b/tests/data/miniHilbert.yml.data.pickle new file mode 100644 index 0000000000000000000000000000000000000000..6d3b5d759f1662a7c85ee5b592c3cd3c65ee5126 GIT binary patch literal 124 zcmZo*sx4&Dh+t!2U~n(WFD)o8WUMV@ir@kA9SaI_GLsWaGV}9_3z=&RSt2-qq5(zu zX_+~x#f7Z3g=`V*K#{Q2qGF($LiPw|AkRS0u#f|+GB~xUEHfFXlC!pu3nEeiHI2Kr Ikf&4+03UTBoB#j- literal 0 HcmV?d00001 diff --git a/tests/data/miniHilbert.yml.pickle b/tests/data/miniHilbert.yml.pickle new file mode 100644 index 0000000000000000000000000000000000000000..69327c1680fab6968bb4577b65586abd5c35a6b9 GIT binary patch literal 1868 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 literal 0 HcmV?d00001 diff --git a/tests/test_validate.py b/tests/test_validate.py index f06d3be..15eb7dc 100644 --- a/tests/test_validate.py +++ b/tests/test_validate.py @@ -33,44 +33,52 @@ 'data', )) -class TestValidate: - def test_1(self, capsys): - global INPUT_DIRNAME +def hilbert_validation(input_yaml_file, data_file): + global INPUT_DIRNAME - g = os.path.join(FIXTURE_DIR, 'Hilbert.yml') - f = os.path.join(FIXTURE_DIR, 'Hilbert.yml.data.pickle') + input_file = os.path.join(FIXTURE_DIR, input_yaml_file) + data_file = os.path.join(FIXTURE_DIR, data_file) - print(g) - print(f) + assert os.path.exists(input_file) + assert os.path.exists(data_file) - assert os.path.exists(g) - assert os.path.exists(f) + # Load Hilbert configuration in YAML format + yml = load_yaml_file(input_file) + assert yml is not None - yml = load_yaml_file(g) - assert yml is not None + # Load previously verified data + d = pickle_load(data_file) + assert d is not None + assert isinstance(d, dict) + cwd = os.getcwd() + try: INPUT_DIRNAME = FIXTURE_DIR + os.chdir(INPUT_DIRNAME) + cfg = parse_hilbert(yml) + finally: + os.chdir(cwd) + + assert cfg is not None + assert isinstance(cfg, Hilbert) - cwd = os.getcwd() - try: - os.chdir(INPUT_DIRNAME) - cfg = parse_hilbert(yml) - finally: - os.chdir(cwd) - - assert cfg is not None - assert isinstance(cfg, Hilbert) - data = cfg.data_dump() + data = cfg.data_dump() + assert isinstance(data, dict) -# print(cfg) -# print(yaml_dump(data)) + # print(cfg) + # print(yaml_dump(data)) + # print(yaml_dump(d)) - d = pickle_load(f) - assert d is not None - assert isinstance(d, dict) + # NOTE: Main check: + assert data == d # Compare dictionaries with simple data! - assert type(data) == type(d) -# print(yaml_dump(d)) +class TestValidate: + def test_minimal_sample(self, capsys): + hilbert_validation('miniHilbert.yml', 'miniHilbert.yml.data.pickle') + + def test_sample(self, capsys): + hilbert_validation('Hilbert.yml', 'Hilbert.yml.data.pickle') - assert data == d + def test_single(self, capsys): + hilbert_validation('singleHostHilbert.yml', 'singleHostHilbert.yml.data.pickle') diff --git a/tools/hilbert.py b/tools/hilbert.py index cd8e492..1711ce4 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -153,7 +153,7 @@ def cmd_list(parser, context, args, obj): return cfg.query(obj) -@subcmd('cfg_query', help='query some part of configuraton. possibly dump it to a file') +@subcmd('cfg_query', help='query some part of configuration. possibly dump it to a file') def cmd_query(parser, context, args): log.debug("Running '{}'" . format('cfg_query')) From 7ddb63835a61886fc1687af988916dd689fa48f0 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Tue, 6 Dec 2016 05:43:18 +0100 Subject: [PATCH 40/42] Client-side hilbert-station tool Added locking, SubCommands use legacy client scripts Updated client scripts: prepare/default/finishall/luncher seem to work TODO: check.fix topswitch.sh! --- station/compose.cfg | 82 +++++++++ station/default.sh | 23 +-- station/docker.cfg | 16 ++ station/finishall.sh | 10 -- station/generate_ogl.sh | 76 ++++++++ station/get-compose.sh | 86 +++++++++ station/luncher.sh | 9 +- station/prepare.sh | 72 +------- station/ptmx.sh | 3 - station/topswitch.sh | 9 - tools/hilbert-station | 384 ++++++++++++++++++++++++++++++++-------- 11 files changed, 592 insertions(+), 178 deletions(-) create mode 100644 station/compose.cfg create mode 100644 station/docker.cfg create mode 100755 station/generate_ogl.sh create mode 100755 station/get-compose.sh diff --git a/station/compose.cfg b/station/compose.cfg new file mode 100644 index 0000000..9a1627b --- /dev/null +++ b/station/compose.cfg @@ -0,0 +1,82 @@ +### HW / SW settings on the station host system: + +# pulse audio +export PULSE_SOCKET=${PULSE_SOCKET:-/run/user/${UID}/pulse/native} +export PULSE_COOKIE=${PULSE_COOKIE:-${HOME}/.config/pulse/cookie} + +# X11 + +if [ -z "${DISPLAY}" ]; then + if [ -r "/tmp/x.id" ]; then + N=$(cat /tmp/x.id | grep 'DISPLAY_NUM:' | tail -n 1 | sed s@DISPLAY_NUM:@@g) + + if [ -f "/tmp/.X${N}-lock" ]; then + export DISPLAY="unix:${N}" + # TODO: make sure we can use it! + fi + fi +fi + +N="0" +# loop through display number 0 ... 100 +# until free display number is found +while [ -z "${DISPLAY}" ] && [ "${N}" -le 100 ] +do +# for ((;;N++)); do + if [ -f "/tmp/.X${N}-lock" ]; then + # TODO: make sure we can use it! + export DISPLAY="unix:${N}" + break; + fi; + N=$((N+1)) +# done +done + +export XAUTH=${XAUTH:-/tmp/.docker.xauth} + +# if [ -n "${DISPLAY}" ]; then +# : echo "DISPLAY: '${DISPLAY}', XAUTHORITY: '${XAUTHORITY}' -> '${XAUTH}'" +# : [ ! -f "${XAUTH}" ] && touch "${XAUTH}" +# : xauth nlist "${DISPLAY}" | sed -e 's/^..../ffff/' | sort | uniq | xauth -f "${XAUTH}" nmerge - +# : [ ! -s "${XAUTH}" ] && echo "WARNING: something is wrong with '${XAUTH}': `ls -al ${XAUTH}`" +# fi +# : xhost + +unset XAUTHORITY + + +export HB_PORT="${HB_PORT:-8888}" +export HB_HOST="${HB_HOST:-127.0.0.1}" +## station_id?? + +HB_DEFAULT_URL="http://${HB_HOST}:${HB_PORT}" +export HB_URL=${HB_URL:-$HB_DEFAULT_URL} + +export HB_INIT_TIMEOUT=3 + +### For now... +export station_public_ip="" +export management_server='' +export management_server_ip="" + +#### ip ro ### | awk '/^default/{print $3}' + + +export qrs_screenshot_message="Bild gespeichert.\n\nImage saved." +export qr_uploadlocs="/tmp/" + +# QR device ID (according to xinput): + +export QR_DEVICE_ID="keyboard:AT Translated Set 2 keyboard" +## export QR_DEVICE_ID="keyboard:Mitsumi Electric Apple Extended USB Keyboard" +# export QR_DEVICE_ID="13" + +## inherited settings from prototype main interactive script: +export CUPS_SERVER="" +export MOUSE_CURSOR="on" +export CUSTOMIZATION="alsa nv vb" +export ALSA_CARD="1" +export LANGUAGE="en" +## export MENU_TRY="gui" +export VNC_PASSWD="" + +export WEBGL_APPS="${WEBGL_APPS:-http://supernova.mfo.de:7070}" diff --git a/station/default.sh b/station/default.sh index c333827..a4c37d8 100755 --- a/station/default.sh +++ b/station/default.sh @@ -1,15 +1,9 @@ #!/bin/sh -set -v -set -x - SELFDIR=`dirname "$0"` SELFDIR=`cd "$SELFDIR" && pwd` cd "${SELFDIR}/" -### set -e -## unset DISPLAY - #! NOTE: cleanup all previously started containers: # docker ps -aq | xargs --no-run-if-empty docker rm -fv # docker images -q -a | xargs --no-run-if-empty docker rmi @@ -18,19 +12,26 @@ if [ -r "./station.cfg" ]; then . "./station.cfg" fi -if [ -r "./startup.cfg" ]; then - . "./startup.cfg" -fi - - station_default_app="${station_default_app:-$default_app}" +## TODO: FIXME: check stopped containers! if [ -r "/tmp/lastapp.cfg" ]; then . "/tmp/lastapp.cfg" else export current_app="${station_default_app}" fi +#if hash ethtool 2>/dev/null; then +# ## TODO: FIXME: 'NET_IF'??? +# for i in `LANG=C netstat -rn | awk '/^0.0.0.0/ {thif=substr($0,74); print thif;} /^default.*UG/ {thif=substr($0,65); print thif;}'`; +# do +## echo "DEBUG: trying to enable WOL for interface: [$i]..." +## sudo -n -P ethtool -s "$i" wol g +# echo "DEBUG: checking WOL setting for interface: [$i]: " +# sudo -n -P ethtool "$i" | grep Wake-on +# done +#fi + if [ -r "./docker.cfg" ]; then . "./docker.cfg" diff --git a/station/docker.cfg b/station/docker.cfg new file mode 100644 index 0000000..0a36af5 --- /dev/null +++ b/station/docker.cfg @@ -0,0 +1,16 @@ +export NO_PROXY=${NO_PROXY:-/var/run/docker.sock} + +#if [ -S "NO_PROXY" ]; then +# export DOCKER_HOST=${DOCKER_HOST:-unix://$NO_PROXY} +#else +# export DOCKER_HOST=${DOCKER_HOST:-$NO_PROXY} +#fi + +#export DOCKER_PLUGINS=${DOCKER_PLUGINS:-/run/docker/plugins/} +export DOCKER_COMPOSE_IMAGE=${DOCKER_COMPOSE_IMAGE:-malex984/dockapp:ddd} + +## export SWARM_DISCOVERY_HOST={SWARM_DISCOVERY_HOST:-dilbert} +## export SWARM_CLUSTER_TOKEN={SWARM_CLUSTER_TOKEN:-??????????????????} + +export COMPOSE_PROJECT_NAME=dockapp +export COMPOSE_FILE=${COMPOSE_FILE:-docker-compose.yml} diff --git a/station/finishall.sh b/station/finishall.sh index bd2de5a..8f5d81c 100755 --- a/station/finishall.sh +++ b/station/finishall.sh @@ -1,23 +1,13 @@ #!/bin/sh -set -v -set -x - SELFDIR=`dirname "$0"` SELFDIR=`cd "$SELFDIR" && pwd` cd "${SELFDIR}/" -## set -e -# unset DISPLAY - if [ -r "./station.cfg" ]; then . "./station.cfg" fi -if [ -r "./startup.cfg" ]; then - . "./startup.cfg" -fi - #if [ -r "./docker.cfg" ]; then # . "./docker.cfg" #fi diff --git a/station/generate_ogl.sh b/station/generate_ogl.sh new file mode 100755 index 0000000..2829ce3 --- /dev/null +++ b/station/generate_ogl.sh @@ -0,0 +1,76 @@ +#!/bin/bash + +#SELFDIR=`dirname "$0"` +#SELFDIR=`cd "$SELFDIR" && pwd` +#cd "$SELFDIR" + +IMAGE_VERSION="${IMAGE_VERSION:-latest}" + +I="dummy" + +# The following is an adaptation to the new naming schema: hilbert/$APP:$VERSION +U=hilbert +IMG="$U/${I}:${IMAGE_VERSION}" # IMG="$APP" #IMG="$U/$I:$APP" + +ID=$(docker images | awk '{ print "[" $1 ":" $2 "]" }' | sort | uniq | grep "\[${IMG}\]") + +if [ -z "$ID" ]; then + echo "ERROR: no such image '${IMG}'" +# exit 2 + U=malex984 + IMG="$U/dockapp:${I}" # IMG="$APP" #IMG="$U/$I:$APP" + ID=$(docker images | awk '{ print "[" $1 ":" $2 "]" }' | sort | uniq | grep "\[${IMG}\]") + + if [ -z "$ID" ]; then + echo "ERROR: no such image '${IMG}'" + exit 2 + fi + +fi + +shift + +G="$1" +shift + +#D=$1 +D=dummyx11 +C="c_$D" + + +## pre-cleanup +docker rm -vf $C 1>&2 || true +docker rmi -f --no-prune=false $D 1>&2 || true + + +R="-it -a stdin -a stdout -a stderr --label is_top_app=0 --ipc=host --net=host --pid=host -v /etc/localtime:/etc/localtime:ro -v /tmp/:/tmp/:rw" +O="--skip-startup-files --no-kill-all-on-exit --quiet --skip-runit" + +## Create $C conainer out of $IMG and run customization script in it: +docker run $R --name $C $IMG $O -- bash -c 'customize.sh' 1>&2 +# --privileged --ipc=host --net=host --pid=host -v /dev/:/dev/:rw + + +# docker start $C && sleep 1 +# docker commit --change "VOLUME /usr/" --change "VOLUME /etc/" --change "VOLUME /opt/" $C $D +# docker diff $C > ${mkfile_dir}/${APP}_${D}.diff + + +## Output the effects of customization procedure: +docker diff $C + +## Select necessary added/changed customizing files: +A=`docker diff $C |grep -E '^A /(usr|etc|sbin|var/lib|root|home)/' |grep -vE ' (/usr/src|/usr/lib/python[23]|/usr/share/doc|/usr/share/man|/etc/container_environment)' |sed 's@^[CA] @@g'|xargs` + +docker commit $C $D + +## pre-cleaup: +docker rm -vf $C 1>&2 +rm -Rf $G 1>&2 || true + +## generate target archive $G: +# TODO: --recursion ? ADDEDFILES=/bin/true /lib/x86_64-linux-gnu/libc.so.6 /lib64/ld-linux-x86-64.so.2 /usr/lib/x86_64-linux-gnu/ ? +docker run $R --rm $D $O -- bash -c "tar czvf $G --hard-dereference --dereference $A && chmod a+rw $G" + +## post-cleanup: +docker rmi -f --no-prune=false $D 1>&2 || true diff --git a/station/get-compose.sh b/station/get-compose.sh new file mode 100755 index 0000000..dff5879 --- /dev/null +++ b/station/get-compose.sh @@ -0,0 +1,86 @@ +#! /bin/bash + +if hash docker-compose 2>/dev/null; then + echo "DEBUG: using $(which docker-compose), $(docker-compose --version)" + ln -s `which docker-compose` "${PWD}/compose" +else + #! Get Docker compose + DOCKER_COMPOSE_VERSION=1.9.0 # NOTE: update to newer compose version if necessary! + DOCKER_COMPOSE_BASE_URL="https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}" + + DOCKER_COMPOSE_BIN_URL="${DOCKER_COMPOSE_BASE_URL}/docker-compose-$(uname -s)-$(uname -m)" + DOCKER_COMPOSE_SH_URL="${DOCKER_COMPOSE_BASE_URL}/run.sh" + + + if [ ! -x ./docker-compose ]; then + if hash curl 2>/dev/null; then + curl -L "${DOCKER_COMPOSE_BIN_URL}" > ./docker-compose && chmod +x ./docker-compose + elif hash wget 2>/dev/null; then + wget -q -O - "${DOCKER_COMPOSE_BIN_URL}" > ./docker-compose && chmod +x ./docker-compose + fi + fi + + if [ -x ./docker-compose ]; then + if [ -x ./docker-compose ]; then + ln -s "${PWD}/docker-compose" "${PWD}/compose" + fi + + else + if [ ! -x ./docker-compose.sh ]; then + if hash curl 2>/dev/null; then + curl -L "${DOCKER_COMPOSE_SH_URL}" > ./docker-compose.sh && chmod +x ./docker-compose.sh + elif hash wget 2>/dev/null; then + wget -q -O - "${DOCKER_COMPOSE_SH_URL}" > ./docker-compose.sh && chmod +x ./docker-compose.sh + fi + fi + + if [ -x ./docker-compose.sh ]; then + ln -s "${PWD}/docker-compose.sh" "${PWD}/compose" + fi + fi +fi + +if [ ! -x ./compose ]; then + echo "Warning: could not get 'docker-compose' from 'https://github.com/docker/compose/releases'! + Please download it as '$PWD/docker-compose' and make it executable!" +else + echo "DEBUG: using `readlink -f ${PWD}/compose`, `./compose --version`" +fi + + + +################################################################################### +### docker login -u malex984 -p ... ... imaginary.mfo.de:5000 + +D="${HOME}/.docker/" +F="${D}/config.json" +mkdir -p "${D}" +HILBERT_SERVER_DOCKER_REPOSITORY="{HILBERT_SERVER_DOCKER_REPOSITORY:-imaginary.mfo.de:5000}" +HILBERT_SERVER_DOCKER_REPOSITORY_AUTH="{HILBERT_SERVER_DOCKER_REPOSITORY_AUTH:-bWFsZXg5ODQ6MzJxMzJx}" +### TODO: FIXME: update wrt server repository! Later on! +cat > "${F}~" < ./local-persist-linux-amd64 +#chmod +x ./local-persist-linux-amd64 +#sudo ./local-persist-linux-amd64 1>./local-persist-linux-amd64.log 2>&1 & + +#docker volume create -d local-persist -o mountpoint="$CFG_DIR/KV" --name=KV +#docker volume create -d local-persist -o mountpoint="$CFG_DIR/OMD" --name=OMD +#docker volume create -d local-persist -o mountpoint="$CFG_DIR/CFG" --name=CFG diff --git a/station/luncher.sh b/station/luncher.sh index 9201a92..63ade57 100755 --- a/station/luncher.sh +++ b/station/luncher.sh @@ -1,8 +1,5 @@ #!/bin/sh -set -v -set -x - # # Run docker-compose within 'ddd' # @@ -36,9 +33,9 @@ if [ -r "./station.cfg" ]; then . "./station.cfg" fi -if [ -r "./startup.cfg" ]; then - . "./startup.cfg" -fi +#if [ -r "./startup.cfg" ]; then +# . "./startup.cfg" +#fi if [ -r "/tmp/lastapp.cfg" ]; then . "/tmp/lastapp.cfg" diff --git a/station/prepare.sh b/station/prepare.sh index d1e09fa..d30bf62 100755 --- a/station/prepare.sh +++ b/station/prepare.sh @@ -1,7 +1,4 @@ -#!/bin/sh - -set -v -set -x +#! /bin/bash ### Preparation for actual docker-framework @@ -15,31 +12,6 @@ cd "${SELFDIR}/" #### TODO: needs some safety check to avoid multiple runs... -## install Docker Volume 'local-persist' plugin following https://github.com/CWSpear/local-persist -##curl -fsSL https://raw.githubusercontent.com/CWSpear/local-persist/master/scripts/install.sh | sudo bash - -### TODO: update to newer compose version if necessary!... -DOCKER_COMPOSE_LINUX64_URL="https://github.com/docker/compose/releases/download/1.8.0/docker-compose-Linux-x86_64" - -if [ ! -f ./compose ]; -then - - if hash curl 2>/dev/null; then - curl -L "${DOCKER_COMPOSE_LINUX64_URL}" > ./compose && chmod +x ./compose - elif hash wget 2>/dev/null; then - wget -q -O - "${DOCKER_COMPOSE_LINUX64_URL}" > ./compose && chmod +x ./compose - fi - -fi - -if [ ! -f ./compose ]; -then - echo "Warning: could not get docker-compose via '${DOCKER_COMPOSE_LINUX64_URL}'! - Please download it as '$PWD/compose' and make it executable!" -fi - -chmod a+x ./compose - #! Finish our services (possible left-overs due to some crash) #### ./finishall.sh # NOTE: no clean-up for left-overs for now @@ -49,33 +21,21 @@ chmod a+x ./compose #! All images?? # docker images -q -a | xargs --no-run-if-empty docker rmi -## cd ./tmp/ -### TODO: add the plugin for global installation? -#curl -fsSL https://github.com/CWSpear/local-persist/releases/download/v1.1.0/local-persist-linux-amd64 > ./local-persist-linux-amd64 -#chmod +x ./local-persist-linux-amd64 -#sudo ./local-persist-linux-amd64 1>./local-persist-linux-amd64.log 2>&1 & - ### add me to all the necessary groups etc ... #if [ ! -L "$CFG_DIR/CFG" ]; then # ln -sf "$CFG_DIR" "$CFG_DIR/CFG" #fi -#docker volume create -d local-persist -o mountpoint="$CFG_DIR/KV" --name=KV -#docker volume create -d local-persist -o mountpoint="$CFG_DIR/OMD" --name=OMD -#docker volume create -d local-persist -o mountpoint="$CFG_DIR/CFG" --name=CFG - - #! TODO: FIXME: SUDO! ### ./ptmx.sh >/dev/null 2>&1 & if [ -f ./OGL.tgz ]; then cp -fp ./OGL.tgz /tmp/ || sudo -n -P cp -fp ./OGL.tgz /tmp/ +else + echo "WARNING: Missing 'OGL.tgz'! Please regenerate!" fi -if hash ethtool 2>/dev/null; then - sudo ethtool -s "${NET_IF}" wol g -fi # if [ -e "/tmp/lastapp.cfg" ]; then # @@ -87,31 +47,13 @@ fi # # fi -### docker login -u malex984 -p ... ... imaginary.mfo.de:5000 - -D="${HOME}/.docker/" -F="${D}/config.json" - -mkdir -p "${D}" -cat > "${F}~" < +# NOTE: uses flock from util-linux[-ng] +LOCKFILE="/var/lock/${TOOL}" +LOCKFD=99 + +# PRIVATE +_lock() { flock -$1 $LOCKFD; } +_no_more_locking() { _lock u; _lock xn && rm -f $LOCKFILE; } +_prepare_locking() { eval "exec $LOCKFD>\"$LOCKFILE\""; trap _no_more_locking EXIT; } + +# PUBLIC +exlock_now() { _lock xn; } # obtain an exclusive lock immediately or fail +exlock() { _lock x; } # obtain an exclusive lock +shlock() { _lock s; } # obtain a shared lock +unlock() { _lock u; } # drop a lock + +# TODO(?): evaluate other ways according to http://stackoverflow.com/questions/1715137/the-best-way-to-ensure-only-1-copy-of-bash-script-is-running + +exec 3>&1 4>&2 +### [ -f ${LOCKFILE} ] && /bin/rm -f +trap 'exec 2>&4 1>&3 ' 0 1 2 3 13 15 RETURN +exec 2>&1 +# 1>log.out + +start_locking () { + DEBUG "NOTE: Checking for exclusive (locked) usage of ${TOOL} (with given subcommand)" + + # ON START: + _prepare_locking + # Simplest example is avoiding running multiple instances of script: `exlock_now || exit 1` + # Remember! Lock file is removed when one of the scripts exits and it is + # the only script holding the lock or lock is not acquired at all. + + if exlock_now + then + DEBUG "Lockfile: $(ls -la ${LOCKFILE})" + else + DEBUG "Lockfile: $(ls -la ${LOCKFILE})" + ERROR "Another user is already running ${TOOL}: please try again later!" + exit 2 + fi + +} + +function INFO() { + echo "INFO [${TOOL}:${FUNCNAME[1]}] $*" +} +function WARNING() { + echo "WARNING [${TOOL}:${FUNCNAME[1]}] $*" +} +function DEBUG() { + echo "DEBUG [${TOOL}:${FUNCNAME[1]}] $*" +} +function ERROR(){ + echo "ERROR [${TOOL}:${FUNCNAME[1]}] $*" +} + +# TODO: read HILBERT_CONFIG_DIR from `~/.hilbert-station` ? +export HILBERT_CONFIG_DIR="${HILBERT_CONFIG_DIR:-${HOME}/.config/${TOOL}}" +export HILBERT_CONFIG_FILE="${HILBERT_CONFIG_FILE:-${HILBERT_CONFIG_DIR}/station.cfg}" CLI_VERSION_ID="\$Id$" usage () { - echo "${TOOL} - Station part for Linux systems" - echo "Usage: " - echo " ${TOOL} -h Display this help message." - echo " ${TOOL} -v Increase verbosity" - echo " ${TOOL} -q Decrease verbosity" - echo " ${TOOL} -p Pedantic mode" - echo " ${TOOL} -V Display version info." - echo " ${TOOL} start Start everything" - echo " ${TOOL} stop Stop everything and shutdown" - echo " ${TOOL} prepare Install a new local configuration" - echo " ${TOOL} app_switch Change the currently running top application to specified one" - echo " ${TOOL} dm_start Start a VM using docker-machine" # on the VM host system + cat << EOF +usage: ${TOOL} [-h] [-p] [-V] [-v | -q] subcommand + +Hilbert - client part for Linux systems + +positional arguments: + subcommand: + app_change Change the currently running top application to specified one + start Start Hilbert on the system + stop Stop Hilbert on the system and shutdown it + + prepare [] Update after installing a new local configuration (post-deployment action) + dm_start Start a VM using docker-machine + +optional arguments: + -h show this help message and exit + -V show version info and exit + -p turn on pedantic mode + -v increase verbosity + -q decrease verbosity +EOF } version () { - echo "DEBUG [${TOOL}]: This tool: [$0]" - echo "DEBUG [${TOOL}]: Version: [${CLI_VERSION_ID}]" + cat << EOF +This tool: [$0] +Version: [${CLI_VERSION_ID}] +Lockfile: [$(ls -l ${LOCKFILE})] - echo "DEBUG [${TOOL}]: Workdir: [${PWD}]" - echo "DEBUG [${TOOL}]: Config Dir: [${HILBERT_CONFIG_DIR}]" - echo "DEBUG [${TOOL}]: Configs: ($(ls ${HILBERT_CONFIG_DIR} | xargs))" +Workdir: [${PWD}] +Config Dir: [${HILBERT_CONFIG_DIR}] +Config file: [$(readlink -f ${HILBERT_CONFIG_FILE})] +All Configs: [$(sh -c "cd ${HILBERT_CONFIG_DIR}/ && ls *.cfg | xargs")] - echo "DEBUG [${TOOL}]: Host: [`hostname`]" - echo "DEBUG [${TOOL}]: System: [`uname -a`]" +Host: [$(hostname)] +System: [$(uname -a)] +EOF + + DEBUG "${HILBERT_CONFIG_FILE}: +[" + cat "${HILBERT_CONFIG_FILE}" # TODO: indent the file contents for pretty-printing? + DEBUG " +]" } +DEBUG "Input args: ($@)" + + +while getopts ":hqvpV" opt; do + case ${opt} in + h ) + usage + exit 0 + ;; + V ) + version + exit 0 + ;; + p ) + DEBUG "Turned-on the pedantic mode!(?)" + set -e # TODO: test this!! + ;; + v ) + DEBUG "Turning on tracing of bash command execution + verbosity..." + set -v + set -x + ;; + q ) + DEBUG "Turning off tracing of bash command execution + verbosity..." + set +v + set +x + ;; + \? ) + ERROR "Invalid Option: -$OPTARG" + exit 1 + ;; + esac +done + + + +if [[ ! -d "${HILBERT_CONFIG_DIR}" ]]; then + WARNING "Configuration directory '${HILBERT_CONFIG_DIR}' is missing!" + mkdir -p "${HILBERT_CONFIG_DIR}" +fi + +if [[ ! -r "${HILBERT_CONFIG_DIR}" ]]; then + WARNING "Configuration directory '${HILBERT_CONFIG_DIR}' is unreadable!" + chmod u+rwx "${HILBERT_CONFIG_DIR}" +fi + +if [[ ! -d "${HILBERT_CONFIG_DIR}" ]]; then + ERROR "Configuration directory '${HILBERT_CONFIG_DIR}' is missing!" + exit 1 +fi + +if [[ ! -r "${HILBERT_CONFIG_DIR}" ]]; then + ERROR "Configuration directory '${HILBERT_CONFIG_DIR}' is unreadable!" + exit 1 +fi + +DEBUG "Configuration directory '${HILBERT_CONFIG_DIR}' exists and is readable..." + +if [[ ! -r "${HILBERT_CONFIG_FILE}" ]]; then + WARNING "Station Configuration file '${HILBERT_CONFIG_FILE}' is unreadable!" +# exit 1 +else + DEBUG "Station Configuration file '${HILBERT_CONFIG_FILE}' exists and is readable..." +fi + +cmd_install_station_config() { + subcommand="prepare(install_station_config)" + arg=$1; shift + + if [[ -z "${arg}" ]]; then + ERROR "Wrong argument '${arg}' to '${subcommand}'!" + usage + exit 1 + fi + + if [[ ! -r "${arg}" ]]; then + ERROR "New configuration file '${arg}' is not readable!" + usage + exit 1 + fi + + # TODO: what about further resources? Maybe a .tar.gz and unpack it into ${new_cfg_dir}? + + # NOTE: New configuration directory + # TODO: make sure there is no such dir yet! + new_cfg_dir=$(mktemp -d --tmpdir=${HILBERT_CONFIG_DIR} "`basename ${arg}`.XXXXXXXXXX") + DEBUG "new_cfg_dir: ${new_cfg_dir}" + + mkdir -p "${new_cfg_dir}" + + # NOTE: take over the deployed station configuration file! + DEBUG "Moving ${arg} => ${new_cfg_dir}/station.cfg" + mv "${arg}" "${new_cfg_dir}/station.cfg" + + ALL_CONFIG_DIR="${HILBERT_CONFIG_DIR}/configs" + + # What about the rest of resources? + if [[ -L "${ALL_CONFIG_DIR}" ]]; then + DEBUG "${ALL_CONFIG_DIR} -> $(readlink -f ${ALL_CONFIG_DIR})" + + # TODO: remove older config? + unlink "${ALL_CONFIG_DIR}" + fi + + # NOTE: atomic configuration update! + # TODO: FIXME: full path in symbolic link => may interfere when volume-mounted... + # use basename ${new_cfg_dir}??? instead? + ln -sf "${new_cfg_dir}" "${ALL_CONFIG_DIR}" + + if [[ ! -L "${ALL_CONFIG_DIR}" ]]; then + WARNING "${ALL_CONFIG_DIR} is not a link!" + fi + +} cmd_prepare () { subcommand="prepare" arg=$1; shift - if [[ -z ${arg} ]]; then - echo "ERROR [${TOOL}]: Wrong argument '${arg}' to '${subcommand}'!" 1>&2 - usage + if [[ -n "${arg}" ]]; then + cmd_install_station_config "${arg}" + fi + + if [[ ! -x "${HILBERT_CONFIG_DIR}/prepare.sh" ]]; then + ERROR "'${HILBERT_CONFIG_DIR}/prepare.sh' is not executable!" exit 1 + else + exec "${HILBERT_CONFIG_DIR}/prepare.sh" fi - echo "ERROR [${TOOL}]: Sorry '${subcommand} ${arg} [$*]' not yet implemented!" - exit 2 + +# # ERROR "Sorry '${subcommand} ${arg} [$*]' not yet implemented!" +# exit 2 } cmd_app_change () { subcommand="app_change" arg=$1; shift if [[ -z ${arg} ]]; then - echo "ERROR [${TOOL}]: Wrong argument '${arg}' to '${subcommand}'!" 1>&2 + ERROR "Wrong argument '${arg}' to '${subcommand}'!" usage exit 1 fi - echo "ERROR [${TOOL}]: Sorry '${subcommand} ${arg} [$*]' not yet implemented!" - exit 2 + # TODO: read configuration. Check whether arg is a valid application + + if [[ ! -x "${HILBERT_CONFIG_DIR}/topswitch.sh" ]]; then + ERROR "'${HILBERT_CONFIG_DIR}/topswitch.sh' is not executable!" + exit 1 + else + exec "${HILBERT_CONFIG_DIR}/topswitch.sh" "${arg}" + fi } cmd_dm_start () { @@ -68,89 +282,111 @@ cmd_dm_start () { arg=$1; shift if [[ -z ${arg} ]]; then - echo "ERROR [${TOOL}]: Wrong argument '${arg}' to '${subcommand}'!" 1>&2 + ERROR "Wrong argument '${arg}' to '${subcommand}'!" usage exit 1 fi - echo "ERROR [${TOOL}]: Sorry '${subcommand} ${arg} [$*]' not yet implemented!" - exit 2 + DM="${DM:-docker-machine}" # TODO: check if ${DM} exists and is an executable! + DEBUG "executing: [${DM} start \"${arg}\"]" + exec ${DM} start "${arg}" +} + +cmd_default () { + if [[ ! -x "${HILBERT_CONFIG_DIR}/default.sh" ]]; then + ERROR "'${HILBERT_CONFIG_DIR}/default.sh' is not executable!" + exit 1 + else + exec "${HILBERT_CONFIG_DIR}/default.sh" + fi } cmd_start () { subcommand="start" - echo "ERROR [${TOOL}]: Sorry '$subcommand [$*]' not yet implemented!" - exit 2 + + # TODO: read config and handle the following: variables! + source "${HILBERT_CONFIG_FILE}" # only: key="...value..."! + + if [[ "${hilbert_autostart}" != "True" ]]; then + DEBUG "hilbert_autostart: ${hilbert_autostart} (True/False)" + DEBUG "hilbert_autostart_delay: ${hilbert_autostart_delay} (positive int)" + + INFO "Auto-starting is not enabled in ${HILBERT_CONFIG_FILE}" + DEBUG "Will NOT start Hilbert!.." + exit 0 + fi + + DEBUG "Sleeping for [${hilbert_autostart_delay}] sec (due to 'hilbert_autostart_delay' from '${HILBERT_CONFIG_FILE}')..." + sleep "${hilbert_autostart_delay}" + + # TODO: check hilbert_autostart and exit is False! + # TODO: sleep hilbert_autostart_delay + + cmd_default } -cmd_stop () { - subcommand="stop" - echo "ERROR [${TOOL}]: Sorry '$subcommand [$*]' not yet implemented!" - exit 2 +cmd_finishall () { + subcommand="stop(finishall)" + + if [[ ! -x "${HILBERT_CONFIG_DIR}/finishall.sh" ]]; then + WARNING "'${HILBERT_CONFIG_DIR}/finishall.sh' is not executable!" + else + "${HILBERT_CONFIG_DIR}/finishall.sh" + fi } +cmd_stop () { + subcommand="stop" + # TODO: NOTE: any arguments? -echo "DEBUG [${TOOL}]: Input args: ($@)" + cmd_finishall -while getopts ":hqvpV" opt; do - case ${opt} in - h ) - usage - exit 0 - ;; - V ) - version - exit 0 - ;; - p ) - set -e - ;; - v ) - set -v - set -x - ;; - q ) - set +v - set +x - ;; - \? ) - echo "Invalid Option: -$OPTARG" 1>&2 - exit 1 - ;; - esac -done + DEBUG "Shutting this system down..." # -h now? + shutdown +} shift $((OPTIND -1)) subcommand=$1; shift -echo "DEBUG [${TOOL}]: subcommand to run: '$subcommand'" +DEBUG "Subcommand to handle: '$subcommand'" case "$subcommand" in prepare) + start_locking cmd_prepare "$@" ;; app_switch|app_change) + start_locking cmd_app_change "$@" ;; dm_start) + # User should be able to start multiple VMs in parallel... cmd_dm_start "$@" ;; stop) - cmd_stop "$@" + start_locking + cmd_stop "$@" # TODO: arguments? ;; start) - cmd_start "$@" + start_locking + cmd_start "$@" # TODO: arguments? + ;; + cmd_*) # hidden subcommand-s + start_locking # NOTE: Just to be sure!.. + ${subcommand} "$@" + + DEBUG "Script successfully handled hidden subcommand: [${subcommand}]!" + exit 0 ;; esac if [[ -z "${subcommand}" ]]; then usage + DEBUG "Script successfully finished without handling any subcommands..." + exit 0 else - echo "ERROR [${TOOL}]: Invalid sub-command: '$subcommand'" 1>&2 + ERROR "Invalid sub-command: '$subcommand'" exit 1 fi -echo "DEBUG [${TOOL}]: Done" - -exit 0 From b9d28283828317bd6a1c7fd4d04dbb51c56fdd11 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Wed, 7 Dec 2016 05:37:02 +0100 Subject: [PATCH 41/42] Updated Station part of Hilbert NOTE: temporary include docker-compose.yml for completeness --- config/hilbert_cli_config.py | 35 +- station/compose.cfg | 15 +- station/default.sh | 8 + station/docker-compose.yml | 610 +++++++++++++++++++++++++++++++++++ station/finishall.sh | 7 + station/get-compose.sh | 4 +- station/prepare.sh | 4 - station/topswitch.sh | 7 +- tools/hilbert-station | 147 ++++++--- 9 files changed, 760 insertions(+), 77 deletions(-) create mode 100644 station/docker-compose.yml diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index b16d9f2..1b253fe 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -1766,7 +1766,21 @@ def shutdown(self): try: _ret = _a.ssh([self._HILBERT_STATION, "stop"], shell=False) except: - s = "Could not shutdown station {}".format(_a) + s = "Could not stop Hilbert on the station {}".format(_a) + if not PEDANTIC: + log.warning(s) + return False + else: + log.exception(s) + raise + + if not _ret: + return _ret + + try: + _ret = _a.ssh([self._HILBERT_STATION, "shutdown"], shell=False) + except: + s = "Could not schedule a shutdown on the station {}".format(_a) if not PEDANTIC: log.warning(s) return False @@ -1776,6 +1790,7 @@ def shutdown(self): return _ret + def deploy(self): global PEDANTIC @@ -1807,7 +1822,7 @@ def deploy(self): assert _serviceIDs is not None assert isinstance(_serviceIDs, ServiceList) # list of ServiceID - _serviceIDs = _serviceIDs.get_data() + _serviceIDs = _serviceIDs.get_data() # Note: IDs from config file - NOT Service::ref! assert isinstance(_serviceIDs, list) # list of strings (with ServiceIDs)? _a = self.get_address() @@ -1824,10 +1839,14 @@ def deploy(self): # NOTE: ATM only compose && Application/ServiceIDs == refs to the same docker-compose.yml! # TODO: NOTE: may differ depending on Station::type! tmp.write("hilbert_station_profile_services=\"{}\"\n".format(' '.join(_serviceIDs))) + for k in _settings: tmp.write("{0}=\"{1}\"\n".format(k, str(_settings.get(k, '')))) + tmp.write("background_services=\"${hilbert_station_profile_services}\"\n") - tmp.write("default_app=\"${hilbert_station_default_application}\"\n") + + tmp.write("default_app=\"${hilbert_station_default_application}\"\n") # ID! + # TODO: collect all compatible applications! tmp.write("possible_apps=\"${default_app}\"\n") @@ -1853,11 +1872,11 @@ def deploy(self): # log.debug("New Station Configuration: {}".format(s)) # os.remove(path) - _cmd = [self._HILBERT_STATION, "prepare", os.path.join("/tmp", os.path.basename(path))] + _cmd = [self._HILBERT_STATION, "init", os.path.join("/tmp", os.path.basename(path))] try: _a.ssh(_cmd, shell=False) except: - s = "Could not prepare the station using the new configuration file with {}".format(' '.join(_cmd)) + s = "Could not initialize the station using the new configuration file with {}".format(' '.join(_cmd)) if not PEDANTIC: log.warning(s) return False @@ -1877,7 +1896,7 @@ def deploy(self): # def finish_service(self, action_args): # raise NotImplementedError("Cannot finish a service/application on this station!") - def app_switch(self, app_id): + def app_change(self, app_id): global PEDANTIC _a = self.get_address() @@ -1886,7 +1905,7 @@ def app_switch(self, app_id): assert isinstance(_a, HostAddress) try: - _ret = _a.ssh([self._HILBERT_STATION, "app_switch", app_id], shell=False) + _ret = _a.ssh([self._HILBERT_STATION, "app_change", app_id], shell=False) except: s = "Could not change top application on the station '{0}' to '{1}'".format(_a, app_id) if not PEDANTIC: @@ -1938,7 +1957,7 @@ def run_action(self, action, action_args): elif action == 'stop': self.shutdown() # action_args elif action == 'app_change': - self.app_switch(action_args) # ApplicationID + self.app_change(action_args) # ApplicationID # elif action == 'start': # self.start_service(action_args) diff --git a/station/compose.cfg b/station/compose.cfg index 9a1627b..705b3c3 100644 --- a/station/compose.cfg +++ b/station/compose.cfg @@ -34,14 +34,15 @@ done export XAUTH=${XAUTH:-/tmp/.docker.xauth} -# if [ -n "${DISPLAY}" ]; then +if [ -n "${DISPLAY}" ]; then # : echo "DISPLAY: '${DISPLAY}', XAUTHORITY: '${XAUTHORITY}' -> '${XAUTH}'" -# : [ ! -f "${XAUTH}" ] && touch "${XAUTH}" -# : xauth nlist "${DISPLAY}" | sed -e 's/^..../ffff/' | sort | uniq | xauth -f "${XAUTH}" nmerge - -# : [ ! -s "${XAUTH}" ] && echo "WARNING: something is wrong with '${XAUTH}': `ls -al ${XAUTH}`" -# fi -# : xhost + -unset XAUTHORITY +# [ ! -f "${XAUTH}" ] && touch "${XAUTH}" + (xauth nlist "${DISPLAY}" | sed -e 's/^..../ffff/' | sort | uniq | xauth -f "${XAUTH}" nmerge - ) 1> /dev/null 2>&1 +# [ ! -s "${XAUTH}" ] && echo "WARNING: something is wrong with '${XAUTH}': `ls -al ${XAUTH}`" + (xhost +) 1> /dev/null 2>&1 +fi + +#unset XAUTHORITY export HB_PORT="${HB_PORT:-8888}" diff --git a/station/default.sh b/station/default.sh index a4c37d8..8976dac 100755 --- a/station/default.sh +++ b/station/default.sh @@ -4,6 +4,9 @@ SELFDIR=`dirname "$0"` SELFDIR=`cd "$SELFDIR" && pwd` cd "${SELFDIR}/" +### set -e +## unset DISPLAY + #! NOTE: cleanup all previously started containers: # docker ps -aq | xargs --no-run-if-empty docker rm -fv # docker images -q -a | xargs --no-run-if-empty docker rmi @@ -12,6 +15,11 @@ if [ -r "./station.cfg" ]; then . "./station.cfg" fi +#if [ -r "./startup.cfg" ]; then +# . "./startup.cfg" +#fi + + station_default_app="${station_default_app:-$default_app}" ## TODO: FIXME: check stopped containers! diff --git a/station/docker-compose.yml b/station/docker-compose.yml new file mode 100644 index 0000000..058c9bd --- /dev/null +++ b/station/docker-compose.yml @@ -0,0 +1,610 @@ +version: '2' +services: + base: + image: malex984/dockapp:base + volumes: + - /tmp:/tmp:rw + - ${PWD}:/DOCKAPP + - /etc/localtime:/etc/localtime:ro + labels: + - "is_top_app=0" + - "description=Base for dockapp services" + working_dir: /DOCKAPP + privileged: false + network_mode: "host" + environment: + - CFG_DIR=/DOCKAPP + - CUPS_SERVER + - ALSA_CARD + - LANGUAGE + - MOUSE_CURSOR + - CUSTOMIZATION + entrypoint: + - /bin/sh + + ddd: + extends: + service: base + image: ${DOCKER_COMPOSE_IMAGE} + labels: + - "is_top_app=0" + - "description=Docker CLI + Compose" + volumes: + - ${NO_PROXY}:${NO_PROXY} + environment: + - NO_PROXY + entrypoint: + - /bin/sh + + admin: + extends: + service: ddd + volumes: + - /dev:/dev:rw + - /run/udev:/run/udev + - /sys/fs/cgroup:/sys/fs/cgroup:ro + - /run/systemd:/run/systemd + - /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket + labels: + - "is_top_app=0" + cap_add: + - SYS_ADMIN + - NET_ADMIN + - ALL + + consul_base: + extends: + service: admin + image: progrium/consul + ports: + - "8400:8400" + - "8500:8500" + - "8600:53/udp" + labels: + - "is_top_app=0" + stdin_open: false + tty: false + restart: "on-failure:5" + entrypoint: + - /bin/start + + consul_agent: + extends: + service: consul_base + command: + - "-advertise" + - "{station_public_ip}" + - "-join" + - "${management_server_ip}" + + consul: + extends: + service: consul_base + volumes: + - "${PWD}/KV:/data" + command: + - "-server" + - "-bootstrap" + - "-advertise" + - "{station_public_ip}" + - "-ui-dir" + - "/ui" + + registrator: + extends: + service: admin + image: gliderlabs/registrator:latest + entrypoint: + - "/bin/registrator" + command: + - "consul://${management_server_ip}:8500" + + x11: + extends: + service: admin + image: malex984/dockapp:dummy + privileged: true + stdin_open: false + tty: false + restart: "on-failure:5" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + command: + - startXephyr.sh + + xephyr: + extends: + service: x11 + environment: + - XCMD=Xephyr + + xvfb: + extends: + service: x11 + environment: + - XCMD=Xvfb + command: + - startXephyr.sh + - "-screen" + - "0" + - "1024x768x16" + + omd_agent: + extends: + service: ddd + image: imaginary.mfo.de:5000/malex984/omd_agent + environment: + - HB_PORT + - HB_HOST + - HB_URL + ports: + - "6556" + - "${HB_PORT}" + stdin_open: false + tty: false + restart: "on-failure:5" + labels: + - "is_top_app=0" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + command: + - omd_agent_entrypoint.sh + + hb_test: + extends: + service: base + privileged: false + image: malex984/dockapp:omd_agent + environment: + - HB_PORT + - HB_HOST + - HB_URL + - HB_INIT_TIMEOUT + - APP_ID=hb_test + stdin_open: false + tty: false + restart: "on-failure:5" + labels: + - "is_top_app=1" + - "description=HB test in python" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + command: + - python2.7 + - /usr/local/bin/heartbeat2.py + + + hb_test_a: + extends: + service: base + image: imaginary.mfo.de:5000/malex984/appa + environment: + - APP_ID=hb_test_a + - HB_PORT + - HB_HOST + - HB_URL + - HB_INIT_TIMEOUT + stdin_open: false + tty: false + restart: "on-failure:5" + labels: + - "description=HB test in bash: A" + - "is_top_app=1" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - /usr/local/bin/A.sh + command: + - AHB_HelloA + + hb_test_b: + extends: + service: hb_test_a + environment: + - APP_ID=hb_test_b + labels: + - "description=HB test in bash: B" + command: + - BHB_HelloB + + hb_test_c: + extends: + service: hb_test_a + environment: + - APP_ID=hb_test_c + labels: + - "description=HB test in bash: C" + command: + - CHB_HelloC + + busybox: + extends: + service: admin + labels: + - "is_top_app=0" + image: busybox + entrypoint: + - /bin/sh + + ptmx: + extends: + service: busybox + stdin_open: false + tty: false + restart: "on-failure:5" + command: + - "./ptmx.sh" + + reboot: + extends: + service: busybox + stdin_open: false + tty: false + command: + - reboot + + omd_anew: + extends: + service: base + image: malex984/dockapp:omd + ports: + - "80" + - "514" + - "5667" + - "5000" + labels: + - "is_top_app=0" + stdin_open: false + tty: false + restart: "on-failure:5" + volumes: + - "omd_data:/OMD" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + command: + - omd_entrypoint.sh + + omd_persistent: + extends: + service: omd_anew + volumes: + - "omd_data:/omd/sites" + + pa: + extends: + service: admin + labels: + - "is_top_app=0" + volumes: + - ${PULSE_SOCKET}:/run/pulse/native + - ${PULSE_COOKIE}:/run/pulse/cookie + environment: + - PULSE_SERVER=/run/pulse/native + - PULSE_COOKIE=/run/pulse/cookie + + gui: + extends: + service: pa + labels: + - "is_top_app=0" + environment: + - QT_X11_NO_MITSHM=1 + - XLIB_SKIP_ARGB_VISUALS=1 + - XAUTHORITY="${XAUTH}" + - DISPLAY + stdin_open: false + tty: false + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + + qrhandler: + extends: + service: gui + labels: + - "is_top_app=0" + image: malex984/dockapp:qrhandler + restart: "on-failure:5" + volumes: + - supernova:/supernova + environment: + - QR_DEVICE_ID + - qrs_screenshot_message + - qr_uploadlocs + command: + - qrhandler.sh + + x11vnc: + extends: + service: gui + labels: + - "is_top_app=0" + image: malex984/dockapp:x11vnc + restart: "on-failure:5" + ports: + - "127.0.0.1:5900-5910:5900-5910" + devices: + - "/dev/shm:/dev/shm" + privileged: true + environment: + - VNC_PASSWD + ipc: host + command: + - x11vnc.sh + cap_add: + - SYS_ADMIN + - NET_ADMIN + - ALL + + + xeyes: + extends: + service: gui + image: malex984/dockapp:xeyes + restart: "on-failure:5" + labels: + - "is_top_app=1" + command: + - xeyes + + kiosk: + extends: + service: gui + image: malex984/dockapp:kiosk + restart: "on-failure:5" + labels: + - "is_top_app=1" + - "description=Kiosk Web Browser GUI app." + environment: + - HB_PORT + - HB_HOST + - HB_URL + - HB_INIT_TIMEOUT=9 + privileged: false + devices: + - "/dev/nvidia0:/dev/nvidia0" + - "/dev/nvidiactl:/dev/nvidiactl" + - "/dev/nvidia-modeset:/dev/nvidia-modeset" + - "/dev/nvram:/dev/nvram" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - hb_wrapper.sh + - launch.sh + - browser.sh + - -l + command: + - "${WEBGL_APPS}/" + + IB_kiosk: + extends: + service: kiosk + labels: + - "description=Image Blend under Kiosk" + environment: + - APP_ID=light_pollution + command: + - "${WEBGL_APPS}/WebGL_ImageBlend_New/fade_08_new_05b_hb.html?HB_APP_ID=light_pollution&HB_URL=${HB_URL}" + + + HZ_kiosk: + extends: + service: kiosk + labels: + - "description=Habitable Zone under Kiosk" + environment: + - APP_ID=habitable_zones + command: + - "${WEBGL_APPS}/WebGL_Habitable_New_HB/gravity_habitable_new_05_hb2.html?HB_APP_ID=habitable_zones&HB_URL=${HB_URL}" + + chrome: + extends: + service: gui + image: malex984/dockapp:chrome + labels: + - "is_top_app=1" + - "description=Google Chrome Web Browser GUI app." + restart: "on-failure:5" + environment: + - HB_PORT + - HB_HOST + - HB_URL + - HB_INIT_TIMEOUT=9 + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - hb_wrapper.sh + - launch.sh + - browser.sh + command: + - "${WEBGL_APPS}/" + + IB_chrome: + extends: + service: chrome + labels: + - "description=Image Blend under Chrome" + environment: + - APP_ID=IB_chrome + command: + - "${WEBGL_APPS}/WebGL_ImageBlend_New/fade_08_new_05b_hb.html?HB_URL=${HB_URL}&HB_APP_ID=IB_chrome" + + HZ_chrome: + extends: + service: chrome + labels: + - "description=Habitable Zone under Chrome" + environment: + - APP_ID=HZ_chrome + command: + - "${WEBGL_APPS}/WebGL_Habitable_New_HB/gravity_habitable_new_05_hb2.html?HB_URL=${HB_URL}&HB_APP_ID=HZ_chrome" + + opera: + extends: + service: chrome + labels: + - "description=Opera Web Browser GUI app." + environment: + - GOOGLE_CHROME=opera + + chromium: + extends: + service: chrome + labels: + - "description=Chromium Web Browser GUI app." + environment: + - GOOGLE_CHROME=chromium-browser + + kivy: + extends: + service: gui + image: malex984/dockapp:kivy + labels: + - "is_top_app=1" + restart: "on-failure:5" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - launch.sh + command: + - /usr/local/src/Deflectouch/run.sh + + main: + extends: + service: gui + image: malex984/dockapp:main + labels: + - "is_top_app=1" + restart: "on-failure:5" + environment: + - MENU_TRY="gui" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - /usr/local/bin/main.sh + + demo: + extends: + service: gui + image: malex984/dockapp:demo + labels: + - "is_top_app=1" + - "description=Choose demo app" + restart: "on-failure:5" + environment: + - MENU_TRY="gui" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - /usr/local/bin/demo.sh + + x11vnc: + extends: + service: gui + image: malex984/dockapp:x11vnc + labels: + - "is_top_app=0" + restart: "on-failure:5" + entrypoint: + - /sbin/my_init + - --skip-runit + - --skip-startup-files + - -- + - /usr/local/bin/x11vnc.sh + + + registry: + image: registry:2 + labels: + - "is_top_app=0" + - "description=Docker Private Registry" + ports: + - "8055:5000" + restart: "on-failure:5" + volumes: + - "${PWD}/REG/DATA:/var/lib/registry" + + registry_tls: + extends: + service: registry + volumes: + - "${PWD}/REG/CERT:/certs" + labels: + - "description=Docker Private Registry (with TLS)" + environment: + - "REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt" + - "REGISTRY_HTTP_TLS_KEY=/certs/domain.key" + + + dockapp: + extends: + service: gui + volumes: + - .:/DOCKAPP + working_dir: /DOCKAPP/ + labels: + - "is_top_app=1" + + register: + extends: + service: dockapp + image: imaginary.mfo.de:5000/malex984/alpine + devices: + - "/dev/bus/usb:/dev/bus/usb:rwm" + - "/dev/nvidia0:/dev/nvidia0" + - "/dev/nvidiactl:/dev/nvidiactl" + - "/dev/dri:/dev/dri" + - "/dev/snd:/dev/snd" + - "/dev/shm:/dev/shm" + - "/dev/input:/dev/input" + network_mode: "host" + ipc: host + pid: "host" + + x11_xclock: + extends: + service: admin + image: alpine:3.4 + stdin_open: false + tty: false + restart: "on-failure:5" + labels: + - "is_top_app=1" + entrypoint: + - /bin/sh + - -c + command: + - 'apk update && apk add xorg-server xf86-video-vesa xf86-input-evdev xf86-input-mouse xf86-input-keyboard udev && echo "exec xclock">>~/.xinitrc && apk add xclock --update-cache --repository "http://dl-cdn.alpinelinux.org/alpine/edge/testing" && startx' + +volumes: + supernova: + driver: local + omd_data: + driver: local + diff --git a/station/finishall.sh b/station/finishall.sh index 8f5d81c..202afa5 100755 --- a/station/finishall.sh +++ b/station/finishall.sh @@ -4,10 +4,17 @@ SELFDIR=`dirname "$0"` SELFDIR=`cd "$SELFDIR" && pwd` cd "${SELFDIR}/" +## set -e +# unset DISPLAY + if [ -r "./station.cfg" ]; then . "./station.cfg" fi +#if [ -r "./startup.cfg" ]; then +# . "./startup.cfg" +#fi + #if [ -r "./docker.cfg" ]; then # . "./docker.cfg" #fi diff --git a/station/get-compose.sh b/station/get-compose.sh index dff5879..04fdfd2 100755 --- a/station/get-compose.sh +++ b/station/get-compose.sh @@ -55,8 +55,8 @@ fi D="${HOME}/.docker/" F="${D}/config.json" mkdir -p "${D}" -HILBERT_SERVER_DOCKER_REPOSITORY="{HILBERT_SERVER_DOCKER_REPOSITORY:-imaginary.mfo.de:5000}" -HILBERT_SERVER_DOCKER_REPOSITORY_AUTH="{HILBERT_SERVER_DOCKER_REPOSITORY_AUTH:-bWFsZXg5ODQ6MzJxMzJx}" +HILBERT_SERVER_DOCKER_REPOSITORY="${HILBERT_SERVER_DOCKER_REPOSITORY:-imaginary.mfo.de:5000}" +HILBERT_SERVER_DOCKER_REPOSITORY_AUTH="${HILBERT_SERVER_DOCKER_REPOSITORY_AUTH:-bWFsZXg5ODQ6MzJxMzJx}" ### TODO: FIXME: update wrt server repository! Later on! cat > "${F}~" < # NOTE: uses flock from util-linux[-ng] + +# NOTE: /var/lock/ == /run/lock/ => will be removed in case of a crash! No stale lockfile is possible! LOCKFILE="/var/lock/${TOOL}" LOCKFD=99 @@ -26,20 +28,19 @@ _prepare_locking() { eval "exec $LOCKFD>\"$LOCKFILE\""; trap _no_more_locking E # PUBLIC exlock_now() { _lock xn; } # obtain an exclusive lock immediately or fail -exlock() { _lock x; } # obtain an exclusive lock +exlock() { _lock x; } # obtain an exclusive lock. wait shlock() { _lock s; } # obtain a shared lock unlock() { _lock u; } # drop a lock # TODO(?): evaluate other ways according to http://stackoverflow.com/questions/1715137/the-best-way-to-ensure-only-1-copy-of-bash-script-is-running exec 3>&1 4>&2 -### [ -f ${LOCKFILE} ] && /bin/rm -f trap 'exec 2>&4 1>&3 ' 0 1 2 3 13 15 RETURN exec 2>&1 # 1>log.out start_locking () { - DEBUG "NOTE: Checking for exclusive (locked) usage of ${TOOL} (with given subcommand)" + DEBUG "Starting exclusive (locked) usage of ${TOOL}..." # ON START: _prepare_locking @@ -49,7 +50,7 @@ start_locking () { if exlock_now then - DEBUG "Lockfile: $(ls -la ${LOCKFILE})" + DEBUG "Obtained exclusive lock of [$(ls -la ${LOCKFILE})]" else DEBUG "Lockfile: $(ls -la ${LOCKFILE})" ERROR "Another user is already running ${TOOL}: please try again later!" @@ -85,22 +86,25 @@ Hilbert - client part for Linux systems positional arguments: subcommand: - app_change Change the currently running top application to specified one - start Start Hilbert on the system - stop Stop Hilbert on the system and shutdown it - - prepare [] Update after installing a new local configuration (post-deployment action) - dm_start Start a VM using docker-machine + init [] init station based on given or installed configuration + list_applications list of supported applications + app_change change the currently running top application to specified + start start Hilbert on the system + stop stop Hilbert on the system + shutdown shut down the system optional arguments: -h show this help message and exit -V show version info and exit - -p turn on pedantic mode -v increase verbosity -q decrease verbosity EOF } +# -p turn on pedantic mode +# dm_start Start a VM using docker-machine -> separate script!!! + + version () { cat << EOF This tool: [$0] @@ -236,10 +240,10 @@ cmd_install_station_config() { if [[ ! -L "${ALL_CONFIG_DIR}" ]]; then WARNING "${ALL_CONFIG_DIR} is not a link!" fi - } -cmd_prepare () { - subcommand="prepare" + +cmd_init () { + subcommand="init" arg=$1; shift if [[ -n "${arg}" ]]; then @@ -252,11 +256,8 @@ cmd_prepare () { else exec "${HILBERT_CONFIG_DIR}/prepare.sh" fi - - -# # ERROR "Sorry '${subcommand} ${arg} [$*]' not yet implemented!" -# exit 2 } + cmd_app_change () { subcommand="app_change" arg=$1; shift @@ -277,21 +278,6 @@ cmd_app_change () { fi } -cmd_dm_start () { - subcommand="dm_start" - arg=$1; shift - - if [[ -z ${arg} ]]; then - ERROR "Wrong argument '${arg}' to '${subcommand}'!" - usage - exit 1 - fi - - DM="${DM:-docker-machine}" # TODO: check if ${DM} exists and is an executable! - DEBUG "executing: [${DM} start \"${arg}\"]" - exec ${DM} start "${arg}" -} - cmd_default () { if [[ ! -x "${HILBERT_CONFIG_DIR}/default.sh" ]]; then ERROR "'${HILBERT_CONFIG_DIR}/default.sh' is not executable!" @@ -301,26 +287,37 @@ cmd_default () { fi } -cmd_start () { +cmd_list_applications () { subcommand="start" # TODO: read config and handle the following: variables! source "${HILBERT_CONFIG_FILE}" # only: key="...value..."! - if [[ "${hilbert_autostart}" != "True" ]]; then - DEBUG "hilbert_autostart: ${hilbert_autostart} (True/False)" - DEBUG "hilbert_autostart_delay: ${hilbert_autostart_delay} (positive int)" + for app in ${possible_apps}; do + echo " - ${app}" + done - INFO "Auto-starting is not enabled in ${HILBERT_CONFIG_FILE}" - DEBUG "Will NOT start Hilbert!.." - exit 0 - fi + DEBUG "Default application: ${default_app}" +} - DEBUG "Sleeping for [${hilbert_autostart_delay}] sec (due to 'hilbert_autostart_delay' from '${HILBERT_CONFIG_FILE}')..." - sleep "${hilbert_autostart_delay}" +cmd_start () { + subcommand="start" - # TODO: check hilbert_autostart and exit is False! - # TODO: sleep hilbert_autostart_delay + # TODO: read config and handle the following: variables! + source "${HILBERT_CONFIG_FILE}" # only: key="...value..."! + + +# if [[ "${hilbert_autostart}" != "True" ]]; then +# DEBUG "hilbert_autostart: ${hilbert_autostart} (True/False)" +# DEBUG "hilbert_autostart_delay: ${hilbert_autostart_delay} (positive int)" +# +# INFO "Auto-starting is not enabled in ${HILBERT_CONFIG_FILE}" +# DEBUG "Will NOT start Hilbert!.." +# exit 0 +# fi + +# DEBUG "Sleeping for [${hilbert_autostart_delay}] sec (due to 'hilbert_autostart_delay' from '${HILBERT_CONFIG_FILE}')..." +# sleep "${hilbert_autostart_delay}" cmd_default } @@ -340,6 +337,11 @@ cmd_stop () { # TODO: NOTE: any arguments? cmd_finishall +} + +cmd_shutdown () { + subcommand="shutdown" + # TODO: NOTE: any arguments? DEBUG "Shutting this system down..." # -h now? shutdown @@ -351,26 +353,41 @@ subcommand=$1; shift DEBUG "Subcommand to handle: '$subcommand'" case "$subcommand" in - prepare) + list_applications) start_locking - cmd_prepare "$@" + cmd_list_applications "$@" # TODO: arguments? + exit 0 ;; - app_switch|app_change) + + init) # |prepare start_locking - cmd_app_change "$@" + cmd_init "$@" + exit 0 ;; - dm_start) - # User should be able to start multiple VMs in parallel... - cmd_dm_start "$@" + app_change) # app_switch| + start_locking + cmd_app_change "$@" + exit 0 ;; stop) start_locking cmd_stop "$@" # TODO: arguments? + exit 0 + ;; + shutdown) + start_locking + cmd_shutdown "$@" # TODO: arguments? ;; start) start_locking cmd_start "$@" # TODO: arguments? ;; + + dm_start) + ERROR "Please use a separate script for starting a VM via docker-machine!" + exit 2 + ;; + cmd_*) # hidden subcommand-s start_locking # NOTE: Just to be sure!.. ${subcommand} "$@" @@ -390,3 +407,29 @@ else fi + +exit 255 + +############### Separate script for the Server system... + +cmd_dm_start () { + subcommand="dm_start" + arg=$1; shift + + if [[ -z ${arg} ]]; then + ERROR "Wrong argument '${arg}' to '${subcommand}'!" + usage + exit 1 + fi + + DM="${DM:-docker-machine}" # TODO: check if ${DM} exists and is an executable! + DEBUG "executing: [${DM} start \"${arg}\"]" + exec ${DM} start "${arg}" +} + +# dm_start) +# # User should be able to start multiple VMs in parallel... +# cmd_dm_start "$@" +# ;; + + From a7d240719bc8cffd4aecd32a25599549f1081819 Mon Sep 17 00:00:00 2001 From: Oleksandr Motsak Date: Thu, 8 Dec 2016 03:55:23 +0100 Subject: [PATCH 42/42] Updates/Fixes due to small real-life testing at HITS hilbert Server-side tool: - Better general Logging in * disabled checking docker-compose-file during verification as it takes too long at HITS :-( * removed general timeout option to _execute Client tool: + More locations for Lockfile (special lock group on Fedora...) * Try sudo if simple shutdown fails... TODO: - repair x11vnc, - fix OGL.tgz generation (for NVIdia OpenGL) - When should we generate OGL.tgz? --- config/hilbert_cli_config.py | 27 +++++----- config/subcmdparser.py | 96 ++++++++++++++++++------------------ station/get-compose.sh | 15 ++++-- tools/hilbert-station | 14 ++++-- tools/hilbert.py | 78 ++++++++++++++--------------- 5 files changed, 124 insertions(+), 106 deletions(-) diff --git a/config/hilbert_cli_config.py b/config/hilbert_cli_config.py index 1b253fe..472f540 100644 --- a/config/hilbert_cli_config.py +++ b/config/hilbert_cli_config.py @@ -31,9 +31,9 @@ from abc import * ############################################################### -logging.basicConfig(format='%(levelname)s [%(filename)s:%(lineno)d]: %(message)s', level=logging.DEBUG) +# logging.basicConfig(format='%(levelname)s [%(filename)s:%(lineno)d]: %(message)s', level=logging.DEBUG) log = logging.getLogger(__name__) -log.setLevel(logging.DEBUG) +# log.setLevel(logging.DEBUG) _pp = PP.PrettyPrinter(indent=4) @@ -95,7 +95,8 @@ def pprint(cfg): ############################################################### -def _execute(_cmd, timeout=None, shell=False, stdout=None, stderr=None): # True??? Try several times? Overall timeout? +# timeout=None, +def _execute(_cmd, shell=False, stdout=None, stderr=None): # True??? Try several times? Overall timeout? global PEDANTIC __cmd = ' '.join(_cmd) # stdout = tmp, stderr = open("/dev/null", 'w') @@ -103,14 +104,13 @@ def _execute(_cmd, timeout=None, shell=False, stdout=None, stderr=None): # True log.debug("Executing shell command: '{}'...".format(__cmd)) retcode = None - with subprocess.Popen(_cmd, shell=shell, stdout=stdout, stderr=stderr) as p: - try: - retcode = p.wait(timeout=timeout) # ? - except: - p.kill() - p.wait() - log.exception("Could not execute '{0}'! Exception: {1}".format(__cmd, sys.exc_info())) - raise + try: + # with subprocess.Popen(_cmd, shell=shell, stdout=stdout, stderr=stderr) as p: + # timeout=timeout, + retcode = subprocess.call(_cmd, shell=shell, stdout=stdout, stderr=stderr) + except: + log.exception("Could not execute '{0}'! Exception: {1}".format(__cmd, sys.exc_info())) + raise assert retcode is not None log.debug("Exit code: '{}'".format(retcode)) @@ -1154,13 +1154,14 @@ def ssh(self, cmd, **kwargs): def check_ssh_alias(cls, _h, **kwargs): """Check for ssh alias""" global PEDANTIC + timeout = kwargs.pop('timeout', 2) log.debug("Checking ssh alias: '{0}'...".format(text_type(_h))) try: # client = paramiko.SSHClient() # client.load_system_host_keys() - _cmd = ["ssh", "-q", "-F", os.path.join(os.environ['HOME'], ".ssh", "config"), "-o", "ConnectTimeout=1", _h, "exit 0"] + _cmd = ["ssh", "-q", "-F", os.path.join(os.environ['HOME'], ".ssh", "config"), "-o", "ConnectTimeout={}".format(timeout), _h, "exit 0"] retcode = _execute(_cmd, **kwargs) # , stdout=open("/dev/null", 'w'), stderr=open("/dev/null", 'w') if retcode: @@ -1516,6 +1517,8 @@ def __init__(self, *args, **kwargs): def check_service(self, _f, _n): global PEDANTIC + return True # TODO: FIXME: takes TOOOOO long at HITS!?!? + # TODO: Check the corresponding file for such a service -> Service in DockerService! fd, path = tempfile.mkstemp() try: diff --git a/config/subcmdparser.py b/config/subcmdparser.py index 0d6b0ce..29a3aca 100644 --- a/config/subcmdparser.py +++ b/config/subcmdparser.py @@ -5,6 +5,8 @@ import logging # NOQA from operator import attrgetter +log = logging.getLogger(__name__) # + ################################# # decorator ################################# @@ -43,9 +45,6 @@ def __init__(self, *args, **kwargs): kwargs['indent_increment'] = 1 kwargs['max_help_position'] = 17 super(SortingHelpFormatter, self).__init__(*args, **kwargs) -# def add_arguments(self, actions): -# actions = sorted(actions, key=attrgetter('help')) -# super(SortingHelpFormatter, self).add_arguments(actions) ######################### class SubCommandHandler(argparse.ArgumentParser): @@ -70,11 +69,6 @@ def __init__(self, *args, **kwargs): self._use_subcommand_help = kwargs.pop('use_subcommand_help', False) self._enable_autocompletion = kwargs.pop('enable_autocompletion', False) - self._log = kwargs.pop('log', None) - if self._log is None: - self._log = logging.getLogger(__name__) - - self._logging_handler_done = False self._ignore_remainder = False self._use_subcommands = True @@ -130,46 +124,13 @@ def set_subcommands(self, subcommand_lookup): return - def logging_handler(parser, args): - if not parser._logging_handler_done: - - _args = vars(args) - - log = parser._log - level = log.level - - # NOTE: logging levels are as follows: - # logging.CRITICAL = 50 - # logging.ERROR = 40 - # logging.WARNING = 30 - # logging.INFO = 20 - # logging.DEBUG = 10 - # logging.NOTSET = 0 - - delta = _args.get('verbose', None) - if delta is not None: - level = max(logging.DEBUG, level - int(delta) * logging.DEBUG) - - delta = _args.get('quiet', None) - if delta is not None: - level = min(logging.CRITICAL, level + int(delta) * logging.DEBUG) - - if log.level != level: - log.debug("Changing logging level: {0} -> {1}" - .format(logging.getLevelName(log.level), logging.getLevelName(level))) - log.setLevel(level) - log.debug("New logging level: {0}".format(logging.getLevelName(log.level))) - - parser._logging_handler_done = True - def parse_args(self, argv=None): """ Works the same as `argparse.ArgumentParser.parse_args`. """ - group = self.add_mutually_exclusive_group() - group.add_argument("-v", "--verbose", action="count", help='increase verbosity') - group.add_argument("-q", "--quiet", action="count", help='decrease verbosity') + group.add_argument("-v", "--verbose", action=CountedVerboseAction, help='increase verbosity') + group.add_argument("-q", "--quiet", action=CountedQuietAction, help='decrease verbosity') # add_argument, set_logging_level, set_subcommands, # handler.set_logging_argument('-l', '--log_level', default_level=logging.INFO) @@ -258,7 +219,7 @@ def run(self, argv=None, context_fxn=None): # # call the logging config fxn # self._logging_config_fxn(level, args) - self.logging_handler(args) +# self.logging_handler(args) # pedantic_handler(self, vars(args)) # generate the context @@ -268,15 +229,56 @@ def run(self, argv=None, context_fxn=None): # create the sub command argument parser scmd_parser = argparse.ArgumentParser(prog='%s %s' % (self.prog, args.cmd), add_help=True) - scmd_parser._log = self._log # handle the subcommands self._subcommand_lookup[args.cmd](scmd_parser, context, args.cargs) return args # run() +# logging.CRITICAL = 50 +# logging.ERROR = 40 +# logging.WARNING = 30 +# logging.INFO = 20 +# logging.DEBUG = 10 +# logging.NOTSET = 0 +class CountedVerboseAction(argparse._CountAction): + def __init__(self, *args, **kwargs): + super(CountedVerboseAction, self).__init__(*args, **kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + new_count = argparse._ensure_value(namespace, self.dest, 0) + 1 + setattr(namespace, self.dest, new_count) + + _log = logging.getLogger() # root logger! + level = max(logging.DEBUG, _log.level - logging.DEBUG) + + if _log.level != level: + log.debug("Changing logging level: %s -> %s", + logging.getLevelName(_log.level), + logging.getLevelName(level)) + _log.setLevel(level) + log.debug("New logging level: %s", logging.getLevelName(_log.level)) + + +class CountedQuietAction(argparse._CountAction): + def __init__(self, *args, **kwargs): + super(CountedQuietAction, self).__init__(*args, **kwargs) + + def __call__(self, parser, namespace, values, option_string=None): + new_count = argparse._ensure_value(namespace, self.dest, 0) + 1 + setattr(namespace, self.dest, new_count) + + _log = logging.getLogger() # root logger! + level = min(logging.CRITICAL, _log.level + logging.DEBUG) + + if _log.level != level: + log.debug("Changing logging level: %s -> %s", + logging.getLevelName(_log.level), + logging.getLevelName(level)) + _log.setLevel(level) + log.debug("New logging level: %s", logging.getLevelName(_log.level)) -class MyHelpAction(argparse.Action): +class MyHelpAction(argparse.Action): ### _HelpAction?? def __init__(self, option_strings, dest=argparse.SUPPRESS, @@ -294,7 +296,7 @@ def __call__(self, parser, namespace, values, option_string=None): raise BaseException("Help was printed!") -class HelpAllAction(argparse.Action): +class HelpAllAction(argparse.Action): ### _HelpAction?? def __init__(self, option_strings, *args, **kwargs): super(HelpAllAction, self).__init__(option_strings=option_strings, *args, **kwargs) diff --git a/station/get-compose.sh b/station/get-compose.sh index 04fdfd2..c634f18 100755 --- a/station/get-compose.sh +++ b/station/get-compose.sh @@ -1,9 +1,9 @@ #! /bin/bash -if hash docker-compose 2>/dev/null; then - echo "DEBUG: using $(which docker-compose), $(docker-compose --version)" - ln -s `which docker-compose` "${PWD}/compose" -else +#if hash docker-composei 2>/dev/null; then +# echo "DEBUG: using $(which docker-compose), $(docker-compose --version)" +# ln -s `which docker-compose` "${PWD}/compose" +#else #! Get Docker compose DOCKER_COMPOSE_VERSION=1.9.0 # NOTE: update to newer compose version if necessary! DOCKER_COMPOSE_BASE_URL="https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}" @@ -38,6 +38,13 @@ else ln -s "${PWD}/docker-compose.sh" "${PWD}/compose" fi fi +#fi + +if [ ! -x ./compose ]; then + if hash docker-composei 2>/dev/null; then + echo "DEBUG: using $(which docker-compose), $(docker-compose --version)" + ln -s `which docker-compose` "${PWD}/compose" + fi fi if [ ! -x ./compose ]; then diff --git a/tools/hilbert-station b/tools/hilbert-station index 28aa9cd..edd6f6c 100755 --- a/tools/hilbert-station +++ b/tools/hilbert-station @@ -18,7 +18,13 @@ LOGLEVEL=0 # NOTE: uses flock from util-linux[-ng] # NOTE: /var/lock/ == /run/lock/ => will be removed in case of a crash! No stale lockfile is possible! -LOCKFILE="/var/lock/${TOOL}" +if [[ -w "/var/lock/lockdev" ]]; then + LOCKFILE="/var/lock/lockdev/${TOOL}" +elif [[ -w "/var/lock/" ]]; then + LOCKFILE="/var/lock/${TOOL}" +else + LOCKFILE="/tmp/_var_lock_${TOOL}" +fi LOCKFD=99 # PRIVATE @@ -341,10 +347,10 @@ cmd_stop () { cmd_shutdown () { subcommand="shutdown" - # TODO: NOTE: any arguments? + arg=$@ - DEBUG "Shutting this system down..." # -h now? - shutdown + DEBUG "Shutting this system down... Arguments: [${arg}]" # -h now? + shutdown ${arg} || sudo -n -P shutdown ${arg} } shift $((OPTIND -1)) diff --git a/tools/hilbert.py b/tools/hilbert.py index 1711ce4..fc63b1a 100755 --- a/tools/hilbert.py +++ b/tools/hilbert.py @@ -1,4 +1,4 @@ -#! /usr/bin/env python3 +#! /usr/bin/env python # -*- coding: utf-8 -*- # encoding: utf-8 @@ -7,9 +7,11 @@ # PYTHON_ARGCOMPLETE_OK # NOQA from __future__ import absolute_import, print_function, unicode_literals - import sys from os import path +import argparse # NOQA +import logging + DIR=path.dirname(path.dirname(path.abspath(__file__))) sys.path.append(DIR) @@ -18,14 +20,31 @@ from helpers import * from hilbert_cli_config import * from subcmdparser import * - #from config.hilbert_cli_config import * #from config.helpers import * #from config.subcmdparser import * -import argparse # NOQA +# datefmt='%Y.%m.%d %I:%M:%S %p' +logging.basicConfig(format='%(levelname)s [%(filename)s:%(lineno)d]: %(message)s') +# %(name)s Name of the logger (logging channel) +# %(levelno)s Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL) +# %(levelname)s Text logging level for the message ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL") +# %(pathname)s Full pathname of the source file where the logging call was issued (if available) +# %(filename)s Filename portion of pathname +# %(module)s Module (name portion of filename) +# %(lineno)d Source line number where the logging call was issued (if available) +# %(funcName)s Function name +# %(created)f Time when the LogRecord was created (time.time() return value) +# %(asctime)s Textual time when the LogRecord was created +# %(msecs)d Millisecond portion of the creation time +# %(relativeCreated)d Time in milliseconds when the LogRecord was created, +# relative to the time the logging module was loaded +# (typically at application startup time) +# %(thread)d Thread ID (if available) +# %(threadName)s Thread name (if available) +# %(process)d Process ID (if available) +# %(message)s The result of record.getMessage(), computed just as the record is emitted -import logging log = logging.getLogger(__name__) # __CLI_VERSION_ID = "$Id$" @@ -139,12 +158,17 @@ def output_handler(parser, ctx, args): log.debug("Specified output dump file: {}".format(od)) assert od is not None - if URI(None).validate(od): - if not PEDANTIC: - log.warning("Output dump file: '{}' already exists! Will be overwritten!".format(od)) - else: - log.warning("Output dump file: '{}' already exists! Cannot overwrite it in PEDANTIC mode!".format(od)) - od = None + f = URI(None) + if f.validate(od): + if os.path.exists(f.get_data()): # TODO: testme! + if not PEDANTIC: + log.warning("Output dump file: '{}' already exists! Will be overwritten!".format(od)) + else: + log.warning("Output dump file: '{}' already exists! Cannot overwrite it in PEDANTIC mode!".format(od)) + od = None + else: # TODO: testme! + log.error("Wrong output file: '{}'".format(od)) + od = None return od @@ -587,7 +611,6 @@ def __init__(self, option_strings, *args, **kwargs): def __call__(self, parser, args, values, option_string=None): global PEDANTIC - args = parser.logging_handler(args) PEDANTIC = True if PEDANTIC: log.debug("PEDANTIC mode is ON!") @@ -599,7 +622,7 @@ def _version(): import ruamel.yaml as yaml import semantic_version - log.debug("Running '{}'".format('version')) + log.debug("Running '--{}'".format('version')) log.debug("Python (platform) version: {}".format(platform.python_version())) log.debug("ruamel.yaml version: {}".format(yaml.__version__)) @@ -607,7 +630,8 @@ def _version(): log.debug("logging version: {}".format(logging.__version__)) log.debug("semantic_version version: {}".format(semantic_version.__version__)) - print("Hilbert Configuration API {}".format(Hilbert(None).get_api_version())) + print("Hilbert Configuration API: {}".format(Hilbert(None).get_api_version())) + print("Logging Level: {}".format(logging.getLevelName(logging.getLogger().level))) log.debug("Done") @@ -617,37 +641,13 @@ def __init__(self, option_strings, *args, **kwargs): super(ListVersionsAction, self).__init__(option_strings=option_strings, *args, **kwargs) def __call__(self, parser, args, values, option_string=None): - args = parser.logging_handler(args) _version() parser.exit(status=0) # setattr(args, self.dest, values) def main(): - # datefmt='%Y.%m.%d %I:%M:%S %p' - logging.basicConfig(format='%(levelname)s [%(filename)s:%(lineno)d]: %(message)s', level=logging.INFO) - log.setLevel(logging.INFO) - - # %(name)s Name of the logger (logging channel) - # %(levelno)s Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL) - # %(levelname)s Text logging level for the message ("DEBUG", "INFO", "WARNING", "ERROR", "CRITICAL") - # %(pathname)s Full pathname of the source file where the logging call was issued (if available) - # %(filename)s Filename portion of pathname - # %(module)s Module (name portion of filename) - # %(lineno)d Source line number where the logging call was issued (if available) - # %(funcName)s Function name - # %(created)f Time when the LogRecord was created (time.time() return value) - # %(asctime)s Textual time when the LogRecord was created - # %(msecs)d Millisecond portion of the creation time - # %(relativeCreated)d Time in milliseconds when the LogRecord was created, - # relative to the time the logging module was loaded - # (typically at application startup time) - # %(thread)d Thread ID (if available) - # %(threadName)s Thread name (if available) - # %(process)d Process ID (if available) - # %(message)s The result of record.getMessage(), computed just as the record is emitted - - handler = SubCommandHandler(use_subcommand_help=True, enable_autocompletion=True, log=log, + handler = SubCommandHandler(use_subcommand_help=True, enable_autocompletion=True, prog='hilbert', description="Hilbert - server tool: loads configuration and does something using it")

5n-jzPF&($gtWIw9}} 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 WTN?#~mnIqbG19w!^_7lO?Ee9B<6*r3 literal 120088 zcmbT7Wn5K3xb9(-0>Y-dyHljQ8w8}gwlvb+9h(*@g$;^`fOL0vh;&OycXJn>b8eh_ zKV3g4%x|q(vu3?B^FIIgF-Aj8{v{d-8XO$lOGO14EjTy?b~rdtA}TV_QhIcG3I~TR z;j69Z?&vM=X6|CA>TG5000*b4*MoVWx`j1-{#MiLh7xu5xBurs|Jld(eM;2H-YLE%)_D8(zBH58YB zAKFm&+qgHyS2*8&Y!vCoEm{`yBYHyVZRLpFdACOy?bFuO_`raDT20=@p;8kc@TgDw z1otF?2)dUJoDy)w=Dc_!Me=1$^4I_CdfmjeUxV@#@>IL2-;yx25_u-_G>~z9|Apd- z-{~st$#L+sQ0=UoVC%76MYrz{&Qw$9*$sgEv#Juda9_5|iMT-$yn$S06rH#M81W%1a?8#W>gA!!y0Z zK94fL(ysosxZIU|T3hCAH<9D2*_Erl`&pTo%0}j&S8-~kJJ1jFh^f~RGr|{d&%VTQkzkM?Jd%ug$E1?Br#d9L=Q`x@W=X245-l42wN18dw9EUY*HV1c z$zmM-%@7uUy-la;Ou)~)`I&TQLpCw=&q5fc_!HTElXCb z=DeeoN)RGjrXlG3n6K9UySvKAvjtPh3t>Y0NbuN6r7??nC32Xf;3L{+qyjiOy%Qak z%JM=MvY%B?4u9H7gXuHyMMwyCTBPr9f9*V&T2sG2A)qX7lC`2*3R%%=7B|>5h;bkT z?YpD*oz6$l@DQFCe{zzD##z+CD0oxl5uva71>M};wuTdh8X zN#0V1)zrJ`p2?}B9W4Rx6m3l_JdsP@GczI%aO3oqeyj# zzCFiD)9f|l&Q`&fw0R6ESYn$xid*=MG|P+;*jk49*qFQBrTJswz+?B->xH#~fU^V| z+tw|lbo0>!Do@eQuShYR*+`>yYgM6J7uhA0c56Cq*{P!A)%?=TfvoLYR0dBuEcZwU z=YN-b$RE`wRT;^7BIuN7z_D#8ZA5$Q93`xjEC~%?!G>`1Pv$|8 zi0&Ou8-%*o;RSy3oANcm9$ZwJSGw1ue;M}9E%sFIDc75E8H9?kjwLeple|Ait~B-j zw(g%MBau(+o~x3#_D&;n``86*@Rdw+;-elPOwbhfy41^&nV6Rn_)fl+`{0C#3fp9< zuz0KJRiw3!o?Kh?iR3tb!?%9Fc8S@}E~~vsg^9~|F=}zweSDMoHy4&zxI@2Ywhpfm zPfY}WZ~d%cCExj$u?qgiMv%pO=Qaqt$yPWT?C??cUR3dpup_y(JbbsNe7I(Eiib zWTx@E%#N~*T(xu$>`famK3l*uG=)=}?OC*un-n{TQKvDN-p4P_drW7BvyYyV!#TaI zK=l5L$O=k4!79OWMKS1TWru7bX0hHS8SB&AUl@LBh_@Mi-ew$_aK=;&@vlbNEwg-z zF#X?++|IO2)!fK@-zW;GI49T*+^oi0eP!kb+h?I|ZbtL%2eXWq#P7Pt8^(Tjjx6k0 zB#;!I3{sEz;$+e+QCKT3VkdS@T`!kX4{mi<&z}4lm8$`Q)`L?}x-XOqiVQyyygp=) z6;#}_t!~Pt(QP8T*d9{n27^L~qkiNY2bP5OQeq=a3yf9g2RX8lVwA~}6YnTl6L2C!Zhep7e;h>{y43sEexRcowLgeNOjhD;2v<_9$O z%RJ>>W|HU9nUB4|!?~qr$Idzp{vqvB~*3ltTytnu^kf2BuplrjD%xOd+R6ppF=-XvvMB7~W1nJjx^tY@_7CD|qiz6R|G~|;0=zXuU4Err)Ys;UrX}Y&OA_i(+ zvA2iftUiXjy{B62rHPPi%kOWVzGhP~7wuPR=6`qzAAtB(>}1{Li3bVA#qYPO3&cE= z%+@0?(C9vFnIpjDQ!zbgfyy+cd-=)VY53+6FOU~R<443)J%3o5`L}`Y3qtA<=uqL( zD6c*nb)6Yu1J6sEDX|JmPnASEes3jMn_0)5TQpZ)g}m+{=F0R3nrFw#2c|?Wv3W13 zC%J?@1;4T9xi?}kt}GP~=H&hf!m`C}7klX@?q4?%c!6)me~PNa`#JSr(`Mv1Udj&e zb&x;8Nh#KJMD7y0Tx-}83#|O&I=w<|yxHzB_lJXV1xLomzY$gUurDa^ikfZ>DfRj) z#v>9;Bq7>us5kzmT1@V!#zH-ycUCzjq}VTp>1Eiw8}XdXc(51&^WVy*m~dp@AG$`a z(ouB{E5{sS%XM<|2cfTUHISYA{Eb>#H^WyLv~t19Ns=3tV#h|hyOdDXSLPl}82#%# zm&NgZ6`>Wag^jPZlT7N~@s6+bIENHZOYtY_Sz3VHvKj5R|#kIKOVG|McgL z${ZW({3$2?;1i~>Mqj-CU8VkR&M2j11=8jXE`|x8mt164uSyYQkML13Erz`wJ5|Pp#?vp&DxSMU0Z}!v6I$iuxcXXg`?V z0E|+}i^n*EK43b@Ah%6E{=LCp+%HjeS~VbtNs1{dWd(;O%)&kZ15!b$f@~d%lDEN# z(8c($S#Puh+UJ3qJI zG3{XX@Q2mSnpz8;QoDyH{hnoHg-032kjVa&70xDvzXbC;%!}J!?ic%~%yRP7({Vh% znhFK4UX@&53(O56Q+Z{LVPcc78?m4tylMTet^BS$Kk-I2 zc79>hYoRC6`tJdTGWKUN%#XONyB^Z+cekq_Yrg(uzmYaCC*QK);Y3-ODk~Jc4~gYi z>n?Q@>20h_%6`3Zz7=qns#r2g`lZxM(X`x)aKYVA#+J;;`Qz$Qz=FuDsZvT9>+&Jz zhcT!n9O+ADmuvY89&qY5pKysQ{`NbJAmT=f0T(VIJK=MeU|BVrbeZ&z18`RD#DqIx zhm-20q0(_EI`YjPA%fQsd^sg^#xwnfZfCZ@H35NLtH;Ui7mAH6&&3!l)jIZeWOSq6`6}> zoVu`MZ1wsK&3-#=?-EAjxQ_1JS&pHPPlq5g-4DO8^XXQqB8@y8DE(7j zy=$l`I`#ZQlmhSdd12sKDAm98{^`r^tbhJeO}wATHe⁣zmJIt}QW)~~m0!iVLE5p2>qC!5%N_F9uuQSBz2TJT8OK_WvGPvazKRH?S4!3&!VghqILkQggS zUp@Wl@C>tjQKEs_%Sm zE(P^7R{XK9+wo1#OHRAgE2|gLjHkhys2)vif(OUDg@+@8i{JA)>tA_#Y_-tKA(wa5 zTqV4}QmR)2ZI0oXGp)YYnHgVg85`G?8DxsGTx8FTXT3{M7UWtVb@1%6qzw3}Rzz?} zd#m$a^6#y&jC56=bp>oDgKUN-Mjd%M7QeOAMJBpO7O$C>1_Cp)Y{g9Sy)bHLKTFa7i!K6_Vv4N zo{S4?rQ24vdoz0>p9Wesv8$l$dFP~8h9gKA)21)H$b&)D_e%!)j;z|k6t{}YkTsL! zTDj%VmE8S<7{hf?dEb*5ebD;G5xUUu0~XfoJQxm+3Qkc*Qrp{PKNlrUTXrfk4kM*% zGk!DP3Ju=PLleNhr{Mg3-gG7y~WC}y){(J7@df&9p`j608o?vC&U z-A_Xu7QB>noy1rKtBRA6U!f@^4wukYP0h2)Qstoz8@8A}8a1f%d{L+GIkQf?7o1d_ zIWM6z{)m@CSGm{b-C0_Wf*K;RdzULL8;OZO*J=!NGEP=Xf8?#@wI%34{k={KdhHaQ zBSil*sI5PPon|OAj!lnhvLHg?iyF;9>YZ-Bm?I_d)h{d2;uy8bIxSyTWP2G+DJB)azcVn;ft0a_6}f-(O))1MbGAl}VvT{~?k*-v~??>6|*l zk2GQ473#9T1W6Tn5HB+9+4{fX@p%oJCXPCqv>ZaO@Itat+4TG*W}L)1aVgQXn*X*e556;gsm}TCAe(CY~R#{b?Dilp5MmSBF~;2 zIHr?|0RdLmST*Ypa63Ys;}c|eydn(*145Bz@@YY5vcd+Q`6FZD`e#%bJdo?e)l$<_ zCR#CeMtC-wd{V5)X>>nlTeQ_shRcDRva*r^jRUL+BZpDir15p9Z_$!#RJ&ne=3v!@ z^4^+%E{$dqoL8JXrHHB6ftE7P--ed2`B=%Q!JM~w(pTjz3_O-{bTruW0ijGk^swi7 zB1_$s3_3kF7yHX#^qt7l%3cBsp&^%c7odq>t_Ni_t04GaK|<^_#PFu)qT4J2T%-B~ z>@VVgple?P?r@n!F0xsw4g>j(lPon~r48%X$~W?{67msOo6AyZgEbxqS!h4IA%cM0 zAI`?&svTLiij=76CWJ((fd%GrCatKvTJch8q!EIGbouF(@7BF_YTuY31ADAQHSMQc z&Usr2tE&~lfU$N1&F#Ib$ z$F0UA@k4;!?85YGeE1+X6QT);$Vx`*_7G;np_7CD zERN)zE25fdoB*ObyUZf=T~rRZg14{S1iwUgWZB&1;V0xty)qWx(&~@W1CC)3E&7#< zqCp~=AkCXEYU!%k{E7o9^dss&j2h^qBQa8Vtd)X>K3_0{G$Y!JlruNacc52a)zOR6EJG^MexA zSjgTKDWxlMF{T?ki}QS=oxgy>>*HDpTen{L_On?3|pgXx&HDVLqDe|vg24VaBFJ%u1QJUKjA zc@kuPvlc}OGj8%s;WTYk*ek!3#YXi(yxgCoEtF5nuo?MyBVzfbRD%?k=~*J6gmoK@_^QAfA4!y*uBy**cgo&rR>a6-e1Xk-aN zFs$a2UQ!#?`34=ff45J(+ODnxCIC!^=%VGyJapzy3QMqfyTS^ogfAAu;YVGRGO!uV zVZOUM%KVZaDC8jYDU=129N+%dG=RS0{dNX0w|)o3ORB^6vacyM7$c2g=Ys#v!SyIO zwQs*ogN&C0?;P8NfLH5wHab5Tms%y5JncZCR2cdAs>q@z_A`BvQX#4gGl=!=kF*GM z!jB`vh9|Efnv9XJyD#4V>*^lpilw#g?@1r!l|hMdKsl_3HSJb{h}s1m;&buqt*YJW zsPGX+A;;IRu@aj!F4xEA#M~C){-*HExI;Ak(GJ{H-B z>PkmpUd%)PU(=KXOp|$6JpRt4!y_Q0 zK4HnNrI3wgTL_a2dk(`~+wMXerr&QN%qxYp^Hh-DO?M~t8lGlol{qn~4>}M;Zmt+DOjUImq${X(=+}I!u zZhw?iGC7Qg>BezH5ZNZRnmiq=6gW+qnQ$3Ypi50&L#9Cw9)^1qxW5)a%*Kt?FvV24 z3^sk5?XmpVc{wTc%1RRjvgy@`&R-qt7F+zh)+Czi)}1E{)G(Z*|876Zz&%_ZHXRKD zku&o8{fftLN`DaaX)lbauN^;&3sA9PlR$}U*57+V=!7$a8@xuSPQauiBo7ZHnl< zQT1R*(lw@SfpXBBvu))T-;3dfNaU9!9}+U3s_YEwoE#aLx+4u&%$~T;lf-WOReVR8 z%1l~>YNff(2Gd!a5~?d!dlN`)KZrZNq!cp(&J=tRiE3+~-J(oH`t`EerS9fmUE4%a zd)*abX<{2#h-&#_?7)J_5b-(vaD=*{!4rv=eVxH>NT-~^CYQMsaJ6JYZa@gNRxA9r{*(@)W79SnKJhyQ4O_C`qY`e3uOO zz3GA3X_z-HYnx@Z<_?N4+MUz(Xs%83ivOAF%|?2FQA(aWVG&{Eh9`KubL%n~WZITA=-@hoS3$@3k| z38MPe>G$@BQL;RRPj|S6ez%O#U?%5LO0`Okz(jaagAL(jA_{!iT;gx4ZnJnM*HB3V zIE`E)>{kg=jl4lm4|R)PD*=_hFU%)QVe*SW1A}!<>1k^>VXMZ*&J-MROhzGVm6! za)`{??w0J9d${;*N{Rx0B4E~{gPputqd|e+ zVz~3aJ>M-dYH(9Bkcl4&Jp);^3l&K)T^=s60|AIo9?}NCfUPaBV1y zyZuHKc%fb@+Y!t5Leh$)=v64cy7mx_9*@CoC(ES6!FPFW}h<>{bj!+QCvx>%!U;7 z07aQZ)Sv0N5)G+;C7xCi|XWIwP@-6ZTnr{h(IHbv( zsgZW(mWK;+zX{Fo}z}^j|t>i)reR?g5J?(VyH%h z7@b(*nsPc`>u6Z@LR!0jqF93OIFH|Pe%j&O!AQV)Twf%q@_1YtD~pMnLaRBA2*H08 z*)f@b-?90t_p7<)6AO#kPs$S|-kgd9J+5IB(I=t2(O(k?WT~jZ6$Q_fLW_F&04Gj1Et59xB@ja8dyaG?RmKE)QHkv;7VR8!wO=(h2&I;`P((3T<<~{C zHPu68!$U)_(Js-lfyW)JRyOFzk2*1|%lJg5hoNG@-XRU>(&LKX8Mv76r_-+0(AHqa zl&>#*lM+a`Uy?FUh>sets{$D@F+u~CNBjsWg4N7-eH&Z`YXY7P?_wlpb`y2}Gav@D z75F^N$be052}&&TNmq#-8DqC{=Pi&$OHr966U6iKP%Ng~QL{hYpCvW0^*5|mU+;d& zSFw44jWR^FEy&8F^o@`ogAUOmR5KBQ&SP(y;Q~*p(r$tV_m5tk(~_g3*>P$?R3Xt9 z&InY_-FKF~@!Xh}rJt&((06dHdP7vSk^4|1qF-QQ7rd5LPA_%WoG6-Y!Pl@`Xnre&pj)@U+&7YkP_kr}NHzKZjHcx6 z8^XJkX!Wo702kn=A%KJwb%hE-Wn)3zVe4efYtAa(v*Mp6W_h#4WRTTq(Z)F-=I|+{ z4GwcW&&ezsPvR~CHS$~S=t3AhOQgQA4=y|^TAu18sleA**Wlk{$=~QhS`%>R`F@JU6gs*sAV7t(^K#~7f37N_QVmAX$I+HVAvzD!GT+~5 zzka+sdbyZWLOU5D8sVzWLVOz?nkV5UVHCY@5W(k5#s)Kf1)1z_mRAyo#ok5}tT9o~ zhe{J?zm(@4wIJh?$xe=oe(}^7v!TY3!z|-WC1N!v(XOyfbK5D1|CfPVYt{}62h>qH z+2S%k?rar&eIg8FkWVDr3fM&U5?&!p1KW32zNBY=kx-v`X_O0b_3y!lWC?ryxaoCg zAVN8tOFI!b?ds5Nf<>J3N~Obep?Q*`Y?#6;*fZq$9|u{#IyT-ho$)gl+YQ5G{)+ouStZ8lczbqR!l+9E+iWE3~dbM z;Zj1_rId)amviFMe?**R;HgiFO_0mzaCf>krp)(jLy6omHbbLX3e8vyP(QD{9PLvdzWa5Z_%?Uy<69L9#w>y^sX^DbZ8sdLR6M8 zA8OnZb0}60-~C9g(W*psztE5rV#K-LGBrDfFt%;{FN)V8$^6Q-nBj@hxU*o%tw=et z#Z?uVIBf$3FgBU9d4*4u3m7$`6X;i5&H(oaW(|A%!G+Z-l(Hl=1bK-pBy0>{3V;KS#m5G{2z~+YyY*|9<;SUoq*HxJ{I5uQd zTTO*Ev#y@MN}CaB===d>Ttt*a$TL|4{N~M>JA4?_WUpl0#`B4&lne?y(IQp)(yJGR z@T_uOYD0IzJbFibDg>_LINF`oCTZNmJ!0S+!_v4WzekVi{btT6_ zk9ECWFdt_Dxs2-K08&7Y&jf=NY^@#xtnxTd6jO3X>7J%CU&;a&lhS<#5mF(b*hUkIOqN|AE zvo=5^C+)tn#Rj7z0+8t49LVqJ#@a;DtipGTVlkrES|2ph21At4yABjrBH4}k= zWy*(}4*--^GzriwGooQHzYz>H3j`OJGl5>j06&Jy7%pf%6HO{_;H6(sT+X}gJk!JT zJ_Y)Cx97WV5XTQ$fx%5v0nP6s4TMQhfaY#^z5rQl1qI+oI=cD!jDPI&e;x?ZlpzZW z$~$r2aaceTQE)4{8)dT(kyg$ZdiiGwor`bEW&Z$^JYmf#A6Rv7&*>-$T2Oax2EO)hkcSBuJKOLo4(~&LDYk5C& zoaSETq6DeuS6%yLpNS7l1q-&uBu;wQkK9^diU_hLb}eHiDggY8!?syt{7!O@W*onqdhYK}h5Z*t;G_32Xxx4PumjMBi0<&ojvYO?a4%p8CKQ1vt4BquE4MY^j>PYE z!0maj(}gymfEnIz4JSX#LlMvIT(92wIuoShV>o{Qll7hiwr9FAQ7GT!f19cvd*i=DzYd8xaP8@Czw;ne@UjCfSucPIV zzIIxiNvtwESg3m)oG;{|#ADS@#cMmtm--pt2PZV_;56Thy#at9Yy$JeBNNwnlT9Go zo{t*N3yCSmwFIPYuQ^xHqrafnVUDZCs@}!28X9>L@JA z%b7Co0HcF*abG)o*w-m(_fQ)?g25+e*V;LOA@5CBi)54?pq;1aQ`i(aHHC=4ZuKQaLypPPpVyY2DTo>}`Vv_7_4PYx~Jd9i*%Bni9P z^I#s4Ow5sm1dM7uiDSoztT_ze%Pfy9Q9n=OSMSnd;(rSA*^Re*`;evAez^&DD{B2L z9Yq2~oteStNm(>>`8Vu~Cmn)V@ zq6|}C)H8ADl|DG&7a)hBVDT?Kt7>XKzpKM^|C`eRL+2KH02o!pD47*{9L)a`xdIj+ zu_aNTa|j4&6L?_ycm1km3r3;8`pdL&TdjA8ynbCk^T7Yh3w6G9Ove2rKMagkM$r?4%_6q5=V5H zC1QB1#D~EQc2;1;^VYt;Ed51sDtQh)X%9h=%K(s7e;1axgB2yf;*xI?g%6>lxx(2` zVdxK)v4sI@e*I`A=2*p4j7Q%MY6b-miD@1F0H1BvtozY1nb%9tZweEhmYoR69XTv4 zu|vtc8ytGJJvNjd^vDbVoO2}uvr{fzkqiKC^Lqd~RNtW10TNH3RYUY46bYR~oiPqn z7!D=JB`Iga1}lKkL{Yk^!^-^^v^TunBjB#3DE?m)*`LW z682~OvvluC2Z>z6x|O-5h4jYC;ZoBO0LbE{Camxu++7&$>Jd4>hZPkSEcoJ=t&Ik_=!C zkx1u`-H2ma$qP^5Lq3bfKLE6K2}F)?72ETyO|4_q7+bNKZi^u7+?6I-P&9qE))t>kM ze!4YcKO-)LzSJ$(j$Gq^<0h?35p?gm0VxnjAs}OWmZJJs-l+O_Oja{|L6(K3#!a<~ z^j*?c%y+=PMbZ~z>HC2e@|m0;lYa)-uDw;tE`Iw@_&z6E{@AFmCf5fZX(ug`3BZi+ zRAHbNRbBMnJKix7OAOCwcx*Vd%Q=9v*+nBJ69h7W@pD>bjLF8h3}HxN6vpV-R6=37 z(YX!ID`It?tH76Z#_%QkBNDf!;)$W@8}IliyKQNO+rij`LYgXS`*3^F3%}*ywLaU+ z5%FPMzOS=Mpr2Z&xi7GLS*oL!K1EV4F}*{2h1ySGQGgZ!8Gyn(GKiB>-F>-6R#*~5 z}{+gBjxFQ$r`d6Mo5q6k*bu!tNv z0;D*oVu397F(K%)oB_^cOb8=JSkQbmr1JAA3Z?(J0M4<6Ad6!TnFA)1TAElkcAhX9 zmcSdAS_!%6ZlOGg`Fk3pq(1w8D7DS39fCzC@+APMv!mIwQODNlEv0*Ldx=Sb*VCt# zkcl`JfM`A^H0|Wi&k~snN=zmgq6kAZODiDdzOL-K?r>qaRqcR}aE;eYT#|L~WC5ct z)4nsq-wwN;S#i}X%om*tfx=%RVz{{T>x<7u&ia569kejKj=-S+u_yV`aMs~{$+~CxRH=YYho*%Tv*8S7Lrs!35E=LrTMbQ@i3Iml ziYlOb@?k{Hk6sq;g7ZGJbSa9HbQZ zIjTi^h+BXVMIvB4U@SGYQjy{ zD%e`&SMICs^?G~N3bPkd$P21Dva(q1`YMoS2?KMX_NstiV6=?SVl+$-){|-k?C>7< z@N?vfaUQO4+cs1&x_n56*)7QqpnVS-;n_nlClH?eE|(`FN6D&YMdpUd1Pa86X;s`% zWmK9(Y2e&5JOR!TM}V+lQ&vblT|*3;M%`T}KvK{Y(Yvg4g5;(d$+9W>+4E1 zndlJ^{n6KIcG)51V7KltK8IPZa##c^*Jf92=Qt)^SF%hM|f&IIvJF+yZvrYv%S@SE4ysl`F^O zFP%;qAD0|#o%VLywgOC^kR23n;7xO`dUyJ6RMR5(1mdc_Q_!PGJzrt+7m&&PTudg= znyYZ8mW)SwC}c+^+VzC;Ug|um`4Yli?XLz&J$|3^YE@-LxJUzFkIniRxR$w1RY)=Cgiw#yCbMc(9R8P#6J z=;f+);M01Faj_J@eHk+QDT(|*<}J!euJwr(N=jo=K;&86CDT5m4Ee0>_rEc&{u?`? zvrvYfz+mYGdy*jbJrom8lFY}#v@ODj};$9h`q4C5H-xT8DEm3BeQ4mUdXX#m%e zZ3%1(AYz%wS0cy5oACp#3o{kx)wNuo0+ z*C?=vY4NwFjyU;wQFxFJBJ<9u_tcvaUOI6!tDMjK$u&AcnfyPQZYM#Nqli9XT|g(p zdi~oJ7QsvV$RAi}&JkfqX&eyK{GL)OwmO`&ou&L4w#u+VVh|Z4&+e(B4F2aLdOO)U z2e#VoJ3)W3`$f)x=6!2wuEZtit?60$1%388KMM_evf%e;^HSiy4k+K<*8W?7Yf%#Q zDH+Go2K1Qnh7;e|Y)$ip|jmJDk?H+>~>I`|G;A;bOLpZ9UiUlV{PtmD%>n-@5M zw$Qk?+8@t`GYP3@O7a;xOm_{ zim}G<4bsX7#vJuLX7h4(R!}WKdo0iy0u=tmK!toe2V_@hhx6w9f~d(|Dd0+wd3GfL zV~$5wmQ7FtUR!3n-oE@99^HZ~lnolOvN#bMr!UcM!tnMxkTn`I3;vRpDaZ1r^(2J#J0PIF7l|dCpp}GAPE-o&upxY+2 zD++665;X`V4e-J!0i}OB*Y)lYTq%29L#E}V4l9b_4eCvzPKr%2N``%H1(92aT_0NcxE1fj|Cym?-e z@5MKf(|+1sNv&pY*WKUc`OP<5*(NINm$-SV-GL!28%!r~|dW zG&X%LA@?1#K&I!aqr+^4sKH$>!?;$3~bn!*k288rc`^;HT`J_+{jQo zs`c`d9m|K&gD+S1ewF?KxK1WebpB;;x+psSRg?COJm8XY{O!8Yn}Aq#wBB?i;5E2% zF^9~KNO7K3jmKd$OKbRCW`6dabZ#y;y#Mm-Hd^-Hcsccpv+Z6>?D5*NN^^TCbBsvD z;WiBUWeQ-*8U!2~Bgh|tBK_`cWg!MB|FFZ>QS+G^8+s6+%>QAcF~G-VDt5Qe3uId{ z&sA?NKyEJZF9U`dg(lAfD*$12(g99_#^gf4=D`zi>u%`}m}`cb<8u1zypBu&-qZxS z1I$qjBwYo1K#`nGz(oQXi-PUhSOP$-tT8UL!^XcHC4g7~iahest9C%z5Fx>ol7T|u zEdk)R0A<4Mk!(im!L($RES{Uvzcx!Zjl@3hL|O;)R9%5e@Z=YD%0gN|V_Khg#uM|x zB*TzT2U*KMj1Y=$m1%#|9&q>xIAC5O?f|7=USHHCbE7!c$rQo&HoKEWaTC_!_s3!T zvz5}%tng+v3`>Q#KYlq8OFy=>`8E&OjTU2rX(0_zntV2cAdN|w5=ZXGw3di^|Jwr= zp9X8B^5dJ-YVWG2XA?@UkVgt2wUhwi9`95Na7Q-d#_3t5S#7+(SHM)0$`1ko4O2>I z2~FJtL{cU&Aj2P~ZBFj{{mHbVd)`{Cuho;liQeAeA3 z8-1ipBfJ1VsH3_9z-PiiOk#JjJ0r>^%Pl!69^(uE)e>6bRFwmo)y2us@6-VFIudvZ z_-%+CTCdm9!(Mta-@Q08hgNZ#-4!cms;T9PKyoa=O#mcN8p>cV@;X|^SqT{a3wyDK za<66(ttKI`9B^ff+haxr|JWIU&fs1L5IJ7%`8sE3;LQ7ZD6o&7KKgIK~4|m(J{WAHt(@OLH17K`zwjf>nBYEyMu{if9z1hJ2qb zVsm(~aphzeP;GS-84!OsPZha8?y~9Rh9tu`Fal;8BKz|igPM1hZc)b{O6|-eCF-FB zGqjP;z%(t=><{i%y!*uhnXfL}Vm-HjgG)yJD`9Rid9u1f@|>fZPz2NQ>-Hl+&_^Riil0qZ*^>Zj!B8yGuPUa72lki5fQXU!KnbE9 z(nc`jkTjMkox>v(1ugqkB4(e$5P;-{x005n)M>5&=#;Sh54eynA&B)$SfMx=B@^6+ zCQC?SWwIO22)vzzRap-e!{~?4Lt;tifD)+n)Mp~WAlfo_2O|T5AHqzeo_Wy3grRPn zOimjIDCSFLA0%38MRc`N3Q^zwH|nDFfCGx_lH_)p9J0piz~>-(&V*^HfMkVih`B+& zU0c+)=s`d(Pc9HbrWnf$F;9{*EqHrWzkz8fohRTbWiyuN7>#y{Ma0z(rSoz#yOR9& z?9lXD_W3f=vM;`GxX%oj`}js(Z6~D=$qey?aVNuDBh5bd%?T5*8_)r9%a3^tLPGlx zXr^3+C0Rigx*r3WEV&PEd6$O&(xH7uaRA&2KCBP$NmQhaNV<1`(PwFrJU(cW;(J;$ zuq@H!UWBb)b0CH%d>rVc`v8cZLBm5HMariP< zqufN4x^YNO`?D0%K=$kMPY4sAca)+*C11{y0t+@~;g}O)NLjAa@kHF6I}|PD zQ?j1h7LCtRksi_*W=bkj{O+B0Py&%~T?70`I8tUgcoU61p`gd+fd`XXhb(G5yyil0 zG{6J2>$--s6;`=%(OroC#(FhZ5uLh|M)vUyC=rl@=)K4h6`wAIDc(%3d`Ga7f%HS( zPOj@D?IDO!nb{g^0p+(dtA6F>Hiu!Ssl)l6)w;>94@X1;c&Nh3sQhf5tD{PbsZ${r z3G2NL9VA7LvH$h4Mc%=J3`jBBq~UfDZlhlo1U)_W5?gHFlK{Us1B6BjFXI$A1xTE! zV5sUur0l++2gH-$YG`Ay+THn-dIS^NEz&mD&reSP(UXWi=8^g~uA@r|#^vgTmmY-c zj<#*P*&^MTqmvC$9VLZG>hgi0m#az8zs)+x8rrjQ)itr zRCm91wL%Ggdb8OIM~YvPX?n(92&*}Ixq-0@#AQ;LcAWcGj0aFK_hSTVzjsoY$*#{W zj1S=L>*w`sh0ju<)bd0;gn5n60j_TqgJ_LaO}ZyxplGpWgeDGj%RrEtDqZNx91cIX znFajslN`l3+PR<71|Rr{oWqZq`Xf$?VDub?g-7+$RB4KFg~Q8}UCn~z$27^e;a3B0 zDgsV&dCOkgY}C29Mb3gU(JoLz49J=Tc{ZHfQ>A5J{Fk_CWML%rMIbj)na%qje7$Kr zlyCg@pM8z7lXb?vui42m82g$SkzG@=%aVOx24h#GXjDpNnTkj#j7SU#*~yaZWJ$Wu z(f4=%e-G~0|A`0EwVc;^UUPolpW`@YSTTgiP;@tDqUX2fMu?Y0qrmCV9dR&)HwuF^X*19u2$Jt_Ycr2n@4jVsB)CO zDEHjK-cUA`3|i3C_HA5d!LwYj*S&}DWF2QuJT6&) zm1D|a_Tc$qlS@C~zZhPLSF;w#!i_qoAC(b@R`VW8oY&O-r%9d_HhEcrsy7`1WS@Ol zh1_VpkPcPV%Kt6+WhQu^v^Vq^U4sXIOFOB!w`dAy)*Y7ew7%F|wZ%lB63{9p(PfcyR#L zhDZQZRwR^JjlxMBEVD~xX30d4KckFCn&*0He=^AH(#@PMQ2|TyAqMLNH z`cT3pbQY^6*Wkte_qFo%)j^N*zEP#;SzXwhVbYh?)u!H8%$`twzk_X^Lp_Ma+6ugz zzs(L4^S!#v%#b}-xBx(mZ)+BnLyF-KshO<8YlLI>SQfBKzHg5hwrKbQn2&y3h4A z&&4o;b07gyw`Er=8VK{?4|0-PvKa`&yG>dcYTXo+R>gzIk&bI@)}q&7X+j7uN-0x( zV>9ACxSs=6I_97JTpp*$OLbw1Lv32`NFg-fp_4yjCJ;-+z@(={Lb1{7;a^qgSS=rZ z7tY4DUW-jgB<|ZZmK%fAF%L3HvfPd2=f(9=^KjSs24z8+HvvmHu-pZ>hO@RTX<7NS ze{>0U9jc;ZH63uK_`BzSuKbcyW@LD`BVf1(q!Suo2AeH))<0_qX;gQQQ4q@KAf z46XW@06zh`YRYiZv7crBjQYyT5%{xepO@METDA&t4%0&kQDxF_ZOw3dYl6Ga;t$0P zoeqJSqg%+JuJl@gKs^8^bP-PJ-sHZMeC(gjMEua0a@8aaXA+RD^^VC&lARuwXXGV^ zrQ?zqo=Btv%LZA7&N38~baRpwc|`}X#~Z24fC|jXpW}HVyq6fj?_!3hrMgA(591U7 ziqmuOMPI1vjl4+A`Q-j@mkrx0EVa`3)jcZn;40vM`tir^$}G8DX4_S`M1DP;fmp|P zt6rCV&lzteBpnsT{B=9%=KD8eLTG3)>%nMx0vQC#aska7F8*&QhMErc(lwp)*0$j;KuRK3moS^dkh_@Jj(r!~k81k19|3 z$P5{{n5Z+R{8{S6OPIu5PknzD9DY{W9dIQgiwz`dEhhqoURRQV-w(?7kN3(EZGoJO z+3%uCgb2EZIsYi^9@MhL?Gpjj2{m~pF6ly0#h1hzmtGkU?iqMpUwLLD6p=f? zEJKO~k}HzL$IfYH#M@qMy!Hb0R&+`M|1u#PiW2_sm{UYX#{0l3HbJbn`ud}VkfxzLH*?CK5~T-*PRE*8!7GFQvHc_J z13HrCg^KA$FG963S5JXV)s;K1zCFKkZph^H2CaxRZ!y^QTjvd%5L;`m+*?T@eN)zk zeB9!nH=qNq>`^bSl_4J_zP`{_*z}>HP8ULB?;N9C}Q@{Px^3t8;c1r~~ehRp0vcGZ!!? z6ZOy^Lf>Bd7Xv)Om71pFliVy4c(di`$J07~ASXcrUB4_D6+?kZnaf^XZIKi1DioAM z1ppIV;fvn2jsTU9S9=15;a65!m&-tXBp{qz4v`LZS-?NJMT>ckZozt&0Br zYx`*R1)bp;!%iR!5+u3__O>+)DY`xqtxGX~j`Fmlk46!6Dc%30G^yUNDt5_x?%e$G zf5}tuKxKj^aWg=+0&P#k@3q(F-^Lnzia|YY0+duU-l3xH2D*ZBf6qIoT{l^LURa%B3=#A)RHbU3I z(85X7VA~UOV-Xc}663}#5ln|TwYf=@pH zM7ki^#RxFh~^ziO6$Rq9T^O#Dzd&$u$7dZdKK(QOhf-~hpr%88*tKM@! zwM>EG%4@XNZ5trVUP6_r*YZF`N}sC|bec}KMPL|A#|=6@YnVpMyn~zskwV3{IASyL ztcJNBzd47p5p;Y& z@gYiiJ&OPY*%3gtht>qY&Lv7}fFS|hKw(6E)WfzE@IP9B6a?d{28w_sv_u5Y!=cDK zz|1jvbba_S^gmVDL-SH}%Q6!WJ8lavm{T%+7woW92aF2nIAjoG^UuU(v{snUS}FP9g6HV{&Fa?TxF_20X2s!$C4#YE~YP+H0)$GCj}bNT7Z#fI9O_(YE?+r=Bjlc}FgCYyJ9oFf!X>anjM z>6C-W0I>36O+7nnHcE3j()w_9{NZo6N4ZgfOK{id3dxe@8ji}W^)f0d8nAaGtYaj42DhmUCCEygB`DQp9e?-y0!$8U57-j~nP~!kR*@$apVY<*mceA!1Ig1&8fFtLe&N)_;qka4tpujR9 zvQo_wIA=}A!<_EicT8N+vuGvSmQvrNa6bOnE=fBZ>bfvvAZ)W>hFm6_ z^2iWG)!DcmXrKZ{HW;;bF`z-vg`Kn(xP`3)ZLgnItCA>^EU!|A-np}>o*TKrL3`t8 zi-8{fmwUrs{96yTkhz52zc;JOu3TsrM%Ar;xNm{TloTa3)PR#NQREuJo`T`WIs%o| zGA(^{8m7>@YXj>tR}*kail7%M?BlJvGy;tNEYIRMYqOz}%aoOsHRoYZ;VF(o1w>5@ z939BF$$)wR_aY+aeD5DW%;?n9uS$GKd@K!5#(e=FET-TC@NFJDtQ{gOmncA#y~N{n z!Mt#7~OBJK&}AnNyCF5^LyMV1-C+ zoX^&vCkYZ_?8g#?e{xLRwA(rf>u>j6z+*EWzLcidBPu8mqiqe`fok9}%D?Wz(UyM8fn8k(bq&9Exk` zs7aHT<29B@f+tu|vsUVRYE$G0^5PwFtbc@{boRY`B;}avTO^ijlA`($s7=v)@mFwE$0tI#*^q8=y92Vxx+9mr#Q99V5UYX=0Gv$5s^y z^5mPft)OSMIHTrciC`1_(SDoV5}W+~M;RG3IZ3%XRp~qfj(IY^z(I%v@eIdGO}-J> zSfYGaP%`^nv&K*dS6RNO<(-Le+H$MyU&arDeeW&jy#Q~K6dYR`d$kbf1tP$RcjBzD z3Kl@n{RtA0>3{bP_0=M>1WY0hXH`Si^r^;RKFq`K>9~L`%Il*+MWeimk_2LVhvhJ? z7DJoD@IckjM3pg-XScXOE`)@FIZ-CjVJr&=(ON`v??GPH(W;X;ucYI2x|StZ|IV~0 z=7D!r^W>K$u)`IgC)Oa8iJrD_VQJ;~jQ1X|j5A-qNq2yd%s|v%Z(~FZ&e@$DADZ{8 z@R_91sKn?(PrShWg?oPh`4S&6nvT1FPrw)gky#UX#%@Go z!2^3s)aYoTcapF*OoNLZr1&DDv?GmZ1AzC3OQ2{b9FDSZ#a^_5@4@G2~9@%m?C z5BhXbH=QnO@WXBO^_?C!Q5cW~!}4W}B01mv-uAi|!(u3DB1cYYj+_Ynz`thrh6UO# z60b~*0kMt;y=^>~H<)nTro>>15&!c$&MFJ-`QE8t+3GuZZ`51?3jKuC z)(7B>89Mig<;T?|mgh0V6C#N@9AECR#fL*@7`GuDBne;qE_;3nJFT_S$ccyU5Igxw z^?$F>9vpfuS*I4SUpt<~;c!%cT4TErbqsQRnxcci)9xn)elR#ab7V^6AZ>>+wqH|m zab4*>tpk&Ynu(6^P2hbQoe@VF%RPPxB}!Tn4EPehJojH-9yk z#Yt&${{0X0@T8Xpr(y*?BE4wmrqV~YGUd|1f)2fR7eWs={I6u-U&HbY;dj#Ug0LWC z_`~Uf*LTwBn+|JsesjYYVqt`faFNNV7o}-RklY~{!4y7{fe2+96NIVx86u0)@sD8j zmhk#aJRNNNewrZ?l-Dg6D}j*11wzdpL2cix4*fS7>`zB!fhEgKXuBmX3JOa$NP65o z58EzC!*S$#!t#vaHz$OYjp5kbG`m(~P5aE%{oaYFzuHVI;xI_XBuv2xPB~q3{ik{5 z@RmpfR12(H@sNh~X}D)Y+O8F$gMJWUx;c{ms)jlo{_hF?2sw>(5VZz=Q6~Pa$^&IV1JCrd zkXEi6x1$=g%RfaZ61KC``j~UKVKyt?o+3~4*ukhe369spX4v9gb5mVkuChUZkcSvH zLQV7;ZBi;*cf(=#GVz*JbMEO4Cn8%j`<6TmQyO_i)^kUH&Z|rdKhdKdRb}FmfMptB zGg(k530Q<*UJ*B}9sx(N=!@8lcxQaD8aggu1tMS^B_v%Dr9npYP9+{z9u^O~Ce*QL4xoaK@$-kW`0x}fN2(D(LpJ?$@ z>Gxh)*Cq(U(m?8`Gd?eF{adrnm;Vbhfe|5DJNF>`0dsl?B)8bl5PmeF`Oap^`w1t?1)KVb zl?f)uWq{rKv?BtyewDtuul7I>3%saYGB6hZhgj#vi1n(JGPr4yKj; zD<+P8i6+RF|It~9&}{te1r~ZNXv^k_vpnD&7ZwpQ1ild=&|J*}BkD|yuE}q^iRcCT z6!S^oY0J4gY zyR!|SwevxR3~Hx<4ht-hkK}1-JeoefL`;YQdKMeP9C`J8RHz|$i?Z+NOm4_;|0KT` zGz7-kG7!CUdxJH^4ft7zp*mZ6*MZ{;6xloxvlJE%C$SOWv6{VodF@Lc$j)e9tU4KPmC)v!^`@dU9_Cz}ilF=u+!L3^!;)LWDg5{4 zGpen(WvF(#jSSpOPwdVo6=I@-j1L$0Zz5#TJox(JO7X9?Z`=<~z-TI!p5SwZ_Ijk> z0cJGr+e$R4T3QezWyHbxmQTs=N|tBb{PflKF)?}kI`Qs7$$r|zI-d25eR%Z zS5}4|6{}2z>k}10D*O})a1BF=D?S4^s7<>4gL$DjLm5ED}mp2$n0$r?h#2XCM-^2?)-F`^?v8PM1!OR%O*dD_O|=&hRjpF{&P}@t?th{0`*t z#nUnRENLs;;kw5Xc8^`Vf;*CEyy-bL@FGE0fXn!3Um1sLQykx#{Zh$p#B0w}^YT9W^irDF+JO-hCxdV(ZXa zxHjOc%6NtnK>;}aR9OtWjlo{7t_(s`_m(0L*8;X^T|Fe?4YUlDBOHUqA+ky8Mhurj zUl$)>ijqFaLA#8~Pa|gkjQO@gxarjpROM?-f`*O4(p(Cj za#N;gYqUOEN7)-e+w~JvZdef8vkfK)4fhGyq%#zp7IT3zD05co$)nb-~!&d>6X-rNbrxP`YUry_I7LWTx*;x3s$-Vdan)ob|Y^b@!2=E%6B}ur@rAKMZboot4b-02OS1`2$SY^aKAdxI|WKGBAI4SpK zkAhiL*Mq+B+ze_pm;{+)%1>RZ5;BO%k0i5ofW^=+L7n~vVp;qA(u?x+0v(Ki;re*u zF0mI&$s3%e7FT@7t`X=Z-2$VFY)?x=OU4q>feVZmlL0mULga_=;|9y~sMy=D1C6$4U}Nr)pjU+fqqb zTR~_qk0IX(>xb4$FI>9h;RQU$C4Xzwv>RYqs)i05HRpL0RLQOlKc0PcA$z4lceMMZ zv4H^WbhG3Jc5|9Pqi>AejO1LQ566mgGIPQ>Ny9t3bNFLTn<1n&{G+?ZO!b5)O)#L+ zzP0wdl=_<>9!zP0LND-0sTi4Q9M*ww)AtfwEIa$x<|<3hApp2&Ci?dFfhyoIQVv__ z=(TiX>3(XN6nC~H1hRU}u;D>e$3ti;Y4NGhJQaVJAz8Fa*q=D5rhKY--g&ahluOf2 zfkw!QFZ0m>fB05}bvuJ*xT^auVV* z=5`r%lq#^0k*I_+fLe6r@Fi4mwKfvH6$FyA6u|E;cvD)OYnrZPKD9yy_m zPmJQb5Ho>!NF)lJdGK5eN4;JK4~1aM zxlx}XFW8k?hYE4619t@N8y`Q7?tK{eSOG$fT zC?2PKLIoX3JK{dk+Q}&!z9}Ch=jHP_JJ1L47= zpSBL#3t`w>_8}Csl;?Ni6XY{>*B#RMYKsDVbr$50xUN^GaDw0(+67X5enLkHGqhp6 zZN`TIm}-Lby)@F);4Uar3ui`1tlGMd|0|@vbuh z?GlNkJWVXX(3;VA|>-aQSNq?+B4vBlDAML=PSLP=7*v{lmRj=e3s^>0WzFYkaqrVTG~Z{81z{Ws)!0Ln-4X5 zZ|Ds9u*t!a7@nuDC0l&fB5CQN^TmRwcsuunc)IG#WjpP)Ye1-s>b-ai-X;djPUo+b zB+eK|mKOGtp`aJjcj2^yikWgvtK2sXNKt`h{y>$qIWfQ19hah+Aef?NsNnHlO_Uak z*-FG|?hfd8o$>$n>e(T^0(n0>@xvPu)z!5nqEkr^$00t?(X+0YLwqZRAha;v^^Fq7C6z}O-V1;di9n5lQr9 z%<~KiX(W_W*tl8YrDHk;h;^_5Qm$Me3mZLq_;LXR-oPt1=|N_%^2y6e==yj=W$-$J z&Jbp((j_|Y!Bv1^-!$?|lUHyI{%Gqo2uB8pK^)s7+Da5ILGN;|V`1`)oQkxKa;-HH z{rS3v0tD7HS)nnQbP-F(ozfab%jCKT7K9_Yu4i-W8~vdGyF%DTD05+p)ducRcevmn z1w@%zO+8~-GMGckkP$1ybuGt%~V3?r|!^+X-0Wfa1h?-uJ(dSFtW-qtXqc9&4YV* zql-k4lVBKlQqJD89X{U9Ge@os(F$AB9R}qO-S)sGwBeCkRl^|FqI9`0UPvL4#qiCe zSC!z{+wdfGD7_z?I)K#G%%gUP%Yq8V$T@*c)-A1O+gKi4!|8n{v>-^a4hcHkytzeY+&KQ8Q%=9oh|9Oyz}$i3@JDdXzuod)-8NM)~$x zl6aBtOk)CPisr$%kn=KAG{F>71ry%scBCWJWBln3m@05K9|GRYM8zW#p`)|QBv)*% zr&H?Fr%UMSr0o)3g+A=ez{%ajuE10VJ%0#}(^SLE=^v3UFfm&Qr5Bi&(UpTi(Ow1? zTVk%zxy82Kp`og+>@LueP#Oh4&Pb_jVl0wo;ddy7&wi69ZK-85H-qxI8iFj2x3>GWl~4yTKj?dXL!JTv8!Qk!E&weNiT zQjh(1z+B+7XMMhL-0}3%d59Zwt|92yN6$QE6jIIcm#1fl z*oVjptndd)c&9bF)PGnuyXBNw4rTymxygUnrNP~sw__?4oYz-hz3^~z!;1PB0AVU(u%dqEImPT`1*Fi$*ffm+ol*4< ztvd4to?clc(aJWfu?=^4c<+u(bntHB>!4QQoQ~c$QMPEll$)G{GFP2EiT^oN~MP^EsDSYl_{3$smJ461gor53?H&+G3;WL z(g}!rWziiEY~6%FZ|>A)_U6BV8a)4I-0AdkPWa=kVAAuJ*~PLs(c;{)egzF*KY!eV ze>HFq!O@eZ!}C4}<%Sp&jC<^atD;AK5kzcDo!Yo=x!2&PCtdvTXN_~klF>aE43S>f zs?Hn{%juXi)=#a-N#p;G)>-lt75U#sB0eE)jfpYI{t^N&)*3d)$?e-eabiu60F$ovSsL` zf#{@dNX%pjcKv&GE{grgNxf&xpVIE%c`P~{t-u{ zr!SNFBm?3KDEP_kpV={`UHA{?pQNGA{)73V#CRyU!?}&CJhw2KnoRW0)zccgx* z7TSG#Zp*Y>B6;E{n*4Yh`3H>u=qh)#V2u_q@R1nITp%jqf@*r97YTNQ)TVJF^JT%o zo(pxk3RN=&XI?_IfL$iNyl$jCh3mgF_oWzhp5`~T`BNX1;_Rwn+xyc~o$~|Hzn#~< zU+a82#XllCm(*4+c?)~kzgS;0TCe){h3uaT;KdiB48A`Agi#S27iS0Etm;mwHnl40 ziI8-$Z07J&(e0&sQ=N+~oqHv#^^K$M8;q+gfqFAwfu&t+OwKCjA8uL`a6@a63V&$0Z# zm@8L~8A-Bm%Vt*OdaVBqOXd6f?&3tlCnSLU*ciF^nd7#yxo6v%4R=xJ+jd384l>_u z3-?cIwV8a#ZJwKm7fW2u*!g|rUVfL2uwb?zYI%J18@^ZyeP|Nq$zzwLdCz$lv*N(kfmi#rRS);;y=kIsA`C|AN~HVNxM>jU?hhsF(3AqwTm^ z5Ygy5aIN!nA~nL>?qR*~kX%-AxO&JY!_CTz=?mAIo*rpQO;u!kWihrF&Ru1D-u;vz zdMp*u3!+wmvr~km{U_Kr=BWm{7l&SHzG+U(`gN@Lq(OY^FI3Mf0)iFlwNu*r?SG-+ zYfi2Ii})79)0ro?`SyIramFAdR*)#=0=lanuwn89QX2y3TYtL|-ceveq_;#O2~;Ly z&xf{j!?52I8MQG)u@^wA)v;{+o-$hq>30O8E$ z9E<&TuOAsyoB;D@#Lsg_>~}jg`PG83ft(fHoR1DzdHg{Sya;g8b6Tw)-3*`^V9~Og zm1B0~ca^9SZavV$qHJ^fZbuh4Lzd#%F!%nYmg zoAP$=qZ^M>*?_at1DE*t1E@M>fVkBgWS@vT)ZPcys0-U2bh7w(GAbcpVWCWd{Yb!SXul$l^>0b^N|ZfnfMH9lD)x)njHnF+|&2bfs9DQkG^5Rh7F0H;+- zYH65fAA<<;pWj|v5>;a8TSkIVgACRbgaZ=>WXa>fGr6Yx8pz4G^vKG62`ws~cu2%T zt`U7Xn}nU5rw<^tgnBR2Lr@q~*d+550MX#>&%ie4t!&YapxcWZ1Nms*!L^>R2hnFk zH*SGFr8O2PZtnal2LaNzRRb$^!ufCgl)qs1b@@pLjFH`~E-hncxOTL;)DgbIyC?*I%UbE+KgC z>>gwoAOjR2T$4buN=$zva>e-p1fEnGm-C*|hwcqmDs3d07LEPno6sGxys8|a9TfrX z3WW_T5LxYZlC#spjZzE!Q7~A&ELFJ%5(9S&JNV?T4hVp#KD9x;7HK1J%O?DNyTL&SIz9-Tj~1R32SM2hM!8v> zvKIl*HNVC}7j(G&y(?|8N!saEiFwAbq_Q~uPoh5|E1v*Tm&Bc3)eM7qQH0a6-z0Yz za^vw3bHn7@?18S+N6_pr|Lv>FImP+u`9eK91|}A@?f~42`26Nbx#N|@V64~1)LR=M zBpmXY;#Kx7fd&ENE?c*9St?UdJ!r|J07Zsg*?n)Km3SPt^yTTL@68*n`2b$yK{%WM zNQ7e^f3Jamm>I@Azn!HrB}e`pv?o&900uS}&<+31GxQ#@S}ENHV%8%GKp|8O+6o|D zUe@nhBKnO9BLF_Th04t#EACz9nf}zZ-sdjtyh*QBHL{nQBRr2W?kQNmkhlC|P7>wz zR`+Bwq7J&-cL)RqU;Au%7%rR~JdmGDR|kRg))r-|P{_>@`J_8IM9YGz>86#UXnNyR zU^lOVYug$9vJ%_%GB(b)eX+Z=Hx!nfUnX9LUl=eA9}c{4s_p( zEDXYxjHX7D^9B|4j%a1CU2UHftWFGhh7AWi6)2rkNO z>MjFq3#D2kQRZmfMGzR*^{P8~+5YIA-=sQAwfj8}3!S{&vs4qHSz z*&_BFu-{)#Zv&0p;rE}8Ow97zi)>uyKk@~RH7va=sMU^!UmLDX%{@2tD3AbL2kQmA*L6PPqtpWAtjfzE_e;i}R9PETk!v9L(NEcpmYXU?nomknD{Wd{2z(>K zHDw=Vxc2+UZC2j%26Y~G4L$ddpD9XXAewd~huOe=eP@T+w;X(QD{)gMn`4yItQzxr zSwetzvGi$kRx#ktk_>a5KGShGxt4aRn}6DQub4h)$VqU zS9K+K8`hl}osoBun(OxdR-sSjafazjPmy#fvA?rDXv9CMhb)i$A2J+PBmndew?|K`O2e(!Xh>yqs4EZDbAj_Wr2?`!;fq|Fbqd5 zTWmf%+5rtmUmamuEeOr2=sj}NRy2}35m-}&I?VUo>XmbOd983z786c=22RGj@X>Mb z<@HM*a6Rgh)uOE*Pk67J{{h}a5ib^>Gu!Shwm~9 z59l!3o>TS>ce(^#3FZ1>36f0i2SLHcc*3ttlZ)jiiNu$19yvk+mh-)wkeDwy^ zsw643QxbFgo>sP$ht|PNVz3w&RY~A2zV?p2DJ|A3pYP52Pl-;s@$U6DCwTO{Y4C2j zUPJRoG4*I8IQ#tSD35?^d1639>CI2gKDB!*K09&4N7|PYaKk^uzr^f?uVUQX>&P3V}>@uf|CvaHX< zIAwjSb%+h+W2fO&C$Q2UC!_LmJax&`A z0Gkone0D?8D$5g{s+*j5$Kj)F@@8K8`IFrjp}Y%#H6dU$(q z!h3R;4m^a(P@B}pJix)4Kk6%|U-Q~4v&$`v$GpZ$l)+15X$}(Q@{6=;;?m_0@FG-@ zs`vY1(gjzu**_~eSQ*zC_47L1qRf`-pgwH2;}Pm@_^MtrEW7$CxM0rq9G^XeiHZE^ zsg?vJ6~czD)Qe9@UUHt5+Cdw zYD;FQwU@Scyo%P(^K^ymZ~j>M5+7`t%YA(7yr8tfOY~J)dRdKGay=}k@OK0H;9Rsz z)S}liGIY~@tE4E8oli=ry%))(-7c`%{4R`r|MK_?_u{A70za?q*KS7wOQ{5#;HO@D z@dEa#ONMqvSc;yl1cQ!aNm_-)$jVtgi+GYaFbKZ2 zLg???yoL@fYcVu>(`1c$RVtbxbocTPYKaW7`nEG5Rd-O)4T4;W_~7c3B)P7Y&7Pe| zoCyIoVzqnCmlbJQMN{05htFV>^HXil81k@{k#{QA6O@WY=b9O~;Ek#|yVE=ZytD~W zs;xWMpZDB=$)j%tyZI$o{a|^?(==CmKgo&D)cOz&)V?gP8G(< zuS~O)hL>i}@z2|tc2JMB%$JK?sko9CCV%uYG+@%o%({jq-yW<7 zK&%%uOWB@ezib=xoG8CXjkeMBNW=~Ql>c&*ZO;w`@^}l5_BYgc+|2fQn%AQg1J)Uk zg)g4bpxjtDf0?@O&duh|#cyMl4(GFW2Y%@pz%g9qeL;i{EAQpV+3=MuBzW$WwZ&D% zX~hBtMg+A)XVt`F0kXd}4gDWwo!!nB9#u_U3r2E63V$$Z3nx`hh#5W3C}WqkOW_tY zpO*ZN+mvY@F?ESjb#K>Ly459J0KYXX;j!DXd%Ko?-azi7aVCbsv)>_tGD3zo1WeE;ya=kBh_*t*;A z@;~=Nmf8RMsD7#3r9@RcmrG+alzuf z9v3dtbno(&>boGBbvF%HFxQ7zw9-9NW7GWoap#uigOns(`joGiO=5Y6~>dLGK%J2))8W$*{!(*=MiwxMPA!Vy7pQ9TJ8{m#j~Sio#xu) zUyGTE=sxu$!!OvXhQ$`479Fkuv`?3E&V3FB*qnF4^h^Ux{9T@rZ8#}eGc}8tur%L6 zhyHLD&sGOpbE>>MMp#z0E8D?cHrwRSkN$Nxgnd;c=SAwQUwe;m0%Ufg6=di$dsdq2 zrXM&gbi}uU45pG$;j`O6Xx}j<%yxbX-^?rEkE2$wSBFWv{2EW;WfYZtViRMLsVQ8c zN>3p_-=W3nSUA4=vy7eG;LmpH4D%9h_ow&Ta#;~o`Juqt%l5Lw8(}TKQH&2CyymKx zb~L>;%8gAPygq5_w^$eU7dE^eHtR}114G?DclAau8AgAWk0U`pLYy^QxX1y<-N>sZ z8TFz7=kU95JTNxo5{ii-l~ZnHQm_EF&qkP(J@nt%q2mo@ZY)Yd$yWUmN6Br)cHX%c40wCldo|;5To=HsC${%Hsn*q zl9t}Q<7%)6Q%v%i716vN)V!LMER9Ie<>M?}%Ros{>8=FN2>U0df9!ZaX8JU#Nl$-z znn!@~n1|PPSQ|=9fIvj+>MICnC{58~*89iI#tJfnXGXw|v^7YmM;2SdCe(LsUlabS z+D{i5`Ah02-L%BCR$n>XB64|s-EFc{0==>h8);Z2TPmNmKY4ZsQ#2kTe2oSW#%p+e zHIwGDs91Hs-^tf0UBZk_FP-H`UuzjeyYO8-lq#b|&?J@wiWeBgzyrG|- z*WK(j4?ACtgCP{df!FX~iI=wPn$^mh=vniNaI@V~Taw&bw{$sW%Gv}3erUed%}jBb zYY?bNMLuM?U*>UlN=htDO+CCjpJa^|V@uyGqvhd2U&p3DnNbv~Yi>?0>=z^}O~k9_ zD!E-okO?}^j?Op`l^oUs^IBK9SZ zok9GMt=PBWdkHwJHiy-vr0ZGhDKRZw$f&N*kqNj3}Sf~9}sEt zJQKvwtJi;4)VVM+k3HfV+NZ+li?(c1>dQL>_rx6cp^Tv8+#5hrAqpumZQncu7x<*j^&{@%QvqDO*v!37{$Nczb?*=`^@875QcO>Xqifp2NRa#hL|Nl5p z>G?XwyDS{SkjGS{p!l|&YMow$e-t3hapc{zO|RolB{L+B(h+oK20kU}bR{4DR2obQ z1BvH!r?;fWboC~|y|@+-3RPk}bnbgXndxKcTf*I5b)D?Jsomc$`pOa9KUk2kUs#lD zu(~`RboRsjJCOLf0Nt$)hV4}g8UleAH#dGd=64w5y+x(L{wn+k0JCii449jdu$lXA zR0qJ`G#Lwm=;!8G-8A&%Dq(8x%7<8P>il}-uYtWj;+hU4ZaqjLl@j3zn z+0;rJsJgdD_D(knRnpR#sfSrexRdV&c5$r$S?p>FZW+x}4D7Y%iH4*@`r_N(cf`%* zJ6QwIcxm}aj9)V)|KP3uVzz0i+!P?00A%=Va=!jj7pDiBFG~esn&X-&O939Mz=2^Ul@2YHqzK2l8B>kPx^3)3|t)KDk=G$ z+c?#Mk>=j#MbTQ@T@fh^mlpT-*QbJdrH25%ylcqmmbCjxWm;&#FI~6@0c1@MM}Q;+ z%TU_P-+c$X){g*Jhi;6}*{*ORTroxc{yI$JH&tHwkKPMHzIhYID`gisV0!6m_YyeY z=3hap)!*IbExkRA*!eJrMsK-W5$e%eCa1GEUMCuI)tfN)wv+R3Z0V;FDvZbt3SC{h zlRq1=kGzT;MLwyo){Nbc0p3bRwb#?& zdu1}3)&WZWj4)*j?G^^-wh|?8Jy~Dc&FL*SOZAn%@(D>#uu&9yPDzP1rPPe8QP&c2N>M9DRHX4xqnWC(Ri=HS#}wVs&Y@p+0To`d9S8GvQ)vHIzPWNwgcO4Ad#AU(|GPgo@A$o0AsBMsCFrbeTn1wNUhaa#yDDJtlR=nbin?TeT-74J6sXF7PvcfH6tTwL+*RJ6lK&qA+G)_u zcgxq_u?Pf0!bvdGLBI$9h&OCP{?qxdm(}(=`tRqhiI)1-*F40da;Gab0djDRcZ~R6 zICNHJ0-`2;vG1Cg^u;*VV(@lDw`p0n7P~}m{2%V#`=9Fg4IeLiWn^b$&yJn!>`nGK zRz`F*Nk&Mv>|M%sju{z;lvP3q)lp`W9T^#=2%r1a`~Cjq^Y}czf57+G9^o~fujli= zuKT*Ky9&S1FFS&NoTX3wG}Z14rZh)rBj0VQ;fqLFuCJlmv&D2HiRGjf@~UkZBsviL z%@kr5|8$#kZjFCGanwP!+T$KP@V%x*;`C?FbEmxA@B1`y3<9J6NHu6SPmj~5%e3Y8 z8?J!)??HQsk+B!_Bi={xiqh^VeZ5CafX(5tOQ%j-x>?qc+EUWaNn{`d0j3EmmU94& zA7r}PSjyx+dclij6K$%rj9tDFw(l?j^D?R?s>?acAV=uDV(P$O*f`P0fxNDkGCCU7 zbNHe3=4N?OO#eI7BljSsAOj4=xXo<QKwsp zxs{ieE%?AurtRm5Lu8|{|AUXJix1sLu%~|tpk`Bdfu;XTlunO19e6+Mr&#d%b1$Wp z@)F;N;jCX^1IpMvc<{CFaRBJ)y-se!Y&N0TmfJRqxwnQ?Xn%)7ynv$fqnYH)pZKx* zVVk_x=sgeCBK~9rzKlfVKx9lAQe)+Y$p(K8_cyl3z&yQx@1zp{ zcW?@Kq{vTP9)HX(NPn4>Bm$4`Jagc3TG2okVC~Vh6^Oz6J_GOlhweS-)nRqYWG2ylc7>D0Mg&EB=(i{Pv}5f|9#N7?xz}9M zxuG6>WY-tq&ix1m!VA@s;z@dWy^))KI~Mf^f*Tw}g>j*!o=9W`Ch~+l+YU2%%B#Qx zR8y~mXEFq(=IB#c);bJ=fi?eW<0nsZy(0XW?=UAQ&Vrt!$ZwC2Ozf5`tvm;6UluVp z`%HK~zD973<;vcCa1&iQ_Cv%%e>L6xYF=o~1*f#^VN+$)H8?^r1);y#{U(|eGs_J{ zeG2pHhGgEJQT(e}kRP;|llbS-1E*|+Ks!IvL{3&iyO{)z@KwKrn4!cgHx81hTaMIef4)!+IWT zJAELdx=9embo%I;ild|o7paVnyHy*!^`E@<;DnlP!|P}AQ+~rwgrqE#_gdb|_Q=k5 z1`1bG3%hCCiuE?U6}kIAEdWK16Cd`+S%(XidJo4bg>zGX!5kwE>27RrjB-hyYw(cb zl1Fqg1zkf%LWitb8kwuPiaT`PJog}1_Lg0)l#uQQObN~T&f4LK$@NcV(6n9&67MIW?L9%(AH3ka8^`$9^wM|my`CO;36B*#bi<$(_Nd01<3Z$Er4c}cf$ zaw-FMQC{W-BJ3;d7;IYlnsO4WK^=ASAtzWc*n|7uD9j~h^cB}ic?=g}_Uy{dGanAA zNp`+ot+cGXGj?b>)tjQmpGzyL%ah;>o1#Dzo9kA`CQpgVV-O*S(Z0IJxA z#V)4`)U4+iP1%^{81uPDF9^uceVy@k=~ z;nT$XBqXTwy{<9bVo55RM{?_I{8&*TPSl{>!q{1p7aJ6X-ul$c_ZX^Edn*_cZ&7tY zysv^?qZQR37JUtd?e7tWVP$wJIR@fr>An^h=NlM)eR_jKNDdhYJA{3s-h8Os^D>pI zcxNI6gw(W_9YW`Iniu2x^?TU{i=;?D$?MzkqNTlJ(Orho#}g7MA}i(chggbO(>K^3 zD>1F4s`1NMF}b?w1hVm;4!@Ym%4=>F&TQ)_og~vQVqbU9CCHRoh9@K?0xR{4fvKP9 zC&hjEZYnKX8$(V~^>|lRXW##NcYp1H^cmAG|K?NCJw}ZU?>;#_$?)YY&Gqd!MvHJP zlCVTi%%h_i$uyVnv3Q;s;errfo8hQ1UM&h&MN^z2O8;r|)-1`D{u3wTTgOQC+u~BR z(T0hCg}xK7PdvP{QjsC07W=B=oFUJ94hj;?@(HVwA%6{?%xwRhKH8qm$&E1VW9|_C zsokA@Opj=f>9DcPokxM6(}u@NQc`uD5G~ze}L1JPDud8 zL|Pepv#yxpgjTPJOzSVJ<2s4Ho58qEs}{EC2fS3hB(K1fCK$@GdND}_}w6fBh&;}iBoph%kVn`M6??6U25Dr_K)U`TD6 zrhDq}Xm%ce;wL_{D+G%P3DS$3-K_5_^()BRcQ*VzMWIUDEe#~+-S4DvEXb(@@CQ{i-y zqifITHrMg6Ua4-hd4MIQJb9>nR?2hXB{AK=Jo$*#6GN;{Ad{e8??bLOrhcmENKJu1 z9S!dm^89qrQEv9PdXJwqEy9kG4mvIuPcgp3c5dFO-E{wQG-pM2w#vi!-r(BYhOYmvnw44ikB) z^vWM7*q^%y2?@&&|vFgc*7wJvAs zak!5!*K28auL1J5K&x8Bu2!d2X`ge*DUIbekA~)`2>NDi@WZqBZkj!azj^MU=$@IW z!0=;Pk1{4<-s?9-e9;#@4$HlK(N9RV^@oz*_ZVVHUGcP0Sl(F8<#O5d?dos@aU(mN zkz7fQzZTT*ErXX0m#a4Jn(pTTpW4f^jRU^C=7b)bRwX&nlpxCK=Q14igSvHHzQJR% z+U&_$hhH*&NQKt&vn_O*+Gmn-2Pul^6syd!`Q%)Tp!8i&z+R_{IM|6+`Quy{JO<%A zsV9QJ1UcVz4vM*fQFthC6!sK$CVx81^Q3xX*-kB2ODed?p8ushz_pqsM)^{{li`kf zO-9sB>*CL-r8eKgbCzb`!aY|eeBKPpw!%a;%HwmmaYn^BE_3P=+aD>-i}a+*ouYZ6 z&TEP&e~ec9K*DX!Pa0Ae`SH~}C}01Nl&oTunvrZ-b5`xa4{s{;rzbI`>USkiSmf_p za&rrX^*B-pat3_%X&^-M=unb)CjlLhjZRTqp(cU%cs1xV7al!7@jns=MVS2NDT{nR zgm2O^TWQp~cQZ${3$tS{H3<=Y`0lS)IBt+IXrnaI)Hbyw*fYvWansp8?0~FT!hC`Z zYS(MBStmI3Q?vKfJNkqk&#T-AM(Li^8~vUeZ9!KSxydn@#qs;?XHUU@P09~<_CBv~ zBzb%?wsI{IuQ1%{-{NaAf8t|BK1};reZWvTbYa3j2Tl`l2A+S zU_S9dhx4iSL;Xn17oD@KE+Zx#t$y~~{({FQI~$bQey$n|=afhaGX#o@+;8q%?Rw?y=NX~%WaM|aCLJaT3Yiw(b%S9&Srhnp#3*eU->lrrf9C;#!!y+Dp+k%1%Q+7z#1$9MRhCb07KkP_6l4JI45G+01b(w$EgJv;EP1*|{MuYi%eo;#{^;;<*{$B30z|cYVU#JB=2ju#{_VVn25>2*pRHaDN`usB`c&+FRF4 z36HT08(~Mmd%GP+d32Hz`Y^=&Z@Q%z2oWm&K0`>L>iT{$#nY`2Hpz8A_1zv+euDGF z(xUxv;61$ld?8y7Lbv9V*qs5l`n^7J4hyDirDyg`x4{OT|EGlyYYK$Iql|1oF8n9X zel$CgH*!9W<;;~%N?~IoiRT_#$}CCbM4?>aFtSrN6l8Ijs_G_h3MK&eM8R^Wkhj2w zT(G6dS!?;1;>#$_^HsEezi8RK zAL#<1VFSQtE_;wC*1*T3^y)0dJ^dn5R>zyQi&a2l(yYOIy%toG+c<(2XQc58Ggk@m z2bi~1z(BFm3zELalM?aodbopE<)8yv3bl|-2L1D|lh>X(-GPf82EVZ^8|DMc0{L-! z3@(cRY1ogEGu|<8{!6?QLbs=A>0`>ssTebB7r@k zymkQyq;O_m*J5{}An{JP$H}@?A6(DS5)XUJT8Qqoe@nzKTHS>QmAK~=Fm;xr(JSw^ z4QH-9Rrz}TMOX$O5apDeR;1hB*p6vYeG188QMjzt#$k{b2 zfe3B<+pw3)V$Lm3zI7zgvYOt0IjC!Iz%|1sAF z#ysDbQhK!XCw^5*i7r5tU+<_HS}Y5QupPzOm+y5Sv27rQdVAt=Q!eu(AZ2n++&W@g z>7^t_YZT5`X2!(wqE|7aoWSTQ#%dR|y`?5-E~rzC0Kx$-iY3_g zv-&~D_Mjt{ClOc>#Z2SVX_A%XpUCrTA`6}u4e)@p1L<&Q$W1Q@=!gx_HIh(vQeGXv z@pwZNfO}7uL}xF1^eVjM!Ty1dpkvrieE+*$b6JBTng-c1axV7oFB`BY;(=~r$O+9! zgldN8eIQAG;Ozas@8@SK0)W`R(N)rhY~bH1@M0Lzyk|9?uT!(ZyRVW#AJdRa-yz;v z6goW}6=Y7zHo-?%E=_X)gWr@gIK?y?aaBKRPsoq)a7^$e#qXlr4`AfykgK)+2Y_L@ z_hZ!(mDii?4GNR3_)ral@(wn<^v7LYdPEM2c~DloVkSWh60yBLXp6Hu$0^0)e^GbN z-|#;b3IbEID%~S`)iAx2W4pakd>f=`;ccJU`i}G;_%7ynEh<7^cJG3{c~tlFcAmJs zh}IDBz%Rqv8K62vz?n6Qc&O?9DmSL6-k_4*e%f+Lia_L8ca2ne<@zO`P-I_b35SUt zBEd$1RVz-wCva?DmW0N}o)Un7!xTKM))Q~IZgiyLL`xs?F_L*4FG~AdLvhwk?t)C8 z0P}+jwpdd04>hS$J&h4v6dIP#h>IA6sa|W*sb-$5N_XdTtUifJyTxzODbd;+?nob1 z#Dmi8h%%>~6pO!0(V$5~FZ<{8R^Y0s&3t*U^z)UXu!lfI*O;*q%T?DAUo8?D-o>ZR z7H*k~diQo;hcMH9xbsUv-$?aCa?`&9U0<;v(zX1D_h{8laIwoNg*PuvAG-%`rSsF~ zWuZk->BH>bTYsf*M_-_P;O1wk#gut%DnXTICLhE_iqS}pib1vh=v2H=D$>(8 zCaKv4@+MaA_>j|4$6Ooa*WsLa@|B)*)j}S)=|%7Pr@hM>@d6$EXRlIHZpS4{Q;ce& z=b6|a*Q#L2>E8Pb5+XbllaJs3a9S+UKdsr`GeOn_@2>=RSDZ6)g3G3Q1O7hK*-P+1$#3o|`*7nd-*z zrgcx&7IxfO`qX1fGq(TNwnI)JeB!j>;O@D&^#0Q4$!m$>13elxA}78iQ7|n@6u+8L z!?wiUm)A6zN1{1E9dT@AeAP*ihMsJ?7|yS8AhP$x*^Bo(1^xtvzpXf{j( ztxzhs$j{vUM`GoyGt~tKKF<)%5qj28DK!V-TfVG+#N~zPv&_Bsc|$T!@w)ZiKjaCa zNPf}7?v<;;QWT&$M=$K27NE%+ar|*+KWyyZN`9yu9Ku&ClM|t8Z7e}gTVyhW*|Pok z6WEfaL6%h1jO(h?ZNtAC*V&CRJ`JhW#UELZOUJTZsUV8TnKaSdV(v4Y%`mtNETqii z#wpHjnIyvz+1R^CtBd$q67 zr>YAN;lJRXrm^_?*B!pC%a;3gY2G>hB$Ok-FY~@49=lHC0HTtZG3gXz)gx>K+IIauXlt2GX1Ceb$*7g|C$veGv;tBmZG zN>FE495`LT*d zuwtw4P3*W|?RVmSN}Aw~(QFo*p#_h159N27dQD87-D-I97>|O0a*NfU8n!OOHC{RM zl>~L!jO-e>2WeLb3cl`b>HC6vq9cMi<1-iM{jfQlD0{Pz+I{s9>2Y>*VLeOb&%#if z-L28;JytQ<*p!YRPE>H09+DkWm@DuX=8c~GlKw(O)XeeeT?*ox9nCkMgiU|Ca8RO8 zb>V%}m}4?&^0D2@gQdRTZ_hLsC$s;`Au%+iFg?EO6yV=nvC$tt0uR4%9DzeuWltVp zgn%HB8@`IoJaPKIQ=(v9(#Zz`&f|l}(-<0h$K1Y2CkwdnqMC+EhD17B*$mSw1n%0Q#SU?yo0O08>8+d+WES?IId&(@zi;LCyn|YjgGYj$-85AYmqKHEr(S? zXc|~sHrjyt#D~y3&mlz(Q^88e!}ALyZ1THSjMb-Xby|vZCLY&eD5}*z6rtP&I*ISrfC*l~{$>0;EMl+7DUCtET_dYgZKJ0{UjcD75yZUp}mox1LD{rM&O z@uzZHAGO62Ie9BD)mie9;&SmkLUFMc5QN5D5gN@mPcIoCU(G)ixvtk;da9Sbo*8M? zgRBK!*1sOTiw@iv=@}Q%$*}WAi&fALE z(pfHstenNbdemkkS(*T zm^VCP!l;-oSrk6e)mA_$t6-S#&CA;~+WYa_b_u(-VvVB$H-A=K$Ma(}dg-8~d_px* z=Hwh7HpPq5?4Qr)*-{m4D#RvJ%$%gMF-05p*;EjKz@xa(@U!%$f=)+j6%R@^C-1i@ z&--%-Cva{_Ro96N>9f8Tt)U`06{D`4&Jv&BdeSgKg`vnrlc|E^lNhQ!;dd{uhL}h+ z_htFo^2}jAjI(J{txfLwV{Z|jO34Ta=^MSi zo_AS+{<0!`hxpH#IlvB3{xMb;DG<5O ztRsqiZRp%|h=ya#&7ryPSq$oSxzmeRpPB2j3+fx4$%dVt;WAUuWviA!wbLIukmo{j zhZ@ly^`takZQbnoWA+8ATRC6HJ6FtiUfo%!U4>nuFX#G@o4DYauM{{OokTpF?-ic+ zB3tjv{T$VQQ-M7qCMWq z^Zx`id*4cy0nPU>Spz3osqwOC0BMvzg8uUGKb6DT^(U~l$UZd-(O*7Bl*C7uDl7<)Il zYyyxaX!lrI#AtmY5JMQK1Xnlj*Fbb~An2~26M$|>Lz=+&*?93%IDiBLd>*>S^ik^2 zx=aAjC+PDhWge~XjN!7;VyDyRZY>auBu&EhC#MM%{E4Y*(52QGrR}qO2kpniabh}^ z)PDpHv{-Rkw2A^ZPLB@z{u=ixBW1DULG&&a_`5ApJ9vf6e#fKlE=T= zbT&VDJqPLE^aXnCFE_%Pf3V=>J)kte1VTC z1zNDpZ9@%`@UGsQpe)2&8KK!KC0l=JB0SD;;9SxJwzr8J95-5}tMLRw>k_xo_${@} zyD$~>#?bzGN&I_F>rwkVu7U*LE(Sd;#Lg>DK@0TxG)*Xpu}iYz;zPgRGqGhr*ZG=R zS3RjWyaQdJ;i{+Yk0d(&ZtZ~PzEST$^uR*2qLy?9QO;0KxEyXh;QmzIvDi7p6IXU^ z8T^iY#zH;7<8psmHsXTrgv7JYzRMsYGG%r0Ge=m=jOSa=+R>+UxKDk$?vl5}7VvM) zz_JuiY4=6@W$FwM&5ev0a5kKx_;@P3(%`L?rOBrXv_&Oe>gxsNHT>1F8erCz5pHW5 z*CkaP24vj%B=_c-n77&yVlWnV^UWUtW9|dw$Yy+Wt!Z3{_XN!{d?boDQhot{smxGZyf%Gli2`tJ=c{Gug_`WJU;@$>&(A{F@58$ zOMjA;*B@RWZuI&I5`hfhgzDvH8~!0@9s2yIAvQJKT`Psg%r|EC4`f4!BX z$A@8yHd(AdW4yt{E6I@t9c3H%h?B$@L~|^vK{1egMqK}`S3ziY)|sf|60mw*gyOS&(e&yH6dPiT(Y%z(p_|XA zmp~+CEb&w8NW}6Z54?WEWW{^ZTXC5@n*UsQZ$&(G&JT(cdA3Ojb^M-9@B_m5P_zv2 z#nq;9Py5Xv7`rShy^?@C*Q<3_!Djfn?M(5)+KxP?i2D#siuT>NC2hr^#v9mucDurg z>Pj_PS-zv?m%HY%9hM^BrwZ~DdD|JGWNFkZ{DAF_%Rk!ugWn|&E?c@AC{ZoDsD!CA zXElJIO|C9}-UOQxToDMbGmi#?1TY%!5|z-uU*~*kWSe_{*Pja8(=@Bk^mRI`;4~m@2&x{shDfH-au^d2W zfj=6($4;7aezBs*Bhoz%H?Fj7*rSBqV@dd!aM9_nz8ilCCq7GUAmx&m#`0WQDhy7B zhDt1tccSHXSpkI!167=y#T|Mx*N}z#zX8;^#bEoYG$!`kDq>W2$Rs}DC#{=Byhvx) z?&1hJ`vd_+qXn$mfH`@jjMQXNNRLa2*yBC{P9K)}tRdb#HENAU3Zxoak z9I<`&Ty~N}SN(F`JCUKw?wu*;e6&fhdTo;B$>Gz4|6QI?rlaSKZzLlSwN)!(TvL&~ z={`fXR7k)Crp(lUI(;tsj9zy~vDpo_uFlNXTv2(N?Bd>%AHExxADo$wNPBfm&p2>3 z%K}H5Q+)Hsp(W+~@Hgtt;-TaT_hYv~3!zK7@5Ur8w3Bm(_Xc?dqu3?m#1QbyMN^I! z6D~iF*T6}W<$8^=Xu!oPa2&` zJ0YcOZi_``+79VnD(d`AOEV+UdR<@tEvU>NWJy$}n6t6@Du>Y@D%iLG0;I;nfeSo=z(TpOt=E zhEAPdzc4L|qS&|h%FD`HjPUa@4ouE!+F;iW#}Q59OTN)Hj;nqR60;&~lLX1w9Bh7$ zh^-6K<&$-a?*7?>zORIIe&s3T7%>%taeFqX^9P%jcaBDPhZD}XKRnz%2qO%-Oy|a| zox3`5C8CY6Qeyk1tMW#X+p>#V3?Xs}+0{MO~>EL$)vP6_95icd1bAG1bFH z&%FClMEI>XI~OKERCMu&h)SnEQ-sB;uRmyH|8+V!_|ktQ#Y(>(zVhVcBD;sL0~IcM zcjDcTbdPt8;<-;xVrDLR{-#u%tNx`L^(N#G$H@}zc=8Pe_e9&A*>I0PEsCNmqk1vL z^C8Y|VrkDA>h+vfBrtWJ^frcxK2qp3IfY-JEKUS{J8@O4(cxONh_AZSnNF1{*`{B* zy$tA><}fN5Nw2=P!J7e+cHgZ&%pTT`FpTk8eVQo5@@TDS&}4!cu)N^*i2b%#=7k`~ z5qmwX4i^)B3$xhXlM{voONn=xd7t_Ymn-WicwRN^{+RV+o%tz){IKevFtY3_O)ystfk0#Q>KZD98PG_lLFiYd^e^W5q z9KAD*z{B!b)``|$gCgxdhYtbG+n>FMVr}OJBe0t1mKnyxSJjH*&d)?izF8 z0!E=)Es|^ZXv*b_33YqxMJ2ELTLg;|iBI{FPv*+KbyL+Zx3Vge(hcWa^Kh6o>kRVwy3ca?tk@ZfDm} z5v3`;(9aAGw|6z}C&wo}Xzu|==;>m(Hol$TLB zF*!${k^Wnu*uC!BDUn8_97c)CN^#>)8PYexO}&nKW^Ns2Lv;g1drc?ZaFTUz#EHOH zM*fP?!Ye>FNZI$&*MFWVG$XP^6mNX`^@V~A9y0edvw>KD6)ierxqE00UUGX2u-joByr3k<1 z4lPDGgGD*lJZjZ2u9bpryTyd;AEkDM51!cBrRoW1a!dtF1rMrGLk#?mD~Ui9<`aK` z`7!qA{MQ&gg?DJ|>%KplqWc5SU()xFV>oqBy(*Q(upiOxzI)-D|LMMP{zIS$+R1oWOq%$KhHgzluYMS) zugCAs-MV{9uv7%tDW4H{W6*K{QT?!oP5U2acj9|5hP||qWowGiEa)3;Khudr;c>Tx zznnfg+znCKfl58+>h@_Y?wnaN?ChtIcNcR}*ZMyXQktk*9UT?L1txn86y;Pm+=9R5DPpRBgpn2rIvk$}?gk80R3^~nzC7T@ zW5!Cd2<*xZ@L*+NKv8hXuG?;`AV=)f$;zdwxU`$x*2Yyvv23~p1|*ADFy z-gvoSq4^BJMnv1ui^x|nAMPh!e}**VCc={4qyGIYaEJzPk)jF46U^-ZVv`g)LtidV z1Pv+oQ($W#0GG^+#ntrcxreKtLoWJ6?JVKnb4RlwmOEgc{U_kj6M*WS=oHZ#bzlgG zcIdhPndPduFwengGmJ1Rav&rfWzImX28jG-8LWT6Q^{F80=ztoX!T1Uc~?IANo)tq z;O#pQBt?KrA6vU4`FuVd|B8&m@3-pyqiJY3P1VS@zlXW97|fAkG6TZZ0^4f%R_ZlP z#4`+!+mFIdq$^8e!j#`0y7;lGpA)kiL^|-QP01N;91O$@OjpRZ}go%J| zYZ&w)BGVmH{Y5pqSkRY?b|9zA`T`m;NzmBfKpIwsMWAR#%$=;Tqy1?N$UEMWpSpiL z7-k$2cw;%!!TlGr)5UnfYAWe}5-{ecdT|K#ga;uUuCC`))yka&Y8SZhkekWAz+MY> zoCaY?pVrGF<6kQ9-DJWSEjaR@RUAqj?rDP_(;w>p4Su4@m9P4-r-p!+rSx$nt{;rI zNF~$$T3JT_mcIi+Z>?!#j*twsheW<$xmcvs@{qDj{0(1aUwt~GgGv1> z_dZbPg&-cp?VpFEWr$oPEJe?CCYp7K#y=B?17pl{ptgoVFZd`x?je}j>gyX`5>e0B z*?2!acD@fVsAn;O`qummSFZGx8JtkCmV++BWfyf zJgCsXE%$H8`YS{1iEeyjI#;v(#W>gC!QD{;i)O=zBlww8#34#o$Ai)z1gazr6dzBb z>}tn7frr?E$>BIyt1A}-mRyeZY|;MXm$s+5lI{9xqJ%9h?t~W2j;-FCYx{c(OJa}q z%(-;ZApoR-15H0c!Y_)u_R