ugly -> bad

This commit is contained in:
Darko Poljak 2016-12-03 18:12:38 +01:00
parent 8c53ce78f5
commit e6fc74c081
4 changed files with 146 additions and 94 deletions

View File

@ -22,15 +22,14 @@
import logging import logging
import os import os
import shutil
import sys import sys
import time import time
import pprint
import itertools import itertools
import tempfile import tempfile
import socket import socket
import cdist import cdist
import cdist.hostsource
import cdist.exec.local import cdist.exec.local
import cdist.exec.remote import cdist.exec.remote
@ -61,55 +60,17 @@ class Config(object):
self.local.create_files_dirs() self.local.create_files_dirs()
self.remote.create_files_dirs() self.remote.create_files_dirs()
@staticmethod
def hostfile_process_line(line):
"""Return host from read line or None if no host present."""
if not line:
return None
# remove comment if present
comment_index = line.find('#')
if comment_index >= 0:
host = line[:comment_index]
else:
host = line
# remove leading and trailing whitespaces
host = host.strip()
# skip empty lines
if host:
return host
else:
return None
@staticmethod @staticmethod
def hosts(source): def hosts(source):
"""Yield hosts from source. try:
Source can be a sequence or filename (stdin if \'-\'). yield from cdist.hostsource.HostSource(source)()
In case of filename each line represents one host. except (IOError, OSError, UnicodeError) as e:
""" raise cdist.Error(
if isinstance(source, str): "Error reading hosts from \'{}\': {}".format(
import fileinput source, e))
try:
for host in fileinput.input(files=(source)):
host = Config.hostfile_process_line(host)
if host:
yield host
except (IOError, OSError, UnicodeError) as e:
raise cdist.Error(
"Error reading hosts from file \'{}\': {}".format(
source, e))
else:
if source:
for host in source:
yield host
@classmethod @classmethod
def commandline(cls, args): def _check_and_prepare_args(cls, args):
"""Configure remote system"""
import multiprocessing
# FIXME: Refactor relict - remove later
log = logging.getLogger("cdist")
if args.manifest == '-' and args.hostfile == '-': if args.manifest == '-' and args.hostfile == '-':
raise cdist.Error(("Cannot read both, manifest and host file, " raise cdist.Error(("Cannot read both, manifest and host file, "
"from stdin")) "from stdin"))
@ -134,10 +95,6 @@ class Config(object):
import atexit import atexit
atexit.register(lambda: os.remove(initial_manifest_temp_path)) atexit.register(lambda: os.remove(initial_manifest_temp_path))
process = {}
failed_hosts = []
time_start = time.time()
# default remote cmd patterns # default remote cmd patterns
args.remote_exec_pattern = None args.remote_exec_pattern = None
args.remote_copy_pattern = None args.remote_copy_pattern = None
@ -154,10 +111,29 @@ class Config(object):
if args_dict['remote_copy'] is None: if args_dict['remote_copy'] is None:
args.remote_copy_pattern = cdist.REMOTE_COPY + mux_opts args.remote_copy_pattern = cdist.REMOTE_COPY + mux_opts
@classmethod
def _base_root_path(cls, args):
if args.out_path: if args.out_path:
base_root_path = args.out_path base_root_path = args.out_path
else: else:
base_root_path = tempfile.mkdtemp() base_root_path = tempfile.mkdtemp()
return base_root_path
@classmethod
def commandline(cls, args):
"""Configure remote system"""
import multiprocessing
# FIXME: Refactor relict - remove later
log = logging.getLogger("cdist")
cls._check_and_prepare_args(args)
process = {}
failed_hosts = []
time_start = time.time()
base_root_path = cls._base_root_path(args)
hostcnt = 0 hostcnt = 0
for host in itertools.chain(cls.hosts(args.host), for host in itertools.chain(cls.hosts(args.host),
@ -199,6 +175,24 @@ class Config(object):
raise cdist.Error("Failed to configure the following hosts: " + raise cdist.Error("Failed to configure the following hosts: " +
" ".join(failed_hosts)) " ".join(failed_hosts))
@classmethod
def _resolve_remote_cmds(cls, args, host_base_path):
control_path = os.path.join(host_base_path, "ssh-control-path")
# If we constructed patterns for remote commands then there is
# placeholder for ssh ControlPath, format it and we have unique
# ControlPath for each host.
#
# If not then use args.remote_exec/copy that user specified.
if args.remote_exec_pattern:
remote_exec = args.remote_exec_pattern.format(control_path)
else:
remote_exec = args.remote_exec
if args.remote_copy_pattern:
remote_copy = args.remote_copy_pattern.format(control_path)
else:
remote_copy = args.remote_copy
return (remote_exec, remote_copy, )
@classmethod @classmethod
def onehost(cls, host, host_base_path, host_dir_name, args, parallel): def onehost(cls, host, host_base_path, host_dir_name, args, parallel):
"""Configure ONE system""" """Configure ONE system"""
@ -206,20 +200,7 @@ class Config(object):
log = logging.getLogger(host) log = logging.getLogger(host)
try: try:
control_path = os.path.join(host_base_path, "ssh-control-path") remote_exec, remote_copy = cls._resolve_remote_cmds(host_base_path)
# If we constructed patterns for remote commands then there is
# placeholder for ssh ControlPath, format it and we have unique
# ControlPath for each host.
#
# If not then use args.remote_exec/copy that user specified.
if args.remote_exec_pattern:
remote_exec = args.remote_exec_pattern.format(control_path)
else:
remote_exec = args.remote_exec
if args.remote_copy_pattern:
remote_copy = args.remote_copy_pattern.format(control_path)
else:
remote_copy = args.remote_copy
log.debug("remote_exec for host \"{}\": {}".format( log.debug("remote_exec for host \"{}\": {}".format(
host, remote_exec)) host, remote_exec))
log.debug("remote_copy for host \"{}\": {}".format( log.debug("remote_copy for host \"{}\": {}".format(

View File

@ -30,40 +30,13 @@ import multiprocessing
import cdist import cdist
import cdist.exec.util as exec_util import cdist.exec.util as exec_util
import cdist.util.ipaddr as ipaddr
# check whether addr is IPv6
try:
# python 3.3+
import ipaddress
def _is_ipv6(addr):
try:
return ipaddress.ip_address(addr).version == 6
except ValueError:
return False
except ImportError:
# fallback for older python versions
import socket
def _is_ipv6(addr):
try:
socket.inet_aton(addr)
return False
except socket.error:
pass
try:
socket.inet_pton(socket.AF_INET6, addr)
return True
except socket.error:
pass
return False
def _wrap_addr(addr): def _wrap_addr(addr):
"""If addr is IPv6 then return addr wrapped between '[' and ']', """If addr is IPv6 then return addr wrapped between '[' and ']',
otherwise return it intact.""" otherwise return it intact."""
if _is_ipv6(addr): if ipaddr.is_ipv6(addr):
return "".join(("[", addr, "]", )) return "".join(("[", addr, "]", ))
else: else:
return addr return addr

72
cdist/hostsource.py Normal file
View File

@ -0,0 +1,72 @@
# -*- coding: utf-8 -*-
#
# 2016 Darko Poljak (darko.poljak at gmail.com)
#
# This file is part of cdist.
#
# cdist is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# cdist 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with cdist. If not, see <http://www.gnu.org/licenses/>.
#
#
import fileinput
class HostSource(object):
"""
Host source object.
Source can be a sequence or filename (stdin if \'-\').
In case of filename each line represents one host.
"""
def __init__(self, source):
self.source = source
def _process_file_line(self, line):
"""Return host from read line or None if no host present."""
if not line:
return None
# remove comment if present
comment_index = line.find('#')
if comment_index >= 0:
host = line[:comment_index]
else:
host = line
# remove leading and trailing whitespaces
host = host.strip()
# skip empty lines
if host:
return host
else:
return None
def _hosts_from_sequence(self):
for host in self.source:
yield host
def _hosts_from_file(self):
for line in fileinput.input(files=(self.source)):
host = self._process_file_line(line)
if host:
yield host
def hosts(self):
if not source:
return
if isinstance(self.source, str):
yield from self._hosts_from_file()
else:
yield from self._hosts_from_sequence()
def __call__(self):
yield from self.hosts()

View File

@ -55,3 +55,29 @@ def resolve_target_addresses(host):
host_fqdn = '' host_fqdn = ''
return (host, host_name, host_fqdn) return (host, host_name, host_fqdn)
# check whether addr is IPv6
try:
# python 3.3+
import ipaddress
def is_ipv6(addr):
try:
return ipaddress.ip_address(addr).version == 6
except ValueError:
return False
except ImportError:
# fallback for older python versions
def is_ipv6(addr):
try:
socket.inet_aton(addr)
return False
except socket.error:
pass
try:
socket.inet_pton(socket.AF_INET6, addr)
return True
except socket.error:
pass
return False