Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mtf config file #218

Merged
merged 2 commits into from
Mar 9, 2018
Merged

Mtf config file #218

merged 2 commits into from
Mar 9, 2018

Conversation

jscotka
Copy link
Collaborator

@jscotka jscotka commented Mar 2, 2018

This tries to remove hardcoded variables and move them to config file(s)

@jscotka jscotka force-pushed the mtf_config branch 4 times, most recently from 52284c9 to 3863727 Compare March 5, 2018 11:49
Copy link
Member

@TomasTomecek TomasTomecek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What is the expected workflow? Will the mtf.yaml config be supplied with the package and users will override it?

@@ -0,0 +1,61 @@
default_module: docker
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this file will require a lot of documentation so users would understand what each key means

Copy link
Collaborator Author

@jscotka jscotka Mar 5, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for these comments.
Yep, I expect that package will provide some default configuration (for testing upstream/fedora)
and some users who understand that, is able to reconfigure it to another value.
from that PoV it is not expected that "normal" user should understand that.

Yep, would be nice to add there documentation. for now probably it is better without documentation, than have these values hardcoded inside python code.

logic of loading files is on lines:
https://github.com/fedora-modularity/meta-test-family/pull/218/files#diff-d49eca679ceb3a9c6a60a7a4afec5f21R89

it will use these files and configuration is updated with each existing file, meand that it loads 1. and in case 3. exist, config is updated by these values

  1. /usr/lib/python2.7/site-packages/moduleframework/mtf.yaml
  2. /etc/mtf.yaml
  3. ~/.mtf.yaml

@jscotka jscotka changed the title WIP: Mtf config Mtf config file Mar 5, 2018
@jscotka jscotka requested a review from phracek March 5, 2018 13:20
@jscotka jscotka force-pushed the mtf_config branch 2 times, most recently from c1d28ce to 24c1c38 Compare March 6, 2018 14:04
Copy link
Member

@phracek phracek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sometimes you use common.fce and sometimes only fce. Like print_info.
Also improve ConfigMTF class so that it is able to use getattr method like https://docs.python.org/2/library/functions.html#getattr

@@ -1,4 +1,4 @@
#
# -*- coding: utf-8 -*-
# Meta test family (MTF) is a tool to test components of a modular Fedora:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer to remove it. It tests also containers. Not or modular Fedora. The line below too.


class MTFConfParser(object):
configname = "mtf.yaml"
source_cfg_file = os.path.join(os.path.dirname(__file__), configname)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would move it to /usr/share/modularityframework/. /usr/lib/python2.7/... is for python packages.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought about that too and in init version I had it there. I'll move it there

class MTFConfParser(object):
configname = "mtf.yaml"
source_cfg_file = os.path.join(os.path.dirname(__file__), configname)
default_cfg_file = os.path.join("/etc", configname)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add /etc at the beginning of the file common.py. There is already set of constants.

self.options = config


def get(self, section=None, key=None):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What about to use function getattr like https://docs.python.org/2/library/functions.html#getattr

Copy link
Collaborator Author

@jscotka jscotka Mar 6, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll implement that. sounds well

