Skip to content
This repository has been archived by the owner on Feb 2, 2018. It is now read-only.

Commit

Permalink
Merge pull request #28 from ashcrow/config
Browse files Browse the repository at this point in the history
Works as expected
  • Loading branch information
cooktheryan committed Feb 11, 2016
2 parents fa804fa + ea6c05c commit a5c4e02
Show file tree
Hide file tree
Showing 10 changed files with 185 additions and 114 deletions.
7 changes: 7 additions & 0 deletions doc/apidoc/commissaire.config.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
commissaire.config module
=========================

.. automodule:: commissaire.config
:members:
:undoc-members:
:show-inheritance:
72 changes: 72 additions & 0 deletions src/commissaire/config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Copyright (C) 2016 Red Hat, Inc
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Configuration.
"""

import logging

import etcd


class Config(dict):
"""
Configuration container.
"""

def __init__(self, listen={}, etcd={}, kubernetes={}):
"""
Creates an instance of the Config class.
:param listen: Structure containing the server listening data.
:type listen: dict
:param etcd: Structure containing the etcd connection data.
:type etcd: dict
:param kubernetes: Structure containing the kubernetes connection data.
:type kubernets: dict
:returns: commissaire.config.Config
"""
self.listen = listen
self.etcd = etcd
self.kubernetes = kubernetes


def cli_etcd_or_default(name, cli, default, ds):
"""
Returns the value for an option in the following order:
CLI switch, etcd value, default.
:param name: The name of the switch/etcd key.
:type name: str
:param cli: The argparse value.
:type cli: list
:param default: The default value if CLI and etcd have no values.
:param ds: Etcd client
:type ds: etcd.Client
"""
result = None
if cli:
result = cli[0]
logging.info('Using CLI for {0} configuration.'.format(name))
else:
try:
result = ds.get('/commissaire/config/{0}'.format(name)).value
logging.info('Using Etcd for {0} configuration.'.format(name))
except etcd.EtcdKeyNotFound:
logging.info(
'No CLI or etcd defined for {0}.'
' Using default of {1}.'.format(name, default))
result = default
return result
12 changes: 6 additions & 6 deletions src/commissaire/containermgr/kubernetes/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,18 +26,18 @@ class ContainerManager(ContainerManagerBase):
Kubernetes container manager implementation.
"""

def __init__(self, connection_config):
def __init__(self, config):
"""
Creates an instance of the Kubernetes Container Manager.
:param connection_config: External resource connection information.
:type connection_config: dict
:param config: Configuration information.
:type config: commissaire.config.Config
"""
ContainerManagerBase.__init__(self)
self.host = connection_config['kubernetes']['uri'].hostname
self.port = connection_config['kubernetes']['uri'].port
self.host = config.kubernetes['uri'].hostname
self.port = config.kubernetes['uri'].port
self.con = requests.Session()
token = connection_config['kubernetes']['token']
token = config.kubernetes['token']
self.con.headers["Authorization"] = "Bearer {0}".format(token)
# TODO: Verify TLS!!!
self.con.verify = False
Expand Down
10 changes: 5 additions & 5 deletions src/commissaire/jobs/investigator.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ def clean_up_key(key_file):
'{0}. Exception:{1}'.format(key_file, exc_msg))


def investigator(queue, connection_config, store, run_once=False):
def investigator(queue, config, store, run_once=False):
"""
Investigates new hosts to retrieve and store facts.
:param queue: Queue to pull work from.
:type queue: gevent.queue.Queue
:param connection_config: External resource connection information.
:type connection_config: dict
:param config: Configuration information.
:type config: commissaire.config.Config
:param store: Data store to place results.
:type store: etcd.Client
"""
Expand Down Expand Up @@ -114,7 +114,7 @@ def investigator(queue, connection_config, store, run_once=False):
oscmd = get_oscmd(data['os'])()
try:
result, facts = transport.bootstrap(
address, key_file, connection_config, oscmd)
address, key_file, config, oscmd)
data['status'] = 'inactive'
store.set(key, json.dumps(data))
except:
Expand All @@ -130,7 +130,7 @@ def investigator(queue, connection_config, store, run_once=False):

