from .xlate import XLATOR
-__version__ = '0.8.9'
+__version__ = '0.9.0'
LOG = logging.getLogger(__name__)
ks_meta_list.append("SWAP_SIZE_MB={}".format(self.cfg.swap_size_mb))
ks_meta_list.append("SYSTEM_STATUS={}".format(status))
ks_meta_list.append("WS_REL_FILESDIR={}".format(self.cfg.cobbler_ws_rel_filesdir))
+ ks_meta_list.append("COBBLER_URL=http://{}".format(self.cfg.cobbler_host))
ks_meta = None
if ks_meta_list:
return assigments[mac]
return None
+ # -------------------------------------------------------------------------
+ def get_dhcp_ips(self, mac_address):
+
+ mac = mac_address.lower()
+ LOG.debug(_("Trying to get IP of MAC address {!r} given by DHCP ...").format(mac))
+ all_leases = self.get_remote_filecontent(self.dhcpd_leases_file)
+
+ ips = []
+
+ cur_ip = None
+ assigments = {}
+ re_lease_start = re.compile(r'^\s*lease\s+((?:\d{1,3}\.){3}\d{1,3})\s+', re.IGNORECASE)
+ re_mac = re.compile(
+ r'^\s*hardware\s+ethernet\s+((?:[0-9a-f]{2}:){5}[0-9a-f]{2})\s*;', re.IGNORECASE)
+
+ for line in all_leases.splitlines():
+ match = re_lease_start.match(line)
+ if match:
+ try:
+ ip = ipaddress.ip_address(match.group(1))
+ cur_ip = str(ip)
+ except ValueError as e:
+ msg = _("Found invalid IP address {ip!r} in leases file: {err}").format(
+ ip=match.group(1), err=e)
+ LOG.error(msg)
+ continue
+
+ match = re_mac.match(line)
+ if match:
+ found_mac = match.group(1).lower()
+ if cur_ip:
+ assigments[cur_ip] = found_mac
+ continue
+
+ for ip in assigments.keys():
+ found_mac = assigments[ip]
+ if mac == found_mac:
+ ips.append(ip)
+
+ if self.verbose > 2:
+ LOG.debug(_("Found DHCP IP assignments:") + "\n" + pp(assigments))
+
+ return ips
+
# -------------------------------------------------------------------------
def ensure_webroot(self):
# Own modules
from fb_tools.common import pp, to_str, is_sequence
-
from fb_tools.errors import HandlerError, ExpectedHandlerError
-
from fb_tools.handler import BaseHandler
+from fb_tools.xlate import format_list
from fb_vmware.errors import VSphereExpectedError
from fb_vmware.errors import VSphereDatacenterNotFoundError
from .xlate import XLATOR
-__version__ = '2.2.5'
+__version__ = '2.3.0'
LOG = logging.getLogger(__name__)
TZ = pytz.timezone('Europe/Berlin')
self.tpl_vm_hostname = None
self.tpl_macaddress = None
self.tpl_ip = None
+ self.tpl_ips = []
self.ts_start_install = None
self.ts_finish_install = None
self.initial_sleep = 60
self.vsphere.poweron_vm(self.tpl_vm, max_wait=self.cfg.max_wait_for_poweron_vm)
self.ts_start_install = time.time()
- self.eval_tpl_ip()
+ self.eval_tpl_ips()
self.wait_for_finish_install()
self.show_install_log()
pool=self.cluster.resource_pool, max_wait=self.cfg.max_wait_for_create_vm)
# -------------------------------------------------------------------------
- def eval_tpl_ip(self):
+ def eval_tpl_ips(self):
LOG.info(_("Trying to evaluate the IP address of the template VM ..."))
- initial_delay = self.vm_boot_delay_secs + 10
+ initial_delay = (2 * self.vm_boot_delay_secs) + 120
LOG.debug(_("Waiting initially for {} seconds:").format(initial_delay))
print(' ==> ', end='', flush=True)
cur_duration = cur_time - start_time
print('', flush=True)
- self.tpl_ip = self.cobbler.get_dhcp_ip(self.tpl_macaddress)
- if not self.tpl_ip:
+ self.tpl_ips = self.cobbler.get_dhcp_ips(self.tpl_macaddress)
+ if not self.tpl_ips:
msg = _(
"Did not got the IP address of MAC address {mac!r} after "
"{delay} seconds.").format(mac=self.tpl_macaddress, delay=initial_delay)
raise ExpectedHandlerError(msg)
- LOG.info(_("Got IP address {!r} for template VM.").format(self.tpl_ip))
+ LOG.info(_("Got IP addresses for template VM:") + ' ' + format_list(self.tpl_ips))
# -------------------------------------------------------------------------
def wait_for_finish_install(self):
LOG.debug(_("Waiting for SSH available ..."))
- addr_infos = socket.getaddrinfo(self.tpl_ip, 22, socket.AF_INET, socket.SOCK_STREAM)
- if self.verbose > 1:
- msg = _("Got following address_infos for {h!r}, IPv4 TCP port {p}:").format(
- h=self.tpl_ip, p=22)
- msg += '\n' + pp(addr_infos)
- LOG.debug(msg)
- if not addr_infos:
- raise HandlerError(_("Did not get address infos for {h!r}, IPv4 TCP port {p}.").format(
- h=self.tpl_ip, p=22))
+ addr_infos = {}
+ for ip in self.tpl_ips:
+ ai = socket.getaddrinfo(ip, 22, socket.AF_INET, socket.SOCK_STREAM)
+ if self.verbose > 1:
+ msg = _("Got following address_infos for {h!r}, IPv4 TCP port {p}:").format(
+ h=ip, p=22)
+ msg += '\n' + pp(ai)
+ LOG.debug(msg)
+ if not ai:
+ raise HandlerError(_("Did not get address infos for {h!r}, IPv4 TCP port {p}.").format(
+ h=ip, p=22))
- addr_info = random.choice(addr_infos)
- LOG.debug(_("Using address info: {}").format(pp(addr_info)))
- family, socktype, proto, canonname, sockaddr = addr_info
+ addr_info = random.choice(ai)
+ LOG.debug(_("Using address info: {}").format(pp(addr_info)))
+ addr_infos[ip] = addr_info
if self.verbose <= 3:
print(' ==> ', end='', flush=True)
i = 0
last_dot = cur_time
- if self.verbose > 3:
- LOG.debug(_("Trying to connect to {a} via TCP port {p} ...").format(
- a=sockaddr[0], p=sockaddr[1]))
-
- try:
- sock = socket.socket(family, socktype, proto)
- except socket.error as e:
- sock = None
- LOG.warn(_("Error creating socket: {}").format(e))
- continue
+ for ip in addr_infos.keys():
- try:
- sock.connect(sockaddr)
- except socket.error as e:
- sock.close()
- sock = None
- if self.verbose > 3:
- LOG.debug(_("Could not connect: {}").format(e))
+ addr_info = addr_infos[ip]
+ if self.check_ssh_available(addr_info):
+ ssh_available = True
+ self.tpl_ip = ip
+ break
+
+ if not ssh_available:
continue
if self.verbose <= 3:
print('', flush=True)
-
- LOG.info(_("Connected to {a} via TCP port {p}.").format(
- a=sockaddr[0], p=sockaddr[1]))
- data = sock.recv(4096)
- if data:
- msg = to_str(data).strip()
- LOG.info(_("Got SSHD banner: {}").format(msg))
- sock.close()
- sock = None
- ssh_available = True
self.ts_finish_install = time.time()
self.ts_finish_install = time.time()
_("SSH not available after {:0.1f} seconds, giving up.").format(duration))
# -------------------------------------------------------------------------
- def exec_remote(self, cmd):
+ def check_ssh_available(self, addr_info):
+
+ family, socktype, proto, canonname, sockaddr = addr_info
+
+ if self.verbose > 3:
+ LOG.debug(_("Trying to connect to {a} via TCP port {p} ...").format(
+ a=sockaddr[0], p=sockaddr[1]))
+
+ try:
+ sock = socket.socket(family, socktype, proto)
+ except socket.error as e:
+ sock = None
+ LOG.warn(_("Error creating socket: {}").format(e))
+ return False
+
+ try:
+ sock.connect(sockaddr)
+ except socket.error as e:
+ sock.close()
+ sock = None
+ if self.verbose > 3:
+ LOG.debug(_("Could not connect: {}").format(e))
+ return False
+
+ LOG.info(_("Connected to {a} via TCP port {p}.").format(
+ a=sockaddr[0], p=sockaddr[1]))
+
+ data = sock.recv(4096)
+ if data:
+ msg = to_str(data).strip()
+ LOG.info(_("Got SSHD banner: {}").format(msg))
+
+ sock.close()
+ sock = None
+
+ return True
+
+ # -------------------------------------------------------------------------
+ def exec_remote(self, cmd, strict_host_key_checking=False):
ssh = None
result = {'out': None, 'err': None}
+ if strict_host_key_checking:
+ policy = paramiko.client.AutoAddPolicy()
+ else:
+ policy = paramiko.client.MissingHostKeyPolicy()
try:
ssh = paramiko.SSHClient()
LOG.debug(_("Loading SSH system host keys."))
ssh.load_system_host_keys()
- LOG.debug(_("Setting SSH missing host key policy to {}.").format('AutoAddPolicy'))
- ssh.set_missing_host_key_policy(paramiko.client.AutoAddPolicy())
+ LOG.debug(_("Setting SSH missing host key policy to {}.").format(
+ policy.__class__.__name__))
+ ssh.set_missing_host_key_policy(policy)
LOG.debug(_("Connecting to {h!r}, port {p} as {u!r} per SSH ...").format(
h=self.tpl_ip, p=self.ssh_port, u=self.ssh_user))