Coder Social home page Coder Social logo

lhupfeldt / multiconf Goto Github PK

View Code? Open in Web Editor NEW
5.0 4.0 3.0 1.71 MB

Python module for data holder objects with multiple environment specific values for a single property

License: BSD 3-Clause "New" or "Revised" License

Python 100.00% Makefile 0.01%

multiconf's Introduction

Build Status Coverage Documentation Status PyPi Package

What

Multiconf is a framework for describing a complex configuration for multiple environments using Python.

Why?

It started from a simple need of deployment automation for Java EE projects, Apache and more. Having worked on different projects with nested levels of plain text property files or XML configuration files,I thought something better was needed. With plain text property files, the number of property files increases as environments and technologies are added to a project. It becomes hard to get an overview of properties describing similar configurations. Has a property value been defined for every environment? And it is getting even harder to describe proper settings: what depends on what and what can be used and what can't. With XML on the other hand, you can create a strict validated model, but you keep having to extend the schema and the tools processing it. And maybe you don't like the verbosity. So why use XML or property files when you can have your configuration directly in python? So, out of this Multiconf was born.

What are proper settings?

E.g:

  • All configured ports follow one convention
  • All servers names follow one convention
  • Some configuration objects must have mandatory parameters (for example: Database name or URL required for Datasource object)
  • Some configuration objects must have mandatory children (for example: WebLogic Cluster doesn't make sense w/o Managed Servers)
  • Default settings are propagated through all environments and can be overridden for specific environments
  • No duplicated settings

How

Multiconf provides a set of classes, where attributes may have different values for different environments, while enforcing that a value is defined for all defined environments. Multiconf allows you to implement your own DOM like object model and get early warning that something within your definition is wrong. Other tools use YAML or JSON to define settings of the components, but then you need something to validate those settings. Multiconf is both - definition and validation. Multiconf allows you to define environment groups, so that you can easily create new environments by adding them to a group and only override the values that differ from the group values.

You have to define your configuration data model as classes derived from Multiconf base classes, one of which is ConfigItem.

E.g, in your config data model (your framework) you define:

class Host(ConfigItem):
    def __init__(name=MC_REQUIRED, mem=MC_REQUIRED):
        self.name = name
        self.mem = mem

    @property
    def fqd(self):
        return "{name}.{env}.my.organisation".format(
            self.name, self.env.name)

In you project configuration file you can then declare a configuration object with different attribute values for different environments:

...
with Host("web1") as host:
    host.setattr('mem', dev="1G", tst="2G", preprod="4G", prod="4G")

Above uses the Multiconf setattr method to assign different values to different envs. Note that the envs dev, tst, preprod and prod must have been declared beforehand and Multiconf will ensure that all of them get a value.

After instantiating your config for the prod env you can then access properties on the host object:

cfg.host.name -> web1
cfg.host.mem -> 4G
cfg.host.fqd -> web1.prod.my.organisation

Note that classes derived from the Multiconf classes (e.g: ConfigItem) do not allow on the fly creation of attributes. Configuration items are not meant for general programming, but for strictly validated configurations.

See the documentation and the demo project for details about nested objects, repeatable objects, instantiation, environment definitions, environment groups, default values and other details.

What Multiconf is not

  • Multiconf is not tied to configuration of any particular product or technology.
  • Multiconf doesn't know how to create any of the environment's components, i.e. Multiconf has no 'playbooks' or 'recipes' to execute.

Running the demo:

Execute ./demo/demo.py --env (or 'python demo/demo.py ...'), e.g:

./demo/demo.py --env prod

If run without any arguments it will print a usage message The valid environments are those specified at the top of demo/config.py

Running the test suite:

Execute: make, py.test or tox Running 'make' will execute the test suite, the demo and build the documentation.

Requirements

Multiconf: Python 3.6.1+ Test Suite: pytest, pytest-cov (for older Python versions use multiconf 8.x) demjson (optional) - pip install -U pytest pytest-cov demjson

multiconf's People

Contributors

henriklynggaard avatar lechat avatar lhupfeldt avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

multiconf's Issues

Improve and publish slides from DemoCamp

Please provide the slides from DemoCamp CPH either here or in another appropriate place (linking from this Wiki) ideally by Dec 27, when Vienna Code Kitchen with PyUGAT participation hopes to have a look at this project and Kokki, maybe do some "cooking";-)

Decorators should be inherited when using subclasses

Assume the following classes

Domain(ConfigItem)
WeblogicDomain(Domain)
JbossDomain(Domain)
ObpmDomain(Domain)

If I set a "nested_repeatable" on the Domain class e.g. "serves, datasources" I currently need to repeat that decorator on all subclasses.

I suggest that such decorators are inherited, and if the decorator is on the subclass the values are merged not overwritten. in the case of nested_repeatable Domain could have "servers, datasources" and JbossDomain could have "directories" resulting in a effective nested_repeatable of "serves, datasources, directories"

Typos in Readme

The readme text contains a few typos, e.g. "Multionf" in one sentence. Beside that, the term J2EE is quite old-fashioned and should ideally be changed to Java EE some time;-)

Repeatable elements should be always be collections

If a child configItem is repeatable, the parent should always return a collection even if only one child object is defined.

With only one logging appender defined I get the following exception when doing this in a template

File "/home/henrik/Temp/adlt/deployment2/cookbooks/jboss/templates/jboss-eap-5.1.2/server/default/conf/jboss-log4j.xml.template", line 8, in