# Verify association with the container manager
try:
container_mgr = KubeContainerManager(connection_config)
container_mgr = KubeContainerManager(config)
# Try 3 times waiting 5 seconds each time before giving up
for cnt in range(0, 3):
if container_mgr.node_registered(address):
Expand Down
58 changes: 14 additions & 44 deletions src/commissaire/script.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

from gevent.pywsgi import WSGIServer

from commissaire.config import Config, cli_etcd_or_default
from commissaire.handlers.clusters import (
ClustersResource, ClusterResource,
ClusterHostsResource, ClusterSingleHostResource,
Expand Down Expand Up @@ -139,35 +140,6 @@ def create_app(store):
return app


def cli_etcd_or_default(name, cli, default, ds):
"""
Returns the value for an option in the following order:
CLI switch, etcd value, default.
:param name: The name of the switch/etcd key.
:type name: str
:param cli: The argparse value.
:type cli: list
:param default: The default value if CLI and etcd have no values.
:param ds: Etcd client
:type ds: etcd.Client
"""
result = None
if cli:
result = cli[0]
logging.info('Using CLI for {0} configuration.'.format(name))
else:
try:
result = ds.get('/commissaire/config/{0}'.format(name)).value
logging.info('Using Etcd for {0} configuration.'.format(name))
except etcd.EtcdKeyNotFound:
logging.info(
'No CLI or etcd defined for {0}.'
' Using default of {1}.'.format(name, default))
result = default
return result


def parse_uri(uri, name):
"""
Parses and returns a parsed URI.
Expand All @@ -194,6 +166,9 @@ def main(): # pragma: no cover
Main script entry point.
"""
import argparse
from commissaire.config import Config

config = Config()

epilog = ('Example: ./commissaire -e http://127.0.0.1:2379'
' -k http://127.0.0.1:8080')
Expand All @@ -212,12 +187,13 @@ def main(): # pragma: no cover
args = parser.parse_args()

try:
etcd_uri = parse_uri(args.etcd_uri, 'etcd')
kube_uri = parse_uri(args.kube_uri, 'kube')
config.etcd['uri'] = parse_uri(args.etcd_uri, 'etcd')
config.kubernetes['uri'] = parse_uri(args.kube_uri, 'kube')
except Exception as ex:
parser.error(ex)

ds = etcd.Client(host=etcd_uri.hostname, port=etcd_uri.port)
ds = etcd.Client(
host=config.etcd['uri'].hostname, port=config.etcd['uri'].port)

try:
logging.config.dictConfig(
Expand All @@ -236,21 +212,15 @@ def main(): # pragma: no cover
interface = cli_etcd_or_default(
'listeninterface', args.listen_interface, '0.0.0.0', ds)
port = cli_etcd_or_default('listenport', args.listen_port, 8000, ds)
config.etcd['listen'] = urlparse.urlparse('http://{0}:{1}'.format(
interface, port))

# TODO: Make this an instance of a configuration class
try:
connection_config = {
'etcd': {
'uri': etcd_uri,
},
'kubernetes': {
'uri': kube_uri,
'token': ds.get('/commissaire/config/kubetoken').value,
}
}
logging.debug('Connection config: {0}'.format(connection_config))
config.kubernetes['token'] = ds.get(
'/commissaire/config/kubetoken').value
logging.debug('Config: {0}'.format(config))
POOLS['investigator'].spawn(
investigator, INVESTIGATE_QUEUE, connection_config, ds)
investigator, INVESTIGATE_QUEUE, config, ds)
except etcd.EtcdKeyNotFound:
parser.error('"/commissaire/config/kubetoken" must be set in etcd!')
# watch_thread = gevent.spawn(host_watcher, ROUTER_QUEUE, ds)
Expand Down
19 changes: 8 additions & 11 deletions src/commissaire/transport/ansibleapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -297,16 +297,16 @@ def get_info(self, ip, key_file):

return (result, facts)

def bootstrap(self, ip, key_file, connection_config, oscmd):
def bootstrap(self, ip, key_file, config, oscmd):
"""
Bootstraps a host via ansible.
:param ip: IP address to reboot.
:type ip: str
:param key_file: Full path the the file holding the private SSH key.
:type key_file: str
:param connection_config: External resource connection information.
:type connection_config: dict
:param config: Configuration information.
:type config: commissaire.config.Config
:param oscmd: OSCmd instance to useS
:type oscmd: commissaire.oscmd.OSCmdBase
:returns: tuple -- (exitcode(int), facts(dict)).
Expand All @@ -322,16 +322,13 @@ def bootstrap(self, ip, key_file, connection_config, oscmd):
resource_filename('commissaire', 'data/templates/'))
tpl_vars = {
'bootstrap_ip': ip,
'kubernetes_api_server_host': connection_config.get(
'kubernetes')['uri'].hostname,
'kubernetes_api_server_port': connection_config.get(
'kubernetes')['uri'].port,
'kubernetes_bearer_token': connection_config.get(
'kubernetes')['token'],
'kubernetes_api_server_host': config.kubernetes['uri'].hostname,
'kubernetes_api_server_port': config.kubernetes['uri'].port,
'kubernetes_bearer_token': config.kubernetes['token'],
'docker_registry_host': '127.0.0.1', # TODO: Where do we get this?
'docker_registry_port': 8080, # TODO: Where do we get this?
'etcd_host': connection_config['etcd']['uri'].hostname,
'etcd_port': connection_config['etcd']['uri'].port,
'etcd_host': config.etcd['uri'].hostname,
'etcd_port': config.etcd['uri'].port,
'flannel_key': '/atomic01/network' # TODO: Where do we get this?
}
tpl_env = jinja2.Environment()
Expand Down
61 changes: 61 additions & 0 deletions test/test_config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
# Copyright (C) 2016 Red Hat, Inc
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Test cases for the commissaire.script module.
"""

import etcd

from . import TestCase
from argparse import Namespace
from mock import MagicMock
from commissaire import config


class Test_CliEtcdOrDefault(TestCase):
"""
Tests for the cli_etcd_or_default function.
"""

def test_cli_etcd_or_default_with_cli_input(self):
"""
Verify cli_etcd_or_default works with cli input.
"""
cli = Namespace(test=['test'])
ds = MagicMock(get=MagicMock(side_effect=etcd.EtcdKeyNotFound))
self.assertEquals(
'test',
config.cli_etcd_or_default('test', cli.test, 'default', ds))

def test_cli_etcd_or_default_with_default_fallback(self):
"""
Verify cli_etcd_or_default falls to default with no other input.
"""
cli = Namespace(test=None)
ds = MagicMock(get=MagicMock(side_effect=etcd.EtcdKeyNotFound))
self.assertEquals(
'default',
config.cli_etcd_or_default('test', cli.test, 'default', ds))

def test_cli_etcd_or_default_with_etcd_result(self):
"""
Verify cli_etcd_or_default uses etcd result when present.
"""
cli = Namespace(test=None)
ds = MagicMock(
get=MagicMock(return_value=MagicMock(value='frometcd')))
self.assertEquals(
'frometcd',
config.cli_etcd_or_default('test', cli.test, 'default', ds))
11 changes: 6 additions & 5 deletions test/test_containermgr_kubernetes.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
from mock import MagicMock

from . import TestCase
from commissaire.config import Config
from commissaire.containermgr.kubernetes import KubeContainerManager


Expand All @@ -33,16 +34,16 @@ def test_node_registered(self):
"""
Verify that KuberContainerManager().node_registered() works as expected.
"""
connection_config = {
'etcd': {
config = Config(
etcd={
'uri': urlparse.urlparse('http://127.0.0.1:4321'),
},
'kubernetes': {
kubernetes={
'uri': urlparse.urlparse('http://127.0.0.1:8080'),
'token': 'token',
}
}
kube_container_mgr = KubeContainerManager(connection_config)
)
kube_container_mgr = KubeContainerManager(config)
# First call should return True. The rest should be False.
kube_container_mgr.con = MagicMock()
kube_container_mgr.con.get = MagicMock(side_effect=(
Expand Down

0 comments on commit a5c4e02

Please sign in to comment.