@@ -868,9 +858,10 @@ def get_module_type():
"""
amodule = os.environ.get('MODULE')
readconfig = get_config(fail_without_url=False)
if "default_module" in readconfig and readconfig[
"default_module"] is not None and amodule is None:
if amodule is None and readconfig.get("default_module"):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about something like:

amodule = getattr(conf[options], "default_module", None)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed by elegant way: config parser has dict as parent class, so all dict methods available there.

@@ -104,14 +107,16 @@ def setRepositoriesAndWhatToInstall(self, repos=[], whattooinstall=None):
if repos:
self.repos = repos
else:
self.repos += get_compose_url() or self.get_url()
self.repos += common.get_compose_url() or self.get_url()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you use common., but above only print_info. Any reason?
Keep the python style.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll fix it. would be nice also to fix all these issues in next PR, we can do issue for this cleanup


# openshift specific section
openshift:
init_wait: 50
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add more documentation

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not able to add there documenttation, because you wrote this part and I've just moved these constants out of code to this file without knowledge what this does mean

( test -e /usr/bin/yum && echo 'yum -y' ||
echo 'apt-get -y' ) )"
# which values are considered as true
true_values: ['yes', 'YES', 'yes', 'True', 'true', 'ok', 'OK']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be one general function. I don't see any reason, why to have it here, in config file.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

make sense

@@ -205,10 +202,10 @@ def __init__(self, args, unknown):
if args.linter:
self.tests += glob.glob("{MTF_TOOLS}/{GENERIC_TEST}/*.py".format(
MTF_TOOLS=metadata_common.MetadataLoaderMTF.MTF_LINTER_PATH,
GENERIC_TEST=common.GENERIC_TEST))
GENERIC_TEST=conf.get("generic", "generic_tests")))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Again, either double get or even better getattr.


# openshift specific section
openshift:
init_wait: 50
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Configuration file is a bit long. What about to create a directory /etc/mtf/ and have there several configuration files. One for each type. Ease for modification.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is good idea, but I'm not sure if anybody than me will modify it :-)
We can discuss it. I like this idea

# timeout in secs, how long wait for compose (composes are cached, but first round can take long time (createrepo of packages))
timeout: 1200
new_compose_dict: { sigkeys: [''] }
url: "https://odcs.fedoraproject.org"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I expect that internally we'll have a different config.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it is also mentioned few lines under (location of internal odcs server)
Probably we will ship, or somewhere stored config file for downstream testing

jscotka added a commit to jscotka/meta-test-family that referenced this pull request Mar 7, 2018
prepare for using private neworks inside nspawn

prepare for using private neworks inside nspawn
from avocado.utils import process
from moduleframework.mtfexceptions import ModuleFrameworkException, ConfigExc, CmdExc, DefaultConfigExc
from mtfexceptions import ModuleFrameworkException, ConfigExc, CmdExc, DefaultConfigExc
from core import DATADIR, is_debug, is_not_silent, print_info, print_debug
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not only import core. print_info is so general and we don't know from which module comes from.


class MTFConfParser(dict):
configdir = "mtf.conf.d"
source_cfg = os.path.join(*(["/"] + DATADIR + [configdir]))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add / to DATADIR and remove ["/"].
I would write
os.path.join(*(DATADIR, [configdir]))

What do you want to do with this code? All directories under DATADIR?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phracek this is not possible, it is connected with using this in setup.py (there is just relative path, so I cannot add this to this DATADIR list)


def __init__(self):
config = {}
for cfgdir in [self.source_cfg, self.default_cfg, self.user_cfg]:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this work with several self.source_cfg directories?

if is_true(odcstoken):
if conf.get("openidc").get("token"):
# use value defined in config file if defined
return conf["openidc"]["token"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get and get are missing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phracek it is dict, so it is not important to use get, because it is already checked that is defined in if

'https://pagure.io/odcs/renew-compose',
'https://pagure.io/odcs/delete-compose',
]
oidc = openidc_client.OpenIDCClient(*conf["openidc"]["auth"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same as above.

'https://pagure.io/odcs/delete-compose',
]
oidc = openidc_client.OpenIDCClient(*conf["openidc"]["auth"])
scopes = conf["openidc"]["scopes"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jscotka You did not catch traceback. Is it enough exception for request.exception.HTTPError?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phracek I think that this is enough. Not important to catch it and transform to another exception. And I've not changed this behaviour anyhow

@@ -348,7 +288,7 @@ def get_profile():
:return: str
"""