TypeError: 'FileAppender' object is not iterable

multiconfig navigation

Issue with parent:

  • If we have Domain->Server then self.contained_in resolves to domain.
  • if we have Domain->Cluster->Server->then self.contained_in does not resolve to domain.

We need set of navigation methods that provide specific str values of the parent at one or more levels above the current node,

e.g.

iDomainXYZ->Cluster123->Server1

contained_in("Domain") returns "DomainXYZ"

contained_in("Cluster") returns "Cluster123"

contained_in("Server") returns "Server1"

Options to dumping of configuration

When working with large configurations it is sometimes neceseary to search for a value, and the finding the corresponding places in the model where it is created.

To fascilitate simple grep'ing, it would be great if dump object had an option to print fully qualified keys.

E.g. conceptually:

'project.name': 'foo',
'project.server.name': 'bar-server'
'project.server.port': '8888'
``

ConfigBuilder cannot access other parts of configuration

In a ConfigBuilder I want to access a proeprty of a parent object, but it fails and only returns me a unfrozen AttributeCollector

The usecase is a serverBuilder where the hostname_patterns is set to "%(domain).%(env).%(project).example.net" and I want to so the expansion when building the Server object, however I cannot lookup the domain name defined in parent object

I could do the conversion lazily in the server ConfigItem but that would mean lazily validating the generated name against know hosts.

Fire and forget

Hi,

I need to create a pipeline, where some jobs within parallel execution do not need to be checked if they are successful or not. I can't seem to find a way to put that into a flow.

Please help!

Aleksey

Provide easy way to handle empty/not defined collections

The use case of "I need to do X if there are some of Y defined" is not cleanly handled, as empty collections are treated as errors (missing property).

Example:
I have a template that needs to write a xml fragment per data source if there are datasources. The current template resembles

#{datasource.jndi} ....

Above code raises a exception when no datasources are defined for a domain (domain has no property 'datasources')
I need to wrap the above in a block testing for "hasattr(domain, 'datasources') in order to get the code to work.

I don't think that is very clean, as it adds alot of boiler plate code. It would be better if the "domain" config item, could let multiconf know that datasources is a valid property and should return a empty collection unless otherwise defined but I cannot find that functionality

Type change protection breaks use of "None"

In a common pattern we use

class Domain(ConfigItem):
    def __init__(self, name, base_port, java_home, domain_user_override=None, **kwargs):
        super(Domain, self).__init__(name=name, base_port=base_port, java_home=java_home, domain_user_override=domain_user_override, **kwargs)


@property 
def user(self):
  if self.domain_user_override
    return self.domain_user_override
  return calculated_user

However when I attempt to use the override as such

with Domain(name='eui', base_port=9000, java_home='/opt/java/jdk1.6.0_17',file_encoding="UTF-8") as eui_domain:
            eui_domain.domain_user_override(devLocal="myname") 

I get the following error:

ConfigError: Found different types of property 'domain_user_override' for different envs: <type 'str'> previously found types: [<type 'NoneType'>]

pip install multiconf not working

Downloading/unpacking multiconf

Getting page https://pypi.python.org/simple/multiconf/
Could not fetch URL https://pypi.python.org/simple/multiconf/: HTTP Error 404: Not Found
Will skip URL https://pypi.python.org/simple/multiconf/ when looking for download links for multiconf
Getting page https://pypi.python.org/simple/
URLs to search for versions for multiconf:

Provide support for post finalization validation

Since some properties depend on their parent objects in order to calculate their final value, they cannot be fully validated before finalization since the parent values are not available before then. This is also described in #7

ConfigItems should support a method for validation after finalization, so that waiting for property access to perform the validation lazily is avoided.

Support of overlapping groups

It should be possible to define groups that overlap e.g. I can have
dev_group for all that it connected to dev env (dev, dev_local)
single_vm_group for all envs which on has a single vm (dev,dev_local,test,edu)

Cannot override ConfigBuilder in severeal statements

Assume the following setup

envs = dev_local dev, test,pp,prod

and the following code:

With MyConfig(url='http://www.example.com/live') as server:
server.url (dev="http://www.example.com/test",
server.url.(dev_local="http://www.example.com/local'")

I get an error: "ConfigError: Redefined attribute", but the program continues.

however when I in the build() method tries to access a property (not the same as above) I do not get the value but instead
AttributeCollector: 'num_servers':frozen, values: {Env('devLocal'): 1, Env('prod'): 4, Env('tst'): 1, Env('dev'): 1, Env('pp'): 1}

Allow @required decorator to take a list

As a programmer using multiconfi, I would like to supply the parameters to the @required decorator as a list, not as a string with commas in.
This would be help readability when there are many @required parameters. It would also be nice to have it on other decorators, e.g. @nested_repeatables.

Thanks
Andy Watkins

On missing key error, do not dump child objects

When working with large configurations, the error dump is so long that it makes it hard to find the actual problem.

I think it would be sufficient if the error dump only displayed the object attributes at the level the error occurred (i.e. did not dump child objects).

Add multiconf attirbutes to __dir__()

When working with large configurations, it would be helpfull to be able to explore the loaded config via tools like ipython. The ipython shell does tab completion of attributes and object methods, based on what is returned by dir(). By adding multiconf attributes and property methods to output of dir() it would greatly help when using such tools.

Remove circle.yml?

Hi,
It seems the circle.yml configuration was not used for some time. CircleCI will switch off version 1, so the file is going to be completely useless in a few months.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.