ich wollte hier einen Problem-Fix mit einer Anregung verbinden.
Ich hatte gerade das Problem, dass ich in einem Netzwerk den Client verteilen wollte, allerdings WINS nicht wirklich mitspielen wollte.
Ich bekam immer nur eine aberweitzige NT_STATUS* - Meldung nach der anderen (also eine gelöst, gab es direkt eine neue) - obwohl nslookup kein Problem hatte, die Hosts zu finden.
Da mir das zu blöd wurde und ein paar Tests mit winexe (die von Ubuntu) gezeigt haben, dass IP-Adresse auch funktioniert, habe ich versucht mit Hilfe der IPs zu deployen.
Leider scheint deploy-opsi-client-agent dies nicht direkt zu unterstützen.
Wenn ich z. B. zu 192.168.yy.xx deployen möchte, bekommt 'winexe' "192" als Hostname übergeben.
Ergo habe ich mir das selbst zurechtgefummelt, sodass es mit IP funktioniert (habe schlicht in den Befehlen "hn" für Hostname, gegen "ipAddress" für IP-Adresse getauscht.
Ich würde mir wünschen, dass das in zukünftigen Versionen vielleicht als Schalter verfügbar ist.
Das Deployment hat übrigens nun ohne Probleme funktioniert.
Anbei meine Version des Scriptes "opsi-deploy-client-agent.ip_address" [kann man sich einfach mit in den Ordner des opsi-client-agent legen, wenn man es nutzen möchte].
Die Stellen an denen ich bearbeitet habe, erkennt man daran, dass der Original-Befehl nochmal auskommentiert darüber oder darunter steht.
Code: Alles auswählen
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
= = = = = = = = = = = = = = = = = =
= opsi-deploy-client-agent =
= = = = = = = = = = = = = = = = = =
This tool is part of the desktop management solution opsi
(open pc server integration) http://www.opsi.org
Copyright (C) 2007-2010 uib GmbH
http://www.uib.de/
All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License version 2 as
published by the Free Software Foundation.
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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
@copyright: uib GmbH <info@uib.de>
@author: Jan Schneider <j.schneider@uib.de>
@license: GNU General Public License version 2
"""
__version__ = '4.0.1.4'
import sys, os, socket, time, gettext, getopt, getpass, re, threading, inspect
# OPSI imports
from OPSI.Logger import *
from OPSI.System import *
from OPSI.Util import *
from OPSI.Util.File import IniFile
from OPSI.Object import *
from OPSI.Types import *
from OPSI.Backend.BackendManager import BackendManager
logger = Logger()
logLevel = LOG_WARNING
logger.setConsoleLevel(logLevel)
logger.setLogFormat('[%L] %M')
logger.setConsoleColor(True)
# Get locale
try:
t = gettext.translation('opsi-deploy-client-agent', LOCALE_DIR)
_ = t.ugettext
except Exception, e:
#logger.error("Locale not found: %s" % e)
def _(string):
"""Dummy method, created and called when no locale is found.
Uses the fallback language (called C; means english) then."""
return string
def usage():
print _(u"\nUsage: %s [options] [host]...") % os.path.basename(sys.argv[0])
print _(u"Deploy opsi client agent to the specified clients.")
print _(u"The c$ and admin$ must be accessable on every client.")
print _(u"Simple File Sharing (Folder Options) should be disabled on the Windows machine.")
print _(u"Options:")
print _(u" -h show this help text")
print _(u" -V show version information")
print _(u" -v increase verbosity (can be used multiple times)")
print _(u" -u username for authentication (default: Administrator)")
print _(u" example for a domain account: -u \"<DOMAIN>\\\\<username>\"")
print _(u" -p password for authentication")
print _(u" -c use fqdn instead of hostname for smb/cifs connection")
print _(u" -x try installation even if ping fails")
print _(u" -r reboot computer after installation")
print _(u" -s shutdown computer after installation")
print _(u" -o start opsiclientd service after installation")
print _(u" -f file containing list of clients (one hostname per line)")
print _(u" -S skip known opsi clients")
print _(u" -t number of concurrent deployment threads (default: 1)")
print ""
def winexe(cmd, host, username, password):
cmd = forceUnicode(cmd)
host = forceUnicode(host)
username = forceUnicode(username)
password = forceUnicode(password)
match = re.search('^([^\\\\]+)\\\\+([^\\\\]+)$', username)
if match:
username = match.group(1) + u'\\' + match.group(2)
winexe = './winexe'
try:
print _(u"Using system's winexe.")
winexe = which('winexe')
except:
print _(u"Using own winexe.")
pass
return execute( u"%s -U '%s' //%s '%s'" % (winexe, username + '%' + password.replace("'", "'\"'\"'"), host, cmd) )
class DeployThread(threading.Thread):
def __init__(self, host, backend, username, password, shutdown, reboot, startService, useNetbios, stopOnPingFailure, skipExistingClient):
threading.Thread.__init__(self)
self.host = host
self.backend = backend
self.username = username
self.password = password
self.shutdown = shutdown
self.reboot = reboot
self.startService = startService
self.useNetbios = useNetbios
self.stopOnPingFailure = stopOnPingFailure
self.skipExistingClient = skipExistingClient
def run(self):
host = forceUnicodeLower(self.host)
hostId = u''
hostObj = None
hostCreated = False
try:
hostName = host.split('.')[0]
if (host.count(u'.') < 2):
hostId = forceHostId(host.replace('_', '-') + u'.' + u'.'.join(getFQDN().split(u'.')[1:]))
else:
hostId = forceHostId(host.replace('_', '-'))
if self.backend.host_getIdents(type = 'OpsiClient', id = hostId) and self.skipExistingClient:
logger.notice(u"Skipping host '%s'" % hostId)
return
logger.notice(u"Starting deployment to host '%s'" % hostId)
logger.notice(u"Querying for ip address of host '%s'" % hostId)
ipAddress = u''
logger.info(u"Getting host '%s' by name" % hostId)
try:
ipAddress = socket.gethostbyname(hostId)
except Exception, e:
logger.warning(u"Failed to get ip address for host '%s' by syscall: %s" % (hostId, e))
if ipAddress:
logger.notice(u"Got ip address '%s' from syscall" % ipAddress)
else:
logger.info(u"Executing 'nslookup %s#20'" % hostName)
for line in execute(u"nmblookup %s#20" % hostName):
match = re.search("^(\d+\.\d+\.\d+\.\d+)\s+%s<20>" % hostName, line, re.IGNORECASE)
if match:
ipAddress = match.group(1)
break
if ipAddress:
logger.notice(u"Got ip address '%s' from netbios lookup" % ipAddress)
else:
raise Exception(u"Failed to get ip address for host '%s'" % hostName)
logger.notice(u"Pinging host %s ..." % ipAddress)
alive = False
try:
for line in execute(u"ping -q -c2 %s" % ipAddress):
match = re.search("\s+(\d+)%\s+packet\s+loss", line)
if match and (forceInt(match.group(1)) < 100):
alive = True
except Exception, e:
logger.error(e)
if alive:
logger.notice(u"Host %s is up" % ipAddress)
elif self.stopOnPingFailure:
raise Exception(u"No ping response received from %s" % ipAddress)
else:
logger.warning(u"No ping response received from %s" % ipAddress)
logger.notice(u"Getting hardware ethernet address of host '%s'" % hostId)
mac = u''
f = open("/proc/net/arp")
for line in f.readlines():
line = line.strip()
if not line:
continue
if (line.split()[0] == ipAddress):
mac = line.split()[3].lower()
break
f.close()
if not mac or (mac == u'00:00:00:00:00:00'):
logger.warning(u"Failed to get hardware ethernet address for host '%s'" % hostName)
mac = u''
else:
logger.notice(u"Found hardware ethernet address '%s'" % mac)
if not self.backend.host_getIdents(type = 'OpsiClient', id = hostId):
logger.notice(u"Creating client '%s'" % hostId)
hostObj = OpsiClient(
id = hostId,
hardwareAddress = mac,
ipAddress = ipAddress,
description = u"",
notes = u"Created by opsi-deploy-client-agent at %s" \
% time.strftime("%a, %d %b %Y %H:%M:%S", time.localtime())
)
self.backend.host_createObjects([hostObj])
hostCreated = True
hostObj = self.backend.host_getObjects(type = 'OpsiClient', id = hostId)[0]
hn = hostId
if self.useNetbios:
hn = hostName
logger.notice(u"Testing winexe")
cmd = u'cmd.exe /C "del /s /q c:\\tmp\\opsi-client-agent_inst && rmdir /s /q c:\\tmp\\opsi-client-agent_inst || echo not found"'
for trynum in (1, 2):
try:
#winexe(cmd, hn, self.username, self.password)
winexe(cmd, ipAddress, self.username, self.password)
break
except Exception, e:
if (trynum == 2):
raise Exception(u"Failed to execute command on host '%s': winexe error: %s" % (hn, e))
logger.info(u"Winexe failure '%s', retrying" % e)
time.sleep(2)
logger.notice(u"Patching config.ini")
configIniName = u'%s_config.ini' % randomString(10)
copy(os.path.join(u'files', u'opsi', u'cfg', u'config.ini'), '/tmp/%s' % configIniName)
configFile = IniFile('/tmp/%s' % configIniName)
config = configFile.parse()
if not config.has_section('shareinfo'):
config.add_section('shareinfo')
config.set('shareinfo', 'pckey', hostObj.opsiHostKey)
if not config.has_section('general'):
config.add_section('general')
config.set('general', 'dnsdomain', u'.'.join(hostObj.id.split('.')[1:]))
configFile.generate(config)
try:
logger.notice(u"Copying installation files")
cmd = u"%s //%s/c$ -U '%s' -c 'prompt; recurse; md tmp; cd tmp; md opsi-client-agent_inst; cd opsi-client-agent_inst; mput files; mput utils; cd files\\opsi\\cfg; lcd /tmp; put %s config.ini; exit;'" \
% (which('smbclient'), ipAddress, self.username + '%' + self.password.replace("'", "'\"'\"'"), configIniName)
#% (which('smbclient'), hn, self.username + '%' + self.password.replace("'", "'\"'\"'"), configIniName)
execute(cmd)
logger.notice(u"Installing opsi-client-agent")
cmd = u'c:\\tmp\\opsi-client-agent_inst\\files\\opsi\\opsi-winst\\winst32.exe /batch c:\\tmp\\opsi-client-agent_inst\\files\\opsi\\setup.ins c:\\tmp\\opsi-client-agent.log /PARAMETER REMOTEDEPLOY'
for trynum in (1, 2):
try:
#winexe(cmd, hn, self.username, self.password)
winexe(cmd, ipAddress, self.username, self.password)
break
except Exception, e:
if (trynum == 2):
raise Exception(u"Failed to install opsi-client-agent: %s" % e)
logger.info(u"Winexe failure '%s', retrying" % e)
time.sleep(2)
finally:
os.remove('/tmp/%s' % configIniName)
try:
cmd = u'cmd.exe /C "del /s /q c:\\tmp\\opsi-client-agent_inst && rmdir /s /q c:\\tmp\\opsi-client-agent_inst"'
#winexe(cmd, hn, self.username, self.password)
winexe(cmd, ipAddress, self.username, self.password)
except Exception, e:
logger.error(e)
logger.notice(u"opsi-client-agent successfully installed on '%s'" % hostId)
self.backend.productOnClient_updateObjects([
ProductOnClient(
productType = u'LocalbootProduct',
clientId = hostId,
productId = u'opsi-client-agent',
installationStatus = u'installed',
actionResult = u'successful'
)
])
if self.reboot or self.shutdown:
cmd = u''
if self.reboot:
logger.notice(u"Rebooting machine '%s'" % hostId)
cmd = u'"%ProgramFiles%\\opsi.org\\opsi-client-agent\\utilities\\shutdown.exe" /L /R /T:20 "opsi-client-agent installed - reboot" /Y /C'
elif self.shutdown:
logger.notice(u"Shutting down machine '%s'" % hostId)
cmd = u'"%ProgramFiles%\\opsi.org\\opsi-client-agent\\utilities\\shutdown.exe" /L /T:20 "opsi-client-agent installed - shutdown" /Y /C'
try:
pf = None
for const in ('%ProgramFiles(x86)%', '%ProgramFiles%'):
lines = []
try:
#lines = winexe(u'cmd.exe /C "echo %s"' % const, hn, self.username, self.password)
lines = winexe(u'cmd.exe /C "echo %s"' % const, ipAddress, self.username, self.password)
except Exception, e:
logger.warning(e)
continue
for line in lines:
line = line.strip()
if (line.find('unavailable') != -1):
continue
pf = line
if pf and (pf != const):
break
pf = None
if not pf:
raise Exception(u"Failed to get program files path")
logger.info(u"Program files path is '%s'" % pf)
#winexe(cmd.replace(u'%ProgramFiles%', pf), hn, self.username, self.password)
winexe(cmd.replace(u'%ProgramFiles%', pf), ipAddress, self.username, self.password)
except Exception, e:
if self.reboot:
logger.error(u"Failed to reboot computer: %s" % e)
else:
logger.error(u"Failed to shutdown computer: %s" % e)
elif self.startService:
try:
#winexe(u'net start opsiclientd', hn, self.username, self.password)
winexe(u'net start opsiclientd', ipAddress, self.username, self.password)
except Exception, e:
logger.error(u"Failed to start opsiclientd: %s" % e)
except Exception, e:
logger.error(u"Deployment to '%s' failed: %s" % (hostId, e))
if hostObj and hostCreated:
try:
self.backend.host_deleteObjects([hostObj])
except Exception, e2:
logger.error(e2)
def main(argv):
global logLevel
hosts = []
hostFile = None
username = u''
password = u''
shutdown = False
reboot = False
startService = False
useNetbios = True
stopOnPingFailure = True
skipExistingClient = False
maxThreads = 1
# Get options
try:
(opts, args) = getopt.getopt(argv, "hVvcxsrou:p:f:St:")
except getopt.GetoptError:
usage()
sys.exit(1)
for (opt, arg) in opts:
if (opt == "-h"):
usage()
return
elif (opt == "-V"):
print __version__
return
elif (opt == "-v"):
logLevel += 1
logger.setConsoleLevel(logLevel)
elif (opt == "-p"):
password = arg
elif (opt == "-u"):
username = arg
elif (opt == "-r"):
reboot = True
elif (opt == "-s"):
shutdown = True
elif (opt == "-o"):
startService = True
elif (opt == "-c"):
useNetbios = False
elif (opt == "-x"):
stopOnPingFailure = False
elif (opt == "-S"):
skipExistingClient = True
elif (opt == "-f"):
hostFile = arg
if not os.path.isfile(hostFile):
raise Exception(u"File '%s' not found!" % hostFile)
elif (opt == "-t"):
maxThreads = forceInt(arg)
if (maxThreads < 1):
maxThreads = 1
if hostFile:
f = open(hostFile)
for line in f.readlines():
line = line.strip()
if not line or line.startswith('#') or line.startswith(';'):
continue
hosts.append(forceUnicodeLower(line))
f.close()
elif (len(args) > 0):
hosts = args
else:
raise Exception("No hosts given.")
if not username:
username = u'Administrator'
if not password:
password = forceUnicode(getpass.getpass())
if not password:
raise Exception("No password given.")
logger.addConfidentialString(password)
# Create BackendManager
backend = BackendManager(
dispatchConfigFile = u'/etc/opsi/backendManager/dispatch.conf',
backendConfigDir = u'/etc/opsi/backends',
extend = True,
depotbackend = False,
hostControlBackend = False
)
runningThreads = []
while hosts:
while (len(runningThreads) > maxThreads):
time.sleep(1)
for t in runningThreads:
if t.isAlive():
continue
runningThreads.remove(t)
break
host = hosts.pop()
t = DeployThread(host, backend, username, password, shutdown, reboot, startService, useNetbios, stopOnPingFailure, skipExistingClient)
t.start()
runningThreads.append(t)
time.sleep(0.5)
for t in runningThreads:
if t.isAlive():
t.join()
time.sleep(1)
if (__name__ == "__main__"):
try:
os.chdir( os.path.dirname(os.path.abspath(sys.argv[0])) )
main(sys.argv[1:])
except SystemExit:
pass
except Exception, e:
logger.setConsoleLevel(LOG_ERROR)
logger.logException(e)
print >> sys.stderr, u"ERROR: %s" % forceUnicode(e)
sys.exit(1)
sys.exit(0)