return os.environ.get('PROFILE') or MODULE_DEFAULT_PROFILE
return os.environ.get('PROFILE') or conf["modularity"]["default_profile"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jscotka This returns, either environment variable or value from conf or None. Is it requested?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes this is expected. or this also can cause traceback in case some user break this value from config. It is expected

@@ -469,7 +409,7 @@ def get_template(self):
get location of template from config.yaml file
:return: str
"""
return self.info.get(TEMPLATE)
return self.info.get(conf["openshift"]["template"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Default value is missing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jscotka Do you count with None if template is not specified?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It has to be specified in this config. There is stored default value and in case user remove this item from config, it causes traceback, it is expected.

@@ -26,7 +26,8 @@
import random
import string
from avocado.utils.process import CmdError
from moduleframework import common
from moduleframework.common import conf, is_debug, print_debug, print_info, trans_dict, sanitize_cmd, \
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some parts are part of module core instead of common.

@jscotka jscotka force-pushed the mtf_config branch 2 times, most recently from 62c2004 to e2abdb4 Compare March 8, 2018 10:29

class MTFConfParser(dict):
configdir = "mtf.conf.d"
source_cfg = os.path.join(*(["/"] + core.DATADIR + [configdir]))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jscotka What do you want to do with this command?

source_cfg = os.path.join(*(["/"] + ['etc']  + ["yum"]))
print source_cfg

prints /etc/yum

Why not only os.path.join(core.DATADIR, configdir)?
core.DATADIR could be

core.DATADIR = "/usr/share/moduleframework"

Copy link
Collaborator Author

@jscotka jscotka Mar 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because threre is by intention missing leading / so that it created relative path, instead of /usr/share/moduleframework, and also it is caused by that this syntax was used in setup.py for this directory. So I did not want to change it in setup.py, just put it out of hardcoded value in setup.py
see: https://github.com/fedora-modularity/meta-test-family/pull/218/files#diff-2eeaed663bd0d25b7e608891384b7298L59

'https://pagure.io/odcs/renew-compose',
'https://pagure.io/odcs/delete-compose',
]
oidc = openidc_client.OpenIDCClient(*conf["openidc"]["auth"])
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jscotka Check if ["openidc"]["auth"] exists.
what about if oidc is None. Where do you catch traceback?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't want to catch traceback here in case user break config. This behaviour is same for various service, like apache server, in case user write bad config, or break default apache config file, it did not start and probably just lead to some strange error.

@@ -674,7 +612,7 @@ def run(self, command, **kwargs):

def get_packager(self):
if not self.packager:
self.packager = self.run(PACKAGER_COMMAND, verbose=False).stdout.strip()
self.packager = self.run(conf["generic"]["packager_cmd"], verbose=False).stdout.strip()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be specified always, right? What if packager_cmd is missing?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it causes traceback. by default it is defined in shipped mtf config. if user remove this. then it will lead to expected traceback.

cfgfile = "/usr/share/moduleframework/docs/example-config-minimal.yaml"
print_debug("Using default minimal config: %s" % cfgfile)
core.print_debug("Using default minimal config: %s" % cfgfile)


try:
with open(cfgfile, 'r') as ymlfile:
xcfg = yaml.load(ymlfile.read())
doc_name = ['modularity-testing', 'meta-test-family', 'meta-test']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why meta-test?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know. I've defided it looong time ago, as shorter name in config files, it is closed to modularity-testing, it also miss word framework

return parent


def get_docker_file(dir_name=DEFAULT_DIR_OF_DOCKER_RELATED_STUFF):
def get_docker_file(dir_name=conf["docker"]["dockerfiledefaultlocation"]):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can be None if dockerfiledefaultlocation is empty. Do you count with it?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it will lead to traceback, it is expected

@@ -40,7 +44,7 @@ class ComposeParser(object):

def __init__(self, compose):
self.compose = compose
xmlrepomd = compose + "/" + REPOMD
xmlrepomd = compose + "/" + common.conf["compose"]["repomd"]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not os.path.join?

Copy link
Collaborator Author

@jscotka jscotka Mar 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I Know why, it is URL, not directory. It is possible to use os.path.join now, it is equivalent, but in some case os.path.join can lead to another separator like \ at windows, and it causes bad URL

import sys
import os

DATADIR = ['usr', 'share', 'moduleframework']
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jscotka Why not /usr/share/moduleframework?

Copy link
Collaborator Author

@jscotka jscotka Mar 8, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because original usage of this list is in setup.py in this format, copyied from other upstream projects, and I did't want to change this behaviour, just need to have this location in better place that in setup.py.
see https://github.com/fedora-modularity/meta-test-family/pull/218/files#diff-2eeaed663bd0d25b7e608891384b7298L59

import core


class MTFConfParser(dict):
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jscotka What about something like this:

class Config(dict):
     def __getattr__(self, key):
         try:
             return self[key]
         except KeyError:
             raise AttributeError
     def __setattr__(self, key, value):
         self[key] = value
     def __init__(self, yaml_file, release="current"):
         config = yaml.load(yaml_file)
         self["raw"] = config
         pdc = config["pdc"]
....

And you have access to all fields.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phracek does that have some benefits instead of actual implementation to redefine these getters and setters?
I trough to redefine __getattr__ to lead some easier to debug exceptions (like, show path to file where is this found, and show value from default config, what should not be modifed), but it could be further improvement

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah let's leave it for now.

Copy link
Member

@phracek phracek left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM now.

@phracek phracek merged commit 30c34e8 into fedora-modularity:master Mar 9, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants