View | Details | Raw Unified | Return to bug 29191
Collapse All | Expand All

(-)a/management/univention-system-info/system-info-upload.py (+137 lines)
Line 0    Link Here 
1
#!/usr/bin/python2.6
2
#
3
# Univention System Info
4
#  Stores files uploaded via HTTP POST
5
#
6
# Copyright 2009-2014 Univention GmbH
7
#
8
# http://www.univention.de/
9
#
10
# All rights reserved.
11
#
12
# The source code of this program is made available
13
# under the terms of the GNU Affero General Public License version 3
14
# (GNU AGPL V3) as published by the Free Software Foundation.
15
#
16
# Binary versions of this program provided by Univention to you as
17
# well as other copyrighted, protected or trademarked materials like
18
# Logos, graphics, fonts, specific documentations and configurations,
19
# cryptographic keys etc. are subject to a license agreement between
20
# you and Univention and not subject to the GNU AGPL V3.
21
#
22
# In the case you use this program under the terms of the GNU AGPL V3,
23
# the program is provided in the hope that it will be useful,
24
# but WITHOUT ANY WARRANTY; without even the implied warranty of
25
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
# GNU Affero General Public License for more details.
27
#
28
# You should have received a copy of the GNU Affero General Public
29
# License with the Debian GNU/Linux or Univention distribution in file
30
# /usr/share/common-licenses/AGPL-3; if not, see
31
# <http://www.gnu.org/licenses/>.
32
33
import univention.config_registry as ucr
34
35
import cgi
36
from email.MIMEText import MIMEText
37
import os
38
import socket
39
import smtplib
40
import time
41
import tarfile
42
43
configRegistry = ucr.ConfigRegistry()
44
configRegistry.load()
45
46
47
def save_uploaded_file(form_field, upload_dir, max_size):
48
	form = cgi.FieldStorage()
49
	if form_field not in form:
50
		return (False, None, None)
51
	fileitem = form[form_field]
52
	if not fileitem.filename.endswith('.tar.gz'):
53
		return (False, fileitem.filename, None)
54
	basename = fileitem.filename[:-len('.tar.gz')]
55
	filename = os.path.join(upload_dir, fileitem.filename)
56
	if not os.path.abspath(filename).startswith(upload_dir):
57
		return (False, None, None)
58
	if os.path.exists(filename):
59
		filename += '.%s' % str(time.time() * 100)
60
	fout = file(filename, 'wb')
61
	size = 0
62
	while True:
63
		chunk = fileitem.file.read(100000)
64
		if not chunk:
65
			break
66
		size += len(chunk)
67
		if size > max_size:
68
			fout.close()
69
			os.unlink(fout.name)
70
			return (False, filename, basename)
71
		fout.write(chunk)
72
	fout.close()
73
74
	return (True, filename, basename)
75
76
# make HTTP happy
77
print 'Content-Type: text/plain\n'
78
79
path = configRegistry.get('umc/sysinfo/upload/path', '/var/lib/univention-system-info/archives/')
80
81
ok, filepath, basename = save_uploaded_file('filename', path, configRegistry.get('umc/sysinfo/upload/size', '2000000'))
82
filename = filepath[len(path):]
83
84
if not ok:
85
	print 'ERROR: wrong file type or file too big'
86
else:
87
	infoTable = ''
88
	# get contents of info file
89
	try:
90
		tarFile = tarfile.open(os.path.join(path, filepath), 'r')
91
		infoTable = '<table>\n'
92
		infoDict = {}
93
		for line in tarFile.extractfile(tarFile.getmember('%s/info' % basename)).readlines():
94
			key, val = line.strip().split(':', 1)
95
			if isinstance(key, unicode):
96
				key = key.encode('UTF-8')
97
				val = val.encode('UTF-8')
98
			infoTable += '<tr><td>%s:</td><td>%s</td></tr>\n' % (key.strip(), val.strip())
99
			infoDict[key.strip()] = val.strip()
100
		infoTable += '</table>'
101
	except:
102
		import traceback
103
		infoTable += traceback.format_exc()
104
105
	msg = MIMEText('''
106
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
107
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
108
<html>
109
<head/>
110
<body>
111
<p>A new Univention system info archive has been uploaded.</p>
112
%s
113
114
<p>
115
Archive: <a href="https://%s/univention-system-info-upload/archives/%s">%s</a>
116
</p>
117
</body>
118
</html>
119
''' % (infoTable, socket.getfqdn(), filename, filename), 'html', 'utf-8')
120
	if 'Ticket No' in infoDict.keys() and infoDict['Ticket No']:
121
		msg['Subject'] = '[Ticket#%s] Univention System Info Upload' % (infoDict['Ticket No'],)
122
	else:
123
		msg['Subject'] = 'Univention System Info Upload'
124
	if 'Email' in infoDict.keys() and infoDict['Email']:
125
		sender = infoDict['Email']
126
	else:
127
		sender = configRegistry.get('umc/sysinfo/upload/sender', 'root')
128
	recipient = configRegistry.get('umc/sysinfo/upload/recipient', 'feedback@univention.de')
129
130
	msg['From'] = sender
131
	msg['To'] = recipient
132
133
	s = smtplib.SMTP()
134
	s.connect()
135
	s.sendmail(sender, [recipient], msg.as_string())
136
	s.close()
137
	print 'OK: file saved successfully'
(-)a/management/univention-system-info/umc/de.po (-2 / +2 lines)
 Lines 15-19   msgstr "" Link Here 
15
msgid "Overview of local systems hardware information"
15
msgid "Overview of local systems hardware information"
16
msgstr "Überblick der Hardwareinformationen des lokalen Systems"
16
msgstr "Überblick der Hardwareinformationen des lokalen Systems"
17
17
18
msgid "Hardware information"
18
msgid "Support module"
19
msgstr "Hardwareinformationen"
19
msgstr "Support Modul"
(-)a/management/univention-system-info/umc/js/de.po (-137 / +184 lines)
 Lines 1-10    Link Here 
1
# This file is auto-generated by the dh-umc tools and should not be edited!
1
# This file is auto-generated by the dh-umc tools and should not be edited!
2
#: umc/js/sysinfo.js:165
2
#: umc/js/sysinfo.js:102
3
msgid ""
3
msgid ""
4
msgstr ""
4
msgstr ""
5
"Project-Id-Version: univention-management-console-module-sysinfo\n"
5
"Project-Id-Version: univention-management-console-module-sysinfo\n"
6
"Report-Msgid-Bugs-To: packages@univention.de\n"
6
"Report-Msgid-Bugs-To: packages@univention.de\n"
7
"POT-Creation-Date: 2014-12-18 16:16+0100\n"
7
"POT-Creation-Date: 2016-04-05 15:34+0200\n"
8
"PO-Revision-Date: 2016-01-14 11:26+0100\n"
8
"PO-Revision-Date: 2016-01-14 11:26+0100\n"
9
"Last-Translator: Univention GmbH <packages@univention.de>\n"
9
"Last-Translator: Univention GmbH <packages@univention.de>\n"
10
"Language-Team: Univention GmbH <packages@univention.de>\n"
10
"Language-Team: Univention GmbH <packages@univention.de>\n"
 Lines 13-71   msgstr "" Link Here 
13
"Content-Type: text/plain; charset=UTF-8\n"
13
"Content-Type: text/plain; charset=UTF-8\n"
14
"Content-Transfer-Encoding: 8bit\n"
14
"Content-Transfer-Encoding: 8bit\n"
15
15
16
#: umc/js/sysinfo.js:144
16
#: umc/js/sysinfo.js:123
17
msgid ""
17
msgid ""
18
"<p>Additionally to the information listed above some more details about the "
18
"<p>After clicking \"Next\" the information will be gathered and uploaded to "
19
"system has been collected. The whole set of collected data that will be "
19
"Univention.</p>"
20
"transmitted to Univention can be downloaded at the following URL:</p>"
21
msgstr ""
20
msgstr ""
22
"<p>Zusätzlich zu den oben angezeigten Informationen wurden weitere Details "
23
"über das System ermittelt. Die gesamten Informationen, die an Univention "
24
"übertragen werden sollen, können unter der folgenden URL heruntergeladen "
25
"werden:</p>"
26
21
27
#: umc/js/sysinfo.js:94
22
#: umc/js/sysinfo.js:237
28
msgid ""
29
"<p>If a Univention Support Engineer has asked you to provide this "
30
"information, then please insert the ticket number of the related support "
31
"ticket into the following text field. The ticket number can be found in the "
32
"subject of a support mail of the ticket. This information will speed up the "
33
"processing of the ticket.</p>"
34
msgstr ""
35
"<p>Wenn Sie durch den Univention-Support gebeten worden sind, diese "
36
"Informationen zu ermitteln, dann geben Sie bitte im folgenden Feld die "
37
"Ticketnummer an, welche sich dem Betreff der Support-Mails entnehmen lässt. "
38
"Die Ticketnummer hilft bei der Zuordnung zu dem Supportfall und beschleunigt "
39
"die Bearbeitung.</p>"
40
41
#: umc/js/sysinfo.js:103
42
msgid ""
43
"<p>In the next step the information about the hardware of your system will "
44
"be collected and a summary will be shown. During this step, no information "
45
"will be sent to Univention.</p>"
46
msgstr ""
47
"<p>Im nächsten Schritt werden die Informationen des Systems ermittelt sowie "
48
"eine Zusammenfassung darüber angezeigt. Während dieses Vorganges werden "
49
"keine Informationen an Univention übertragen.</p>"
50
51
#: umc/js/sysinfo.js:169
52
msgid ""
53
"<p>The collected information can be transfered to Univention by uploading "
54
"the data or by sending it via mail. Please select the corresponding option.</"
55
"p>"
56
msgstr ""
57
"<p>Die ermittelten Informationen können entweder hochgeladen oder per Mail "
58
"an Univention geschickt werden. Bitte wählen Sie die gewünschte Variante.</p>"
59
60
#: umc/js/sysinfo.js:115
61
msgid ""
62
"<p>The following information has been collected and will be transfered to "
63
"Univention with your acceptance.</p>"
64
msgstr ""
65
"<p>Die folgenden Informationen wurden ermittelt und werden mit Ihrer "
66
"Zustimmung an Univention übertragen:</p>"
67
68
#: umc/js/sysinfo.js:265
69
msgid ""
23
msgid ""
70
"<p>The information could not be transfered to Univention.</p><p>You can send "
24
"<p>The information could not be transfered to Univention.</p><p>You can send "
71
"them as email!</p>"
25
"them as email!</p>"
 Lines 73-79   msgstr "" Link Here 
73
"<p>Die Informationen konnten nicht an Univention übertragen werden.</"
27
"<p>Die Informationen konnten nicht an Univention übertragen werden.</"
74
"p><p>Sie können die Information per E-Mail senden!</p>"
28
"p><p>Sie können die Information per E-Mail senden!</p>"
75
29
76
#: umc/js/sysinfo.js:189
30
#: umc/js/sysinfo.js:136
77
msgid ""
31
msgid ""
78
"<p>The information were transfered to Univention successfully.</p><p>Thank "
32
"<p>The information were transfered to Univention successfully.</p><p>Thank "
79
"you very much for your support!</p>"
33
"you very much for your support!</p>"
 Lines 81-91   msgstr "" Link Here 
81
"<p>Die Informationen wurden erfolgreich an Univention übertragen.</"
35
"<p>Die Informationen wurden erfolgreich an Univention übertragen.</"
82
"p><p>Vielen Dank für Ihre Unterstützung!</p>"
36
"p><p>Vielen Dank für Ihre Unterstützung!</p>"
83
37
84
#: umc/js/sysinfo.js:61
38
#: umc/js/sysinfo.js:64
39
#, fuzzy
85
msgid ""
40
msgid ""
86
"<p>This module collects information about the hardware of your system. This "
41
"<p>This module collects information about the configuration of your system. "
87
"might be helpful in connection with a support case. By transmitting the data "
42
"This might be helpful in connection with a support case. By transmitting the "
88
"to Univention you provide the information on which platforms UCS is "
43
"data to Univention you provide the information on which platforms UCS is "
89
"currently used and therefore should be supported by newer versions. In the "
44
"currently used and therefore should be supported by newer versions. In the "
90
"following procedure you will be informed in detail about the each step.</"
45
"following procedure you will be informed in detail about the each step.</"
91
"p><p>No information is transmitted without your acceptance</p>"
46
"p><p>No information is transmitted without your acceptance</p>"
 Lines 98-144   msgstr "" Link Here 
98
"genau informiert.</p><p>Es werden keine Informationen ohne Ihre Einwilligung "
53
"genau informiert.</p><p>Es werden keine Informationen ohne Ihre Einwilligung "
99
"an Univention übermittelt</p>"
54
"an Univention übermittelt</p>"
100
55
101
#: umc/js/sysinfo.js:148 umc/js/sysinfo.js:203 umc/js/sysinfo.js:322
56
#: umc/js/sysinfo.js:106
57
#, fuzzy
58
msgid ""
59
"<p>Which information do you want to send to the Univention support. Please "
60
"select the corresponding option.</p>"
61
msgstr ""
62
"<p>Die ermittelten Informationen können entweder hochgeladen oder per Mail "
63
"an Univention geschickt werden. Bitte wählen Sie die gewünschte Variante.</p>"
64
65
#: umc/js/sysinfo.js:263 umc/js/sysinfo.js:334
102
msgid "Archive with system information"
66
msgid "Archive with system information"
103
msgstr "Archiv mit den Systeminformationen"
67
msgstr "Archiv mit den Systeminformationen"
104
68
105
#: umc/js/sysinfo.js:119
69
#: umc/js/sysinfo.js:78
106
msgid "CPU"
70
msgid "Contact support with existing ticket number"
107
msgstr "CPU"
71
msgstr ""
108
109
#: umc/js/sysinfo.js:110
110
msgid "Collected data"
111
msgstr "Ermittelte Daten"
112
72
113
#: umc/js/sysinfo.js:73
73
#: umc/js/sysinfo.js:296
114
msgid "Comment"
74
msgid "Downloading newest Version of Univention-System-Information"
115
msgstr "Kommentar"
75
msgstr ""
116
76
117
#: umc/js/sysinfo.js:60
77
#: umc/js/sysinfo.js:85
118
msgid "General information"
78
msgid "E-Mail"
119
msgstr "Allgemeine Informationen"
79
msgstr ""
120
80
121
#: umc/js/sysinfo.js:140
81
#: umc/js/sysinfo.js:68
122
msgid "Graphics card"
82
msgid "Error description"
123
msgstr "Grafikkarte"
83
msgstr ""
124
84
125
#: umc/js/sysinfo.js:81
85
#: umc/js/sysinfo.js:326
126
msgid ""
86
msgid "Executing USI"
127
"If this is related to a support case the next step will be to enter the "
128
"ticket number. Otherwise the information about your system will be collected "
129
"and a summary is shown."
130
msgstr ""
87
msgstr ""
131
"Wenn sich dies auf einen Supportfall bezieht, wird im nächsten Schritt die "
132
"Ticketnummer abgefragt. Anderenfalls werden die Informationen zu Ihrem "
133
"System ermittelt und eine Zusammenfassung angezeigt."
134
88
135
#: umc/js/sysinfo.js:152
89
#: umc/js/sysinfo.js:243
136
msgid ""
90
#, fuzzy
137
"In the following step two possibilities to transmit the information to "
91
msgid "Gathering Hardware informations"
138
"Univention will be described."
92
msgstr "Allgemeine Informationen"
93
94
#: umc/js/sysinfo.js:257
95
#, fuzzy
96
msgid "Gathering System informations"
97
msgstr "Archiv mit den Systeminformationen"
98
99
#: umc/js/sysinfo.js:111
100
msgid "General system information including logfiles, config files, etc."
139
msgstr ""
101
msgstr ""
140
"Im folgenden Schritt werden Ihnen zwei Möglichkeiten geboten, die "
141
"Informationen an Univention zu übermitteln."
142
102
143
#: umc/js/sysinfo/lib.js:47
103
#: umc/js/sysinfo/lib.js:47
144
msgid ""
104
msgid ""
 Lines 148-182   msgstr "" Link Here 
148
"Informationen zu diesem Fehler werden, zusammen mit Angaben über das "
108
"Informationen zu diesem Fehler werden, zusammen mit Angaben über das "
149
"Betriebssystem, an den Hersteller übermittelt."
109
"Betriebssystem, an den Hersteller übermittelt."
150
110
151
#: umc/js/sysinfo.js:65
111
#: umc/js/sysinfo.js:118
152
msgid "Manufacturer"
112
msgid "Information about the system's hardware"
153
msgstr "Hersteller"
113
msgstr ""
154
155
#: umc/js/sysinfo.js:130
156
msgid "Memory"
157
msgstr "Arbeitsspeicher"
158
159
#: umc/js/sysinfo.js:174
160
msgid "Method"
161
msgstr "Methode"
162
163
#: umc/js/sysinfo.js:69
164
msgid "Model"
165
msgstr "Modell"
166
167
#: umc/js/sysinfo.js:135
168
msgid "Network adapter"
169
msgstr "Netzwerkkarte"
170
114
171
#: umc/js/sysinfo.js:125
115
#: umc/js/sysinfo.js:243 umc/js/sysinfo.js:257 umc/js/sysinfo.js:267
172
msgid "Number of CPUs"
116
#: umc/js/sysinfo.js:296 umc/js/sysinfo.js:321 umc/js/sysinfo.js:326
173
msgstr "Anzahl der CPUs"
117
#: umc/js/sysinfo.js:338
118
msgid "Processing"
119
msgstr ""
174
120
175
#: umc/js/sysinfo/lib.js:59
121
#: umc/js/sysinfo/lib.js:59
176
msgid "Remarks (e.g. steps to reproduce) (optional)"
122
msgid "Remarks (e.g. steps to reproduce) (optional)"
177
msgstr "Bemerkungen (z.B. Schritte, den Fehler nachzustellen) (optional)"
123
msgstr "Bemerkungen (z.B. Schritte, den Fehler nachzustellen) (optional)"
178
124
179
#: umc/js/sysinfo.js:177 umc/js/sysinfo.js:339
125
#: umc/js/sysinfo.js:101
126
#, fuzzy
127
msgid "Select information"
128
msgstr "Support Informationen"
129
130
#: umc/js/sysinfo.js:287
180
msgid "Send mail"
131
msgid "Send mail"
181
msgstr "Mail senden"
132
msgstr "Mail senden"
182
133
 Lines 192-221   msgstr "Das Versenden der Informationen zum Hersteller ist fehlgeschlagen" Link Here 
192
msgid "Show error message"
143
msgid "Show error message"
193
msgstr "Fehlermeldung anzeigen"
144
msgstr "Fehlermeldung anzeigen"
194
145
195
#: umc/js/sysinfo.js:89
146
#: umc/js/sysinfo.js:321
196
msgid "Support information"
147
msgid "Starting USI process"
197
msgstr "Support Informationen"
148
msgstr ""
198
149
199
#: umc/js/sysinfo/lib.js:69
150
#: umc/js/sysinfo/lib.js:69
200
msgid "Thank you for your help"
151
msgid "Thank you for your help"
201
msgstr "Vielen Dank für Ihre Hilfe"
152
msgstr "Vielen Dank für Ihre Hilfe"
202
153
203
#: umc/js/sysinfo.js:77
154
#: umc/js/sysinfo.js:72
204
msgid "This is related to a support case"
205
msgstr "Dies bezieht sich auf einen Supportfall"
206
207
#: umc/js/sysinfo.js:98
208
msgid "Ticket"
155
msgid "Ticket"
209
msgstr "Ticket"
156
msgstr "Ticket"
210
157
211
#: umc/js/sysinfo.js:199
158
#: umc/js/sysinfo.js:239
159
#, fuzzy
212
msgid ""
160
msgid ""
213
"To transfer the information via mail please follow these steps:"
161
"To transfer the information via mail please follow these steps:"
214
"<ol><li>Download the archive with the collected information and save it on "
162
"<ol><li>Download the archive with the collected information and save it on "
215
"your local system</li><li>Click on link <i>Send mail</i> to open your mail "
163
"your local system</li><li>Click on li    nk <i>Send mail</i> to open your "
216
"program</li><li>Attach the downloaded archive to the mail and send it to "
164
"mail program</li><li>Attach the downloaded archive to the mail and send it "
217
"Univention</li><li>End this assistant by clicking on the button <i>Finish</"
165
"to Univention</li><li>End this assistant by clicking on the button "
218
"i></li></ol>"
166
"<i>Finish</i></li></ol>"
219
msgstr ""
167
msgstr ""
220
"Für das Versenden der Informationen per Mail gehen Sie bitte wie folgt vor:"
168
"Für das Versenden der Informationen per Mail gehen Sie bitte wie folgt vor:"
221
"<ol><li>Laden Sie die Datei mit den Informationen herunter und speichern "
169
"<ol><li>Laden Sie die Datei mit den Informationen herunter und speichern "
 Lines 225-250   msgstr "" Link Here 
225
"diese.</li><li>Beenden Sie diesen Assistenten durch Klicken auf die "
173
"diese.</li><li>Beenden Sie diesen Assistenten durch Klicken auf die "
226
"Schaltfläche <i>Fertigstellen</i></li></ol>"
174
"Schaltfläche <i>Fertigstellen</i></li></ol>"
227
175
228
#: umc/js/sysinfo.js:164
176
#: umc/js/sysinfo.js:131
229
msgid "Transfer the information"
230
msgstr "Übertragung der Informationen"
231
232
#: umc/js/sysinfo.js:194
233
msgid "Transfer via mail"
234
msgstr "Übertragung via Mail"
235
236
#: umc/js/sysinfo.js:184
237
msgid "Transfered successfully"
177
msgid "Transfered successfully"
238
msgstr "Übertragung erfolgreich"
178
msgstr "Übertragung erfolgreich"
239
179
240
#: umc/js/sysinfo.js:176
180
#: umc/js/sysinfo.js:63
241
msgid "Upload"
181
#, fuzzy
242
msgstr "Hochladen"
182
msgid "Univention-system-information"
183
msgstr "Archiv mit den Systeminformationen"
243
184
244
#: umc/js/sysinfo.js:264
185
#: umc/js/sysinfo.js:236
245
msgid "Uploading failed"
186
msgid "Uploading failed"
246
msgstr "Hochladen fehlgeschlagen"
187
msgstr "Hochladen fehlgeschlagen"
247
188
189
#: umc/js/sysinfo.js:267 umc/js/sysinfo.js:338
190
#, fuzzy
191
msgid "Uploading informations"
192
msgstr "Hochladen fehlgeschlagen"
193
248
#: umc/js/sysinfo/lib.js:74
194
#: umc/js/sysinfo/lib.js:74
249
msgid "You can also send the information via mail:"
195
msgid "You can also send the information via mail:"
250
msgstr "Sie können die Informationen auch per Mail schicken:"
196
msgstr "Sie können die Informationen auch per Mail schicken:"
 Lines 252-254   msgstr "Sie können die Informationen auch per Mail schicken:" Link Here 
252
#: umc/js/sysinfo/lib.js:63
198
#: umc/js/sysinfo/lib.js:63
253
msgid "Your email address (optional)"
199
msgid "Your email address (optional)"
254
msgstr "Ihre E-Mail Adresse (optional)"
200
msgstr "Ihre E-Mail Adresse (optional)"
201
202
#: umc/js/sysinfo.js:90
203
msgid "phone number"
204
msgstr ""
205
206
#~ msgid ""
207
#~ "<p>Additionally to the information listed above some more details about "
208
#~ "the system has been collected. The whole set of collected data that will "
209
#~ "be transmitted to Univention can be downloaded at the following URL:</p>"
210
#~ msgstr ""
211
#~ "<p>Zusätzlich zu den oben angezeigten Informationen wurden weitere "
212
#~ "Details über das System ermittelt. Die gesamten Informationen, die an "
213
#~ "Univention übertragen werden sollen, können unter der folgenden URL "
214
#~ "heruntergeladen werden:</p>"
215
216
#~ msgid ""
217
#~ "<p>If a Univention Support Engineer has asked you to provide this "
218
#~ "information, then please insert the ticket number of the related support "
219
#~ "ticket into the following text field. The ticket number can be found in "
220
#~ "the subject of a support mail of the ticket. This information will speed "
221
#~ "up the processing of the ticket.</p>"
222
#~ msgstr ""
223
#~ "<p>Wenn Sie durch den Univention-Support gebeten worden sind, diese "
224
#~ "Informationen zu ermitteln, dann geben Sie bitte im folgenden Feld die "
225
#~ "Ticketnummer an, welche sich dem Betreff der Support-Mails entnehmen "
226
#~ "lässt. Die Ticketnummer hilft bei der Zuordnung zu dem Supportfall und "
227
#~ "beschleunigt die Bearbeitung.</p>"
228
229
#~ msgid ""
230
#~ "<p>In the next step the information about the hardware of your system "
231
#~ "will be collected and a summary will be shown. During this step, no "
232
#~ "information will be sent to Univention.</p>"
233
#~ msgstr ""
234
#~ "<p>Im nächsten Schritt werden die Informationen des Systems ermittelt "
235
#~ "sowie eine Zusammenfassung darüber angezeigt. Während dieses Vorganges "
236
#~ "werden keine Informationen an Univention übertragen.</p>"
237
238
#~ msgid ""
239
#~ "<p>The following information has been collected and will be transfered to "
240
#~ "Univention with your acceptance.</p>"
241
#~ msgstr ""
242
#~ "<p>Die folgenden Informationen wurden ermittelt und werden mit Ihrer "
243
#~ "Zustimmung an Univention übertragen:</p>"
244
245
#~ msgid "CPU"
246
#~ msgstr "CPU"
247
248
#~ msgid "Collected data"
249
#~ msgstr "Ermittelte Daten"
250
251
#~ msgid "Comment"
252
#~ msgstr "Kommentar"
253
254
#~ msgid "Graphics card"
255
#~ msgstr "Grafikkarte"
256
257
#~ msgid ""
258
#~ "If this is related to a support case the next step will be to enter the "
259
#~ "ticket number. Otherwise the information about your system will be "
260
#~ "collected and a summary is shown."
261
#~ msgstr ""
262
#~ "Wenn sich dies auf einen Supportfall bezieht, wird im nächsten Schritt "
263
#~ "die Ticketnummer abgefragt. Anderenfalls werden die Informationen zu "
264
#~ "Ihrem System ermittelt und eine Zusammenfassung angezeigt."
265
266
#~ msgid ""
267
#~ "In the following step two possibilities to transmit the information to "
268
#~ "Univention will be described."
269
#~ msgstr ""
270
#~ "Im folgenden Schritt werden Ihnen zwei Möglichkeiten geboten, die "
271
#~ "Informationen an Univention zu übermitteln."
272
273
#~ msgid "Manufacturer"
274
#~ msgstr "Hersteller"
275
276
#~ msgid "Memory"
277
#~ msgstr "Arbeitsspeicher"
278
279
#~ msgid "Method"
280
#~ msgstr "Methode"
281
282
#~ msgid "Model"
283
#~ msgstr "Modell"
284
285
#~ msgid "Network adapter"
286
#~ msgstr "Netzwerkkarte"
287
288
#~ msgid "Number of CPUs"
289
#~ msgstr "Anzahl der CPUs"
290
291
#~ msgid "This is related to a support case"
292
#~ msgstr "Dies bezieht sich auf einen Supportfall"
293
294
#~ msgid "Transfer the information"
295
#~ msgstr "Übertragung der Informationen"
296
297
#~ msgid "Transfer via mail"
298
#~ msgstr "Übertragung via Mail"
299
300
#~ msgid "Upload"
301
#~ msgstr "Hochladen"
(-)a/management/univention-system-info/umc/js/sysinfo.js (-177 / +184 lines)
 Lines 15-21    Link Here 
15
 * cryptographic keys etc. are subject to a license agreement between
15
 * cryptographic keys etc. are subject to a license agreement between
16
 * you and Univention and not subject to the GNU AGPL V3.
16
 * you and Univention and not subject to the GNU AGPL V3.
17
 *
17
 *
18
 * In the case you use this program under the terms of the GNU AGPL V3,
18
 * In thGe case you use this program under the terms of the GNU AGPL V3,
19
 * the program is provided in the hope that it will be useful,
19
 * the program is provided in the hope that it will be useful,
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 Lines 42-50   define([ Link Here 
42
	"umc/widgets/Text",
42
	"umc/widgets/Text",
43
	"umc/widgets/TextArea",
43
	"umc/widgets/TextArea",
44
	"umc/widgets/CheckBox",
44
	"umc/widgets/CheckBox",
45
	"umc/widgets/RadioButton",
46
	"umc/widgets/ProgressBar",
45
	"umc/i18n!umc/modules/sysinfo",
47
	"umc/i18n!umc/modules/sysinfo",
46
	"umc/modules/sysinfo/lib" // FIXME: needs to live here to be loaded
48
	"umc/modules/sysinfo/lib" // FIXME: needs to live here to be loaded
47
], function(declare, lang, array, topic, tools, Module, Wizard, StandbyMixin, ComboBox, TextBox, Text, TextArea, CheckBox, _) {
49
], function(declare, lang, array, topic, tools, Module, Wizard, StandbyMixin, ComboBox, TextBox, Text, TextArea, CheckBox, RadioButton, ProgressBar, _) {
48
50
49
	var SysinfoWizard = declare("umc.modules.sysinfo.Wizard", [ Wizard, StandbyMixin ], {
51
	var SysinfoWizard = declare("umc.modules.sysinfo.Wizard", [ Wizard, StandbyMixin ], {
50
52
 Lines 53-184   define([ Link Here 
53
		_archiveFilename: null,
55
		_archiveFilename: null,
54
		_archiveLink: null,
56
		_archiveLink: null,
55
		_mailLink: null,
57
		_mailLink: null,
58
		_ticketNumberUsed: false,
56
59
57
		constructor: function() {
60
		constructor: function() {
58
			this.pages = [{
61
			this.pages = [{
59
				name: 'general',
62
				name: 'general',
60
				headerText: _('General information'),
63
				headerText: _('Univention-system-information'),
61
				helpText: _('<p>This module collects information about the hardware of your system. This might be helpful in connection with a support case. By transmitting the data to Univention you provide the information on which platforms UCS is currently used and therefore should be supported by newer versions. In the following procedure you will be informed in detail about the each step.</p><p>No information is transmitted without your acceptance</p>'),
64
				helpText: _('<p>This module collects information about the configuration of your system. This might be helpful in connection with a support case. By transmitting the data to Univention you provide the information on which platforms UCS is currently used and therefore should be supported by newer versions. In the following procedure you will be informed in detail about the each step.</p><p>No information is transmitted without your acceptance</p>'),
62
				widgets: [{
65
				widgets: [{
63
					type: TextBox,
64
					name: 'manufacturer',
65
					label: _('Manufacturer')
66
				}, {
67
					type: TextBox,
68
					name: 'model',
69
					label: _('Model')
70
				}, {
71
					type: TextArea,
66
					type: TextArea,
72
					name: 'comment',
67
					name: 'comment',
73
					label: _('Comment')
68
					label: _('Error description')
69
				}, {
70
					type: TextBox,
71
					name: 'ticketNumber',
72
					label: _('Ticket'),
73
					value: '',
74
					visible: this._ticketNumberUsed
74
				}, {
75
				}, {
75
					type: CheckBox,
76
					type: CheckBox,
76
					name: 'supportBox',
77
					name: 'supportBox',
77
					label: _('This is related to a support case')
78
					label: _('Contact support with existing ticket number'),
79
					onChange: lang.hitch(this, function(value) {
80
						this._toggleTicketNumberUsed();
81
					})
78
				}, {
82
				}, {
79
					type: Text,
83
					type: TextBox,
80
					name: 'secondText',
84
					name: 'emailBox',
81
					label: _('If this is related to a support case the next step will be to enter the ticket number. Otherwise the information about your system will be collected and a summary is shown.')
85
					label: _('E-Mail'),
82
				}],
86
					required: true
83
				layout: [['manufacturer', 'model'],
84
					 	 ['comment'],
85
					 	 ['supportBox'],
86
					 	 ['secondText']]
87
			}, {
88
				name: 'support',
89
				headerText: _('Support information'),
90
				helpText: '',
91
				widgets: [{
92
					type: Text,
93
					name: 'firstText',
94
					content: _('<p>If a Univention Support Engineer has asked you to provide this information, then please insert the ticket number of the related support ticket into the following text field. The ticket number can be found in the subject of a support mail of the ticket. This information will speed up the processing of the ticket.</p>')
95
				}, {
87
				}, {
96
					type: TextBox,
88
					type: TextBox,
97
					name: 'ticket',
89
					name: 'phoneBox',
98
					label: _('Ticket'),
90
					label: _('phone number')
99
					value: ''
100
				}, {
91
				}, {
101
					type: Text,
102
					name: 'secondText',
103
					content: _('<p>In the next step the information about the hardware of your system will be collected and a summary will be shown. During this step, no information will be sent to Univention.</p>')
104
				}],
92
				}],
105
				layout: [['firstText'],
93
				layout: [,
106
					 	 ['ticket'],
94
						 ['supportBox'],
107
					 	 ['secondText']]
95
						 ['ticketNumber'],
96
						 ['comment'],
97
						 ['emailBox'],
98
						 ['phoneBox']]
108
			}, {
99
			}, {
109
				name: 'collect',
100
				name: 'chooseInfo',
110
				headerText: _('Collected data'),
101
				headerText: _('Select information'),
111
				helpText: '',
102
				helpText: _(''),
112
				widgets: [{
103
				widgets: [{
113
					type: Text,
104
					type: Text,
114
					name: 'firstText',
105
					name: 'firstText',
115
					content: _('<p>The following information has been collected and will be transfered to Univention with your acceptance.</p>')
106
					content: _('<p>Which information do you want to send to the Univention support. Please select the corresponding option.</p>')
116
				}, {
117
					type: TextBox,
118
					name: 'cpu',
119
					label: _('CPU'),
120
					value: ''
121
				}, {
122
					type: TextBox,
123
					name: 'num_cpu',
124
					sizeClass: 'OneThird',
125
					label: _('Number of CPUs'),
126
					value: ''
127
				}, {
107
				}, {
128
					type: TextBox,
108
					type: RadioButton,
129
					name: 'mem',
109
					name: 'usi',
130
					label: _('Memory'),
110
					value: 'usi',
131
					value: ''
111
					label: _('General system information including logfiles, config files, etc.'),
112
					radioButtonGroup: 'infoChoice',
113
					checked: true
132
				}, {
114
				}, {
133
					type: TextBox,
115
					type: RadioButton,
134
					name: 'net_dev',
116
					name: 'hardware',
135
					label: _('Network adapter'),
117
					value: 'hardware',
136
					value: ''
118
					label: _("Information about the system's hardware"),
137
				}, {
119
					radioButtonGroup: 'infoChoice'
138
					type: TextBox,
139
					name: 'gfx_dev',
140
					label: _('Graphics card')
141
				}, {
120
				}, {
142
					type: Text,
121
					type: Text,
143
					name: 'secondText',
122
					name: 'secondText',
144
					content: _('<p>Additionally to the information listed above some more details about the system has been collected. The whole set of collected data that will be transmitted to Univention can be downloaded at the following URL:</p>')
123
					content: _('<p>After clicking "Next" the information will be gathered and uploaded to Univention.</p>')
145
				}, {
146
					type: Text,
147
					name: 'download',
148
					content: _('Archive with system information')
149
				}, {
150
					type: Text,
151
					name: 'thirdText',
152
					content: _('In the following step two possibilities to transmit the information to Univention will be described.')
153
				}],
124
				}],
154
				layout: [['firstText'],
125
				layout: [['firstText'],
155
					 	 ['cpu', 'num_cpu'],
126
					 	 ['usi'],
156
					 	 ['mem'],
127
						 ['hardware'],
157
					 	 ['net_dev'],
128
						 ['secondText']]
158
					 	 ['gfx_dev'],
159
					 	 ['secondText'],
160
					 	 ['download'],
161
					 	 ['thirdText']]
162
			}, {
163
				name: 'transfer',
164
				headerText: _('Transfer the information'),
165
				helpText: _(''),
166
				widgets: [{
167
					type: Text,
168
					name: 'firstText',
169
					content: _('<p>The collected information can be transfered to Univention by uploading the data or by sending it via mail. Please select the corresponding option.</p>')
170
				}, {
171
					type: ComboBox,
172
					name: 'method',
173
					value: 'upload',
174
					label: _('Method'),
175
					staticValues: [
176
						{id: 'upload', label: _('Upload')},
177
						{id: 'mail', label: _('Send mail')}
178
					]
179
				}],
180
				layout: [['firstText'],
181
					 	 ['method']]
182
			}, {
129
			}, {
183
				name: 'uploaded',
130
				name: 'uploaded',
184
				headerText: _('Transfered successfully'),
131
				headerText: _('Transfered successfully'),
 Lines 187-227   define([ Link Here 
187
					type: Text,
134
					type: Text,
188
					name: 'firstText',
135
					name: 'firstText',
189
					content: _('<p>The information were transfered to Univention successfully.</p><p>Thank you very much for your support!</p>')
136
					content: _('<p>The information were transfered to Univention successfully.</p><p>Thank you very much for your support!</p>')
190
				}],
191
				layout: [['firstText']]
192
			}, {
193
				name: 'mail',
194
				headerText: _('Transfer via mail'),
195
				helpText: '',
196
				widgets: [{
197
					type: Text,
198
					name: 'firstText',
199
					content: _('To transfer the information via mail please follow these steps:<ol><li>Download the archive with the collected information and save it on your local system</li><li>Click on link <i>Send mail</i> to open your mail program</li><li>Attach the downloaded archive to the mail and send it to Univention</li><li>End this assistant by clicking on the button <i>Finish</i></li></ol>')
200
				}, {
137
				}, {
201
					type: Text,
138
					type: Text,
202
					name: 'download',
139
					name: 'secondText',
203
					content: _('Archive with system information')
140
					content: this._archiveLink
204
				}, {
141
				},{
205
					type: Text,
142
					type: Text,
206
					name: 'mail',
143
					name: 'thirdText',
207
					content: 'Send Mail'
144
					content: ''
208
				}],
145
				}],
209
				layout: [['firstText'],
146
				layout: [['firstText'],
210
					 	 ['download'],
147
						 ['secondText']
211
					 	 ['mail']]
148
						 ['thirdText']]
212
			}];
149
			}];
213
		},
150
		},
214
151
215
		buildRendering: function() {
152
		buildRendering: function() {
216
			this.inherited(arguments);
153
			this.inherited(arguments);
217
			this._disableWidgets();
154
			this._progressBar = new ProgressBar();
218
		},
155
		},
219
156
		// toggle function for setting either ticket no or email as reuired
220
		_disableWidgets: function() {
157
		// so we always have contact informations
221
			var widgets = ['cpu', 'num_cpu', 'mem', 'net_dev', 'gfx_dev'];
158
		_toggleTicketNumberUsed: function(otherWidget, sourceWidget) {
222
			array.forEach(widgets, lang.hitch(this, function(iwidget) {
159
			this._ticketNumberUsed = this.getWidget('general', 'supportBox').get('value');
223
				this.getWidget('collect', iwidget).set('disabled', true);
160
			this.getWidget('general', 'ticketNumber').set('visible', this._ticketNumberUsed);
224
			}));
161
			this.getWidget('general', 'ticketNumber').set('required', this._ticketNumberUsed);
162
			this.getWidget('general', 'emailBox').set('required', !this._ticketNumberUsed);
225
		},
163
		},
226
164
227
		canCancel: function(pageName) {
165
		canCancel: function(pageName) {
 Lines 242-277   define([ Link Here 
242
180
243
		next: function() {
181
		next: function() {
244
			var nextPage = this.inherited(arguments);
182
			var nextPage = this.inherited(arguments);
245
			if (nextPage == 'general') {
183
			if (nextPage == 'chooseInfo') {
246
				this.getGeneralInfo();
184
				// TODO validate if a mail address OR a ticket number are specified
247
			}
185
				var mailWidget = this.getWidget('general', 'emailBox')
248
			if (nextPage == 'support') {
186
				var ticketNrWidget = this.getWidget('general', 'ticketNumber')
187
				// don't go to next page if a required field is empty
249
				if (this.getWidget('general', 'supportBox').get('value') === false) {
188
				if (this.getWidget('general', 'supportBox').get('value') === false) {
250
					nextPage = 'collect';
189
					if (!mailWidget.get('value')) {
190
						this._triggerValidationMessage(mailWidget);
191
						return 'general';
192
					}
193
				}else{
194
					if (!ticketNrWidget.get('value')) {
195
						this._triggerValidationMessage(ticketNrWidget);
196
						return 'general';
197
					}
251
				}
198
				}
252
			}
199
			}
253
			if (nextPage == 'collect') {
254
				this.getSystemInfo();
255
			}
256
			if (nextPage == 'uploaded') {
200
			if (nextPage == 'uploaded') {
257
				if (this.getWidget('transfer', 'method') == 'mail') {
201
				var doUSI = this.getWidget('chooseInfo', 'usi').get('checked');
258
					nextPage = 'mail';
202
				if (doUSI == true) {
259
				} else {
203
					this.usiProcess();
260
					return this.uploadArchive().then(function() {
204
				}else{
261
						return nextPage;
205
					this.getSystemInfo();
262
					}, lang.hitch(this, function() {
263
						this.getPage('uploaded').set('headerText', _('Uploading failed'));
264
						this.getWidget('uploaded', 'firstText').set('content', _('<p>The information could not be transfered to Univention.</p><p>You can send them as email!</p>'));
265
						return nextPage;
266
					}));
267
				}
206
				}
268
			}
207
			}
269
			if (nextPage == 'mail') {
270
				this.getMailInfo();
271
			}
272
			return nextPage;
208
			return nextPage;
273
		},
209
		},
274
210
211
		gerValidationMessage: function(widget) {
212
			// manual trigger for the "required filed" functionality
213
			widget._hasBeenBlurred = true;
214
			widget.validate();
215
		},
216
275
		hasPrevious: function(pageName) {
217
		hasPrevious: function(pageName) {
276
			if (pageName == 'uploaded') {
218
			if (pageName == 'uploaded') {
277
				return false;
219
				return false;
 Lines 287-331   define([ Link Here 
287
					return 'general';
229
					return 'general';
288
				}
230
				}
289
			}
231
			}
290
			if (previousPage == 'uploaded') {
291
				if (this.getWidget('transfer', 'method') == 'mail') {
292
					return 'transfer';
293
				}
294
			}
295
			return previousPage;
232
			return previousPage;
296
		},
233
		},
297
234
298
		getGeneralInfo: function() {
235
		setUploadFailedCaptions: function() {
299
			this.standbyDuring(tools.umcpCommand('sysinfo/general')).then(
236
			this.getPage('uploaded').set('headerText', _('Uploading failed'));
300
				lang.hitch(this, function(data) {
237
			this.getWidget('uploaded', 'firstText').set('content', _('<p>The information could not be transfered to Univention.</p><p>You can send them as email!</p>'));
301
					var generalPage = this.getPage('general');
238
302
					generalPage._form.setFormValues(data.result);
239
			this.getWidget('uploaded', 'thirdText').set('content', _('To transfer the information via mail please follow these steps:<ol><li>Download the archive with the collected information and save it on your local system</li><li>Click on li    nk <i>Send mail</i> to open your mail program</li><li>Attach the downloaded archive to the mail and send it to Univention</li><li>End this assistant by clicking on the button <i>Finish</i></li></ol>'));
303
				})
304
			);
305
		},
240
		},
306
241
307
		getSystemInfo: function() {
242
		getSystemInfo: function() {
308
			var generalValues =  this.getPage('general')._form.get('value');
243
			this._progressBar.setInfo(_('Processing'), _('Gathering Hardware informations'), 10);
309
			var supportValues =  this.getPage('support')._form.get('value');
244
			this.standby(true, this._progressBar);
310
			var requestValues = {
245
			tools.umcpCommand('sysinfo/general').then(
311
				'manufacturer': generalValues.manufacturer,
312
				'model': generalValues.model,
313
				'comment': generalValues.comment,
314
				'ticket': supportValues.ticket
315
			};
316
			this.standbyDuring(tools.umcpCommand('sysinfo/system', requestValues)).then(
317
				lang.hitch(this, function(data) {
246
				lang.hitch(this, function(data) {
318
					this._archiveFilename = data.result.archive;
247
					var generalValues = data.result;
319
					this._archiveLink = lang.replace('<a href="{url}">{text}</a>', {
248
					var ticketNumber = this.getWidget('general', 'ticketNumber').get('value');
320
						'url': '/univention-management-console/system-info/' + this._archiveFilename,
249
					var comment = this.getWidget('general', 'comment').get('value');
321
						'text': _('Archive with system information')
250
					var requestValues = {
322
					});
251
						'manufacturer': generalValues.manufacturer,
252
						'model': generalValues.model,
253
						'comment': comment,
254
						'ticket': ticketNumber
255
					};
323
256
324
					var collectPage = this.getPage('collect');
257
					this._progressBar.setInfo(_('Processing'), _('Gathering System informations'), 40);
325
					collectPage._form.setFormValues(data.result);
258
					tools.umcpCommand('sysinfo/system', requestValues).then(
326
					this.getWidget('collect', 'download').set('content', this._archiveLink);
259
						lang.hitch(this, function(data) {
260
							this._archiveFilename = data.result.archive;
261
							this._archiveLink = lang.replace('<a href="{url}">{text}</a>', {
262
								'url': '/univention-management-console/system-info/' + this._archiveFilename,
263
								'text': _('Archive with system information')
264
							});
327
265
328
					this.getWidget('mail', 'download').set('content', this._archiveLink);
266
							this.getWidget('uploaded', 'secondText').set('content', this._archiveLink);
267
							this._progressBar.setInfo(_('Processing'), _('Uploading informations'), 70);
268
							this.uploadArchive().then(lang.hitch(this, function(){
269
								// upload successful
270
								this.standby(false);
271
							}), lang.hitch(this, function(){
272
								// upload failed
273
								this.setUploadFailedCaptions();
274
								this.standby(false);
275
							}));
276
						})
277
					);
329
				})
278
				})
330
			);
279
			);
331
		},
280
		},
 Lines 343-348   define([ Link Here 
343
			);
292
			);
344
		},
293
		},
345
294
295
		downloadUSI: function() {
296
			this._progressBar.setInfo(_('Processing'), _('Downloading newest Version of Univention-System-Information'), 20);
297
			return tools.umcpCommand('sysinfo/download_usi');
298
		},
299
300
		executeUSI: function() {
301
			return tools.umcpCommand('sysinfo/general').then(
302
				lang.hitch(this, function(data) {
303
					var generalValues = data.result;
304
					var ticketNumber = this.getWidget('general', 'ticketNumber').get('value');
305
					var comment = this.getWidget('general', 'comment').get('value');
306
					var email = this.getWidget('general', 'emailBox').get('value');
307
					var requestValues = {
308
						'manufacturer': generalValues.manufacturer,
309
						'model': generalValues.model,
310
						'comment': comment,
311
						'ticket': ticketNumber,
312
						'email': email
313
					};
314
					return tools.umcpCommand('sysinfo/execute_usi', requestValues);
315
				})
316
			);
317
		},
318
319
		usiProcess: function() {
320
321
			this._progressBar.setInfo(_('Processing'), _('Starting USI process'), 10);
322
			this.standby(true, this._progressBar);
323
324
			this.downloadUSI().then(
325
				lang.hitch(this, function() {
326
					this._progressBar.setInfo(_('Processing'), _('Executing USI'), 40);
327
					this.executeUSI().then(
328
						lang.hitch(this, function(data) {
329
							this._archiveFilename = data.result;
330
							var name = data.result.replace('/var/www/univention-management-console/system-info/','');
331
							// create Link on uploaded page so user can easily downlad the created archive
332
							this._archiveLink = lang.replace('<a href="{url}">{text}</a>', {
333
								'url': '/univention-management-console/system-info/' + name,
334
								'text': _('Archive with system information')
335
							});
336
							// implement link ind uploaded page
337
							this.getWidget('uploaded', 'secondText').set('content', this._archiveLink);
338
							this._progressBar.setInfo(_('Processing'),_('Uploading informations'), 70);
339
							this.uploadArchive().then(lang.hitch(this, function() {
340
								// upload successful
341
								this.standby(false);
342
							}), lang.hitch(this, function() {
343
								// upload failed
344
								this.setUploadFailedCaptions()
345
								this.standby(false);
346
							}));
347
						})
348
					);
349
				})
350
			);
351
		},
352
346
		uploadArchive: function() {
353
		uploadArchive: function() {
347
			var values = {'archive': this._archiveFilename};
354
			var values = {'archive': this._archiveFilename};
348
			return this.standbyDuring(tools.umcpCommand('sysinfo/upload', values));
355
			return this.standbyDuring(tools.umcpCommand('sysinfo/upload', values));
(-)a/management/univention-system-info/umc/python/sysinfo/__init__.py (-32 / +193 lines)
 Lines 4-10    Link Here 
4
# Univention Management Console
4
# Univention Management Console
5
#  module: collecting system information
5
#  module: collecting system information
6
#
6
#
7
# Copyright 2011-2014 Univention GmbH
7
# Copyright 2011-2016 Univention GmbH
8
#
8
#
9
# http://www.univention.de/
9
# http://www.univention.de/
10
#
10
#
 Lines 57-62   ucr = univention.config_registry.ConfigRegistry() Link Here 
57
57
58
_ = umc.Translation('univention-management-console-module-sysinfo').translate
58
_ = umc.Translation('univention-management-console-module-sysinfo').translate
59
59
60
import stat
61
from shutil import copyfile
62
import tarfile
63
import tempfile
64
import bz2
65
import gzip
66
import pwd
67
import grp
68
import socket
69
import ssl
70
71
72
SYSINFO_PATH = '/var/www/univention-management-console/system-info/'
73
60
74
61
class Instance(umcm.Base):
75
class Instance(umcm.Base):
62
76
 Lines 74-79   class Instance(umcm.Base): Link Here 
74
			return (True, None, None, )
88
			return (True, None, None, )
75
89
76
	def get_general_info(self, request):
90
	def get_general_info(self, request):
91
		result = self.gather_general_info()
92
		if not result:
93
			message = _('Failed to execute command')
94
			request.status = MODULE_ERR
95
			self.finished(request.id, None, message)
96
			return
97
		request.status = SUCCESS
98
		self.finished(request.id, result)
99
100
	def gather_general_info(self):
77
		DMIDECODE = '/usr/sbin/dmidecode'
101
		DMIDECODE = '/usr/sbin/dmidecode'
78
		MANUFACTURER_CMD = (DMIDECODE, '-s', 'system-manufacturer', )
102
		MANUFACTURER_CMD = (DMIDECODE, '-s', 'system-manufacturer', )
79
		MODEL_CMD = (DMIDECODE, '-s', 'system-product-name', )
103
		MODEL_CMD = (DMIDECODE, '-s', 'system-product-name', )
 Lines 82-118   class Instance(umcm.Base): Link Here 
82
		for command in (MANUFACTURER_CMD, MODEL_CMD, ):
106
		for command in (MANUFACTURER_CMD, MODEL_CMD, ):
83
			(exitcode, stdout, stderr, ) = self._call(command)
107
			(exitcode, stdout, stderr, ) = self._call(command)
84
			if exitcode:
108
			if exitcode:
85
				message = _('Failed to execute command')
109
				return None
86
				request.status = MODULE_ERR
87
				self.finished(request.id, None, message)
88
				return
89
			else:
110
			else:
90
				stdout = stdout[:-1] # remove newline character
111
				stdout = stdout[:-1]  # remove newline character
91
				stdout_list.append(stdout)
112
				stdout_list.append(stdout)
92
		result = {}
113
		result = {}
93
		result['manufacturer'] = stdout_list[0]
114
		result['manufacturer'] = stdout_list[0]
94
		result['model'] = stdout_list[1]
115
		result['model'] = stdout_list[1]
95
116
		return result
96
		request.status = SUCCESS
97
		self.finished(request.id, result)
98
117
99
	def get_system_info(self, request):
118
	def get_system_info(self, request):
100
		MANUFACTURER = request.options['manufacturer'].encode( 'utf-8' )
119
		MANUFACTURER = request.options['manufacturer'].encode('utf-8')
101
		MODEL = request.options['model'].encode( 'utf-8' )
120
		MODEL = request.options['model'].encode('utf-8')
102
		COMMENT = request.options['comment'].encode( 'utf-8' )
121
		COMMENT = request.options['comment'].encode('utf-8')
103
		SYSTEM_INFO_CMD = ( '/usr/bin/univention-system-info',
122
		TICKET = request.options.get('ticket', '')
104
							'-m', MANUFACTURER,
123
		result = self.gather_system_info(MANUFACTURER, MODEL, COMMENT, TICKET)
105
							'-t', MODEL,
124
		if not result:
106
							'-c', COMMENT,
125
			request.status = MODULE_ERR
107
							'-s', request.options.get('ticket', ''),
126
		else:
108
							'-u', )
127
			request.status = SUCCESS
128
			self.finished(request.id, result)
129
130
	def gather_system_info(self, manufacturer, model, comment, ticket='', email=None):
131
		SYSTEM_INFO_CMD = ('/usr/bin/univention-system-info',
132
							'-m', manufacturer,
133
							'-t', model,
134
							'-c', comment,
135
							'-s', ticket,
136
							'-u',)
109
137
110
		(exitcode, stdout, stderr, ) = self._call(SYSTEM_INFO_CMD)
138
		(exitcode, stdout, stderr, ) = self._call(SYSTEM_INFO_CMD)
111
		if exitcode:
139
		if exitcode:
112
			MODULE.error('Execution of univention-system-info failed: %s'
140
			MODULE.error('Execution of univention-system-info failed: %s' % stdout)
113
			             % stdout)
114
			result = None
141
			result = None
115
			request.status = MODULE_ERR
116
		else:
142
		else:
117
			result = {}
143
			result = {}
118
			for line in stdout.splitlines():
144
			for line in stdout.splitlines():
 Lines 130-139   class Instance(umcm.Base): Link Here 
130
						result['mem'] = result['mem'].replace('.', ',')
156
						result['mem'] = result['mem'].replace('.', ',')
131
					except (IndexError, ValueError):
157
					except (IndexError, ValueError):
132
						pass
158
						pass
133
			result.pop('Temp', None) # remove unnecessary entry
159
			if email:
134
			request.status = SUCCESS
160
				result['email'] = email
135
161
			result.pop('Temp', None)  # remove unnecessary entry
136
		self.finished(request.id, result)
162
		return result
137
163
138
	@simple_response
164
	@simple_response
139
	def get_mail_info(self):
165
	def get_mail_info(self):
 Lines 149-158   class Instance(umcm.Base): Link Here 
149
	@sanitize(archive=StringSanitizer(required=True))
175
	@sanitize(archive=StringSanitizer(required=True))
150
	@simple_response
176
	@simple_response
151
	def upload_archive(self, archive):
177
	def upload_archive(self, archive):
178
		self._upload_archive(archive)
179
180
	def _upload_archive(self, archive):
152
		ucr.load()
181
		ucr.load()
153
		url = ucr.get('umc/sysinfo/upload/url', 'https://forge.univention.org/cgi-bin/system-info-upload.py')
182
		url = ucr.get('umc/sysinfo/upload/url', 'https://forge.univention.org/cgi-bin/system-info-upload.py')
154
183
155
		SYSINFO_PATH = '/var/www/univention-management-console/system-info/'
156
		path = os.path.abspath(os.path.join(SYSINFO_PATH, archive))
184
		path = os.path.abspath(os.path.join(SYSINFO_PATH, archive))
157
		if not path.startswith(SYSINFO_PATH):
185
		if not path.startswith(SYSINFO_PATH):
158
			raise UMC_Error('Archive path invalid.')
186
			raise UMC_Error('Archive path invalid.')
 Lines 173-189   class Instance(umcm.Base): Link Here 
173
	@simple_response
201
	@simple_response
174
	def upload_traceback(self, traceback, remark, email):
202
	def upload_traceback(self, traceback, remark, email):
175
		ucr.load()
203
		ucr.load()
176
		ucs_version = '{0}-{1} errata{2} ({3})'.format( ucr.get( 'version/version', '' ), ucr.get( 'version/patchlevel', '' ), ucr.get( 'version/erratalevel', '0' ), ucr.get( 'version/releasename', '' ) )
204
		ucs_version = '{0}-{1} errata{2} ({3})'.format(ucr.get('version/version', ''), ucr.get('version/patchlevel', ''), ucr.get('version/erratalevel', '0'), ucr.get('version/releasename', ''))
177
		# anonymised id of localhost
205
		# anonymised id of localhost
178
		uuid_system = ucr.get('uuid/system', '')
206
		uuid_system = ucr.get('uuid/system', '')
179
		url = ucr.get('umc/sysinfo/traceback/url', 'https://forge.univention.org/cgi-bin/system-info-traceback.py')
207
		url = ucr.get('umc/sysinfo/traceback/url', 'https://forge.univention.org/cgi-bin/system-info-traceback.py')
180
		MODULE.process('Sending %s to %s' % (traceback, url))
208
		MODULE.process('Sending %s to %s' % (traceback, url))
181
		request_data = {
209
		request_data = {
182
			'traceback' : traceback,
210
			'traceback': traceback,
183
			'remark' : remark,
211
			'remark': remark,
184
			'email' : email,
212
			'email': email,
185
			'ucs_version' : ucs_version,
213
			'ucs_version': ucs_version,
186
			'uuid_system' : uuid_system,
214
			'uuid_system': uuid_system,
187
		}
215
		}
188
		request = urllib2.Request(url, request_data)
216
		request = urllib2.Request(url, request_data)
189
		urllib2.urlopen(request)
217
		urllib2.urlopen(request)
218
219
	@simple_response
220
	def download_usi_script(self):
221
		self._download_usi_script()
222
223
	def _download_usi_script(self):
224
		# TODO error handling
225
		TMP_FOLDER = "/tmp"
226
		usi_file = "%s/usi.py" % (TMP_FOLDER,)
227
		url = "https://updates.software-univention.de/download/scripts/univention-support-info"
228
		usi_fallback = "/usr/share/pyshared/univention/management/console/modules/sysinfo/univention-system-information"
229
		try:
230
			# create custom https handler for a secure connection
231
			url_opener = urllib2.build_opener(HTTPSHandler)
232
			# set as default url opener
233
			urllib2.install_opener(url_opener)
234
			_usi = urllib2.urlopen(url)
235
			with open(usi_file, "wb") as _download_file:
236
				_download_file.write(_usi.read())
237
		except (urllib2.HTTPError, urllib2.URLError, httplib.HTTPException):
238
			# fallback to integrated usi in case the download fails
239
			copyfile(usi_fallback, usi_file)
240
		else:
241
			# make the script executable
242
			st = os.stat(usi_file)
243
			os.chmod(usi_file, st.st_mode | stat.S_IEXEC)
244
245
	@simple_response
246
	def execute_usi_script(self, manufacturer='', model='', comment='', ticket='', email=''):
247
		return self._execute_usi_script(manufacturer, model, comment, ticket, email)
248
249
	def _execute_usi_script(self, manufacturer='', model='', comment='', ticket='', email=''):
250
		TMP_FOLDER = "/tmp"
251
		usi_file = "/tmp/usi.py"
252
		output_file = None
253
		# test if usi.py exists
254
		if os.path.isfile(usi_file):
255
			# execute usi script
256
			_usi_exec = self._call(usi_file)
257
			if not _usi_exec[0]:  # if no error
258
				# parse the output and get the filename
259
				if len(_usi_exec) == 3 and _usi_exec[1]:
260
					_usi_output = _usi_exec[1].split('\n')
261
					usi_output = [entry for entry in _usi_output if entry]  # remove empty strings from list
262
					for entry in usi_output:
263
						# TODO better use regex
264
						if entry.strip().startswith(TMP_FOLDER):
265
							output_file = entry.strip()
266
		# get and append general system info and ticket number if existent
267
		general_info = {
268
			'Manufacturer': manufacturer,
269
			'Model': model,
270
			'Comment': comment,
271
			'Ticket No': ticket,
272
			'Email': email
273
		}
274
		output_file = self.append_general_info_to_archive(output_file, general_info)
275
		output_file = self.copy_to_upload_path(output_file)  # copy finished archive to the right directory and change path accordingly
276
		return output_file
277
278
	def append_general_info_to_archive(self, archive, info):
279
		# create temp files
280
		_tmp_file = tempfile.NamedTemporaryFile(delete=False)
281
		_tmp_file.close()  # we just need the name
282
		_tmp_archive = tempfile.NamedTemporaryFile(delete=False)
283
		_tmp_archive.close()  # we just need the name
284
285
		# decompress archive
286
		with open(_tmp_archive.name, 'wb') as uncompressed_file, bz2.BZ2File(archive, 'rb') as compressed_file:
287
			for data in iter(lambda: compressed_file.read(100 * 1024), b''):
288
				uncompressed_file.write(data)
289
290
		# open archive in read mode to get folder name
291
		tar = tarfile.open(_tmp_archive.name, "r")
292
		archive_folder = os.path.commonprefix(tar.getnames())
293
		tar.close()
294
295
		# correct archive name
296
		gz_archive = archive_folder.rstrip('/') + '.tar.gz'
297
		info['archive'] = gz_archive.split('/')[-1]
298
299
		# write info file
300
		tmp_file = open(_tmp_file.name, "w")
301
		for entry in info:
302
			tmp_file.write("%s: %s%s" % (entry, info.get(entry), os.linesep,))
303
		tmp_file.close()
304
305
		# append info file to archive
306
		tar = tarfile.open(_tmp_archive.name, "a")
307
		tar.add(_tmp_file.name, arcname="%sinfo" % (archive_folder))
308
		tar.close()
309
310
		# re-compress archive as .gz, upload server takes only this format
311
		with open(_tmp_archive.name, 'rb') as uncompressed_file, gzip.open(gz_archive, 'wb') as compressed_file:
312
			for data in iter(lambda: uncompressed_file.read(100 * 1024), b''):
313
				compressed_file.write(data)
314
		compressed_file.close()
315
		return gz_archive
316
317
	def copy_to_upload_path(self, archive):
318
		# copy file to upload folder
319
		archive_name = archive.split('/')[-1]
320
		upload_file = SYSINFO_PATH + archive_name
321
		copyfile(archive, upload_file)
322
		# set owner and group
323
		uid = pwd.getpwnam("www-data").pw_uid
324
		gid = grp.getgrnam("www-data").gr_gid
325
		os.chown(upload_file, uid, gid)
326
		return upload_file
327
328
329
class HTTPSConnection(httplib.HTTPSConnection):
330
	'''override httplib so we can check certificates against ca bundle'''
331
	def connect(self):
332
		sock = socket.create_connection((self.host, self.port), self.timeout)
333
		if self._tunnel_host:
334
			self.sock = sock
335
			self._tunnel()
336
		self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, cert_reqs=ssl.CERT_REQUIRED, ca_certs="/etc/ssl/certs/ca-certificates.crt")
337
338
	def getreply(self):
339
		response = self.getresponse()
340
		self.file = response.fp
341
		return response.status, response.reason, response.msg
342
343
	def getfile(self):
344
		return self.file
345
346
347
class HTTPSHandler(urllib2.HTTPSHandler):
348
	''' handler to force certificate verification '''
349
	def https_open(self, req):
350
		return self.do_open(HTTPSConnection, req)
(-)a/management/univention-system-info/umc/python/sysinfo/de.po (-2 / +2 lines)
 Lines 3-9   msgid "" Link Here 
3
msgstr ""
3
msgstr ""
4
"Project-Id-Version: univention-management-console-module-sysinfo\n"
4
"Project-Id-Version: univention-management-console-module-sysinfo\n"
5
"Report-Msgid-Bugs-To: packages@univention.de\n"
5
"Report-Msgid-Bugs-To: packages@univention.de\n"
6
"POT-Creation-Date: 2014-12-18 16:16+0100\n"
6
"POT-Creation-Date: 2016-04-05 15:34+0200\n"
7
"PO-Revision-Date: 2016-01-14 11:26+0100\n"
7
"PO-Revision-Date: 2016-01-14 11:26+0100\n"
8
"Last-Translator: Univention GmbH <packages@univention.de>\n"
8
"Last-Translator: Univention GmbH <packages@univention.de>\n"
9
"Language-Team: Univention GmbH <packages@univention.de>\n"
9
"Language-Team: Univention GmbH <packages@univention.de>\n"
 Lines 12-17   msgstr "" Link Here 
12
"Content-Type: text/plain; charset=UTF-8\n"
12
"Content-Type: text/plain; charset=UTF-8\n"
13
"Content-Transfer-Encoding: 8bit\n"
13
"Content-Transfer-Encoding: 8bit\n"
14
14
15
#: umc/python/sysinfo/__init__.py:85
15
#: umc/python/sysinfo/__init__.py:93
16
msgid "Failed to execute command"
16
msgid "Failed to execute command"
17
msgstr "Die Ausführung des Kommandos ist fehlgeschlagen"
17
msgstr "Die Ausführung des Kommandos ist fehlgeschlagen"
(-)a/management/univention-system-info/umc/python/sysinfo/univention-support-info (+847 lines)
Line 0    Link Here 
1
#!/usr/bin/env python
2
# -*- coding: utf-8 -*-
3
#
4
# univention-support-info - collect system information
5
#
6
# Copyright 2011 Univention GmbH
7
#
8
# http://www.univention.de/
9
#
10
# All rights reserved.
11
#
12
# The source code of this program is made available
13
# under the terms of the GNU Affero General Public License version 3
14
# (GNU AGPL V3) as published by the Free Software Foundation.
15
#
16
# Binary versions of this program provided by Univention to you as
17
# well as other copyrighted, protected or trademarked materials like
18
# Logos, graphics, fonts, specific documentations and configurations,
19
# cryptographic keys etc. are subject to a license agreement between
20
# you and Univention and not subject to the GNU AGPL V3.
21
#
22
# In the case you use this program under the terms of the GNU AGPL V3,
23
# the program is provided in the hope that it will be useful,
24
# but WITHOUT ANY WARRANTY; without even the implied warranty of
25
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26
# GNU Affero General Public License for more details.
27
#
28
# You should have received a copy of the GNU Affero General Public
29
# License with the Debian GNU/Linux or Univention distribution in file
30
# /usr/share/common-licenses/AGPL-3; if not, see
31
# <http://www.gnu.org/licenses/>.
32
33
keyID = '18B913ABF3C1550B8C2DFDA994F01970E89E3BEC'
34
# create with: gpg --armor --export --export-options export-minimal $keyID
35
keyData = '\n'.join(('-----BEGIN PGP PUBLIC KEY BLOCK-----',
36
					 'Version: GnuPG v1.4.9 (GNU/Linux)',
37
					 '',
38
					 'mQGiBEA2RhgRBADee7hGh5TPPwqs+z5tfLett9xaVxmRkUfBvqesVIj93WzrKsU3',
39
					 'S7hjnMlh+JieFjJLy6jTJYtvqqFIxh3vw5btCwhntrTQnu00U/r3UdznqE/zGH2L',
40
					 'A734aHaSaq6UFKE5kwX0DECgSI1hwc20d7guLJXSqOpwfYktXiB+27GRCwCgh4OR',
41
					 'MWncPkhaJhusO8YCSnSN0GED/2ez8utubP1FloTfTof4/OLfBvPwdgJ5Q7FRqeF9',
42
					 'wDmfd8Hetzr+Fh4zMs6dY0c5+unUQiLXjY9F01WT7SM+yFrs5EHzb+gyjIdTmTtn',
43
					 'mtNTL2cZK8freAv9LPWCHfQ1rii+Qd71+/CKLDfwwLqQxEAkOsrpOsUD4dip6vkm',
44
					 'ZtaRBACUYoOtB738OzjPqOpbnmNQjQYVtGCocDjfKs+bMyq+LPOyC31NVC4LvqhC',
45
					 'nwXSUSy8jfXLzInPXgEUiHvGAEvnNzRLAIh6W/pIaK7tIITESmV/C3PBvxLEkJNm',
46
					 '8Ll+2qGVspYnGTUFe6JzxARzcTVow4JlB+dX40bk7LNqUe6Au7QqVW5pdmVudGlv',
47
					 'biBTdXBwb3J0IDxzdXBwb3J0QHVuaXZlbnRpb24uZGU+iF4EExECAB4GCwkIBwMC',
48
					 'AxUCAwMWAgECHgECF4AFAkm+NOYCGQEACgkQlPAZcOieO+xhXwCfdZ7+eWGpJfhz',
49
					 'CnrfuzgdzqsetMMAn3oUbDZCqzH083DKCNS5547V8XkCtCpVbml2ZW50aW9uIFN1',
50
					 'cHBvcnQgPHNlcnZpY2VAdW5pdmVudGlvbi5kZT6IYAQTEQIAIAUCSNdW8wIbIwYL',
51
					 'CQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEJTwGXDonjvsQcoAn2b9FNPECtPus0Sf',
52
					 '3ENGafyXSIq7AJ9sbNm+QryXW1rtvtsHlNgYI9eGpLQrVW5pdmVudGlvbiBTdXBw',
53
					 'b3J0IDxmZWVkYmFja0B1bml2ZW50aW9uLmRlPohgBBMRAgAgBQJI11aYAhsjBgsJ',
54
					 'CAcDAgQVAggDBBYCAwECHgECF4AACgkQlPAZcOieO+wmzACfVmZKVc37T7W9FQGN',
55
					 'K+dXsLbDplkAniAYh0l9Nd8wMh/QZrxcRdlgOBrhtDRVbml2ZW50aW9uIFN1cHBv',
56
					 'cnQgPHBhcnRuZXItdGVjaG5pY2FsQHVuaXZlbnRpb24uZGU+iGAEExECACAFAkho',
57
					 'p9gCGyMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRCU8Blw6J477IMYAJ9oZoTS',
58
					 'vHsxF7TYJSGo3pcutuV4RACfbxLxxjU7suCGs+khvINRl9pJel60KlVuaXZlbnRp',
59
					 'b24gU2VydmljZSA8c2VydmljZUB1bml2ZW50aW9uLmRlPohgBBMRAgAgBQJJvjVV',
60
					 'AhsjBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQlPAZcOieO+ycGwCeM8pJxUrL',
61
					 'oiKylTxiKZ4MwQoV/L0An3y/9GafqT8SaUgSjYO+9P4szWATtCtQYXJ0bmVyLUxp',
62
					 'c3RzIDxwYXJ0bmVyLWxpc3RzQHVuaXZlbnRpb24uZGU+iGAEExECACAFAkm+NQEC',
63
					 'GyMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRCU8Blw6J477C67AJ93Pv9Dcq7g',
64
					 'HreBv3f1Q07IjDI3bACfUZgClXNISIewXER8FzV5cC08LRm0LFVuaXZlbnRpb24g',
65
					 'RmVlZGJhY2sgPGZlZWRiYWNrQHVuaXZlbnRpb24uZGU+iGAEExECACAFAkm+NSsC',
66
					 'GyMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRCU8Blw6J477E8QAJ0XE91GawgL',
67
					 'lVGfeiiT7c32P35IDACePCNLSzHA6K6JrV7CP98BeZUUNYu0LFVuaXZlbnRpb24g',
68
					 'SGVscGRlc2sgPGhlbHBkZXNrQHVuaXZlbnRpb24uZGU+iGAEExECACAFAkm+NUMC',
69
					 'GyMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRCU8Blw6J477JNxAJ4l9wqf+WtV',
70
					 'C0sAtu91aGWvgW/JQACfTJUCWf1DTqn1sDhbNiCG2jA+B9K0LFVuaXZlbnRpb24g',
71
					 'VmVydHJpZWIgPHZlcnRyaWViQHVuaXZlbnRpb24uZGU+iGAEExECACAFAkm+NWwC',
72
					 'GyMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRCU8Blw6J477Jq3AJ9fN/6oKbqY',
73
					 'exKHPdLQw31wC8HGTgCfZ5gn5zDd2JSY9tirDtMw5SSdfk20M1BhcnRuZXItVGVj',
74
					 'aG5pY2FsIDxwYXJ0bmVyLXRlY2huaWNhbEB1bml2ZW50aW9uLmRlPohgBBMRAgAg',
75
					 'BQJJvjUPAhsjBgsJCAcDAgQVAggDBBYCAwECHgECF4AACgkQlPAZcOieO+wlNQCf',
76
					 'eZ7Z4PeCx7SF+k1CK0bC8oouICkAn3/NYT1ASQLFP8CBqku1shs1lFCstDNQcmVt',
77
					 'aXVtLVRlY2huaWNhbCA8cHJlbWl1bS10ZWNobmljYWxAdW5pdmVudGlvbi5kZT6I',
78
					 'YAQTEQIAIAUCSb41GgIbIwYLCQgHAwIEFQIIAwQWAgMBAh4BAheAAAoJEJTwGXDo',
79
					 'njvsxqcAnjRmgwWtXJqEbptTSSkaamNmGp9KAJ0R7b4RYDSKr+aFGPhhgetqLNXO',
80
					 'MrQwVW5pdmVudGlvbiBPWCBTdXBwb3J0IDxveC1zdXBwb3J0QHVuaXZlbnRpb24u',
81
					 'ZGU+iGAEExECACAFAk1GmXcCGyMGCwkIBwMCBBUCCAMEFgIDAQIeAQIXgAAKCRCU',
82
					 '8Blw6J477JwmAJ9WeeR2SzUtHY7pPolhm4fQmtM20QCfaebVO97CHdKkcAqPjJ3K',
83
					 'RwWVtpC5AQ0EQDZGGxAEAJotyyct6jvNscl9q2stDB+BUuXefdd7UMdSySSGqt5c',
84
					 '7f/6IEX/eiG/2nIsqX1IsSQ+Bw0ZQTQUhgI8hICUsmjdjvWnBCyHX8xnMESITDv/',
85
					 'fJmxgaP8fbMSJexhnizjlz8m74OgnfFew6EuRWRXA/SDeTwmsaUafTv7biKaDlU7',
86
					 'AAMFA/9hJUqdh+tSaEfwUzPgHdFT8EIM2B0VSmVnqHSWwCjuJTLTWJi+DDe2hq7p',
87
					 'QPpcATzgEg5qu5lsqh0AAXV998fD/RiO3B+ct1rwYbNlchACIXtgDTe43dmUaKkp',
88
					 'fPRxeQZr8iym706LJOyppF+jXqOm2oy6Sf++/YElcCBmPPDIwIhGBBgRAgAGBQJA',
89
					 'NkYbAAoJEJTwGXDonjvsqD0AnRVxlYyWk3DrKL0ZCxRZrtpW6pbwAJ9R/HZLaaH+',
90
					 '043H7VXVPPTjhs6Tig==',
91
					 '=BE0y',
92
					 '-----END PGP PUBLIC KEY BLOCK-----',
93
					 ))
94
toprc = '\n'.join(('RCfile for "top with windows"		   # shameless braggin\'',
95
				   'Id:a, Mode_altscr=0, Mode_irixps=1, Delay_time=3.000, Curwin=0',
96
				   'Def	 fieldscur=AEHIOQTWKNMbcdfgjplrsuvyzX',
97
				   '		winflags=62905, sortindx=10, maxtasks=0',
98
				   '		summclr=1, msgsclr=1, headclr=3, taskclr=1',
99
				   'Job	 fieldscur=ABcefgjlrstuvyzMKNHIWOPQDX',
100
				   '		winflags=62777, sortindx=0, maxtasks=0',
101
				   '		summclr=6, msgsclr=6, headclr=7, taskclr=6',
102
				   'Mem	 fieldscur=ANOPQRSTUVbcdefgjlmyzWHIKX',
103
				   '		winflags=62777, sortindx=13, maxtasks=0',
104
				   '		summclr=5, msgsclr=5, headclr=4, taskclr=5',
105
				   'Usr	 fieldscur=ABDECGfhijlopqrstuvyzMKNWX',
106
				   '		winflags=62777, sortindx=4, maxtasks=0',
107
				   '		summclr=3, msgsclr=3, headclr=2, taskclr=3',
108
				   '',
109
				   ))
110
111
import cStringIO
112
import glob
113
import gzip
114
import optparse
115
import os
116
import shutil
117
import socket
118
import stat
119
import subprocess
120
import sys
121
import tarfile
122
import tempfile
123
import time
124
from distutils.spawn import find_executable
125
126
# ignore apt's "API not stable yet" warning
127
import warnings
128
warnings.filterwarnings("ignore", category=FutureWarning, append=True)
129
130
import apt
131
import apt_pkg
132
133
try:
134
	from univention import config_registry
135
except ImportError:
136
	if os.path.isfile('/usr/share/pyshared/univention/config_registry.py'):
137
		import imp
138
		config_registry = imp.load_source('config_registry', '/usr/share/pyshared/univention/config_registry.py')
139
	else:
140
		sys.path.append('/usr/share/pyshared')
141
		from univention import config_registry
142
143
ucr = config_registry.ConfigRegistry()
144
ucr.load()
145
timeString = time.strftime('%Y-%m-%d_%H-%M-%SZ', time.gmtime())
146
hostname = socket.gethostname()
147
148
149
150
def Popen(CommandTuple, Input=None):
151
	try:
152
		process = subprocess.Popen(CommandTuple, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True, env=env)
153
		(stdoutdata, stderrdata) = process.communicate(input=Input)
154
		return (process.returncode, stdoutdata, stderrdata)
155
	except (OSError, IOError), error:
156
		return ('Could not execute %s: %s' % (repr(CommandTuple), repr(' '.join(map(str, error.args)))), '', '')
157
158
def _ldapsearchCommand():
159
	''' Get ldapsearch command depending on UCS version '''
160
	if find_executable('univention-ldapsearch'):
161
		return 'univention-ldapsearch'
162
	return 'ldapsearch'
163
164
def _sprint(string):
165
	''' write status string to stdout without newline '''
166
	sys.stdout.write(string)
167
	sys.stdout.flush()
168
169
def U32(i):
170
	'''
171
	Return i as an unsigned integer, assuming it fits in 32 bits.
172
	If it's >= 2GB when viewed as a 32-bit unsigned int, return a long.
173
	'''
174
	if i < 0:
175
		i += 1L << 32
176
	return i
177
178
def addFile(name, size, fileobj):
179
	# try to determine filesize
180
	if size == None or size == False:
181
		fileobj.seek(0,os.SEEK_END)
182
		size = fileobj.tell()
183
	if fileobj.tell() > 0:
184
		fileobj.seek(0)
185
186
	info = tarfile.TarInfo()
187
	info.size = size
188
	info.name = 'univention-support-info-' + hostname + '-' + timeString + '/' + name
189
	info.mode = stat.S_IRUSR
190
	info.mtime = time.time()
191
	archive.addfile(info, fileobj)
192
193
def addFileByPath(filename):
194
	if filename.startswith('/proc/'):
195
		# This is a /proc/ file, os.stat(filename).st_size will always return 0
196
		tmpf = tempfile.mkstemp(prefix='univention-support-info.')[1]
197
		try:
198
			shutil.copy(filename, tmpf)
199
		except (OSError, IOError), error:
200
			error = '\n'.join(map(str, error.args))
201
			addFile('files/' + filename.strip('/').replace('/', '_') + '.ERROR', len(error), cStringIO.StringIO(error))
202
			os.unlink(tmpf)
203
		filesize = os.stat(tmpf).st_size
204
		os.unlink(tmpf)
205
	else:
206
		try:
207
			filesize = os.stat(filename).st_size
208
		except (OSError, IOError), error:
209
			filesize = 0
210
211
	try:
212
		fileobj = open(filename, 'rb')
213
	except (OSError, IOError), error:
214
		error = '\n'.join(map(str, error.args))
215
		addFile('files/' + filename.strip('/').replace('/', '_') + '.ERROR', len(error), cStringIO.StringIO(error))
216
	else:
217
		addFile('files/' + filename.strip('/').replace('/', '_'), filesize, fileobj)
218
		fileobj.close()
219
220
def certificateValidity(CertificatePath):
221
	try:
222
		import M2Crypto
223
	except ImportError, error:
224
		error = '\n'.join(map(str, error.args))
225
		addFile('info/ssl/' + CertificatePath.strip('/').replace('/', '_') + '.ERROR', len(error), cStringIO.StringIO(error))
226
		return
227
228
	try:
229
		cert = M2Crypto.X509.load_cert(CertificatePath)
230
		validity = '%s\nNot Before: %s\nNot After : %s\n' % (CertificatePath, cert.get_not_before(), cert.get_not_after(), )
231
		addFile('info/ssl/' + CertificatePath.strip('/').replace('/', '_'), len(validity), cStringIO.StringIO(validity))
232
	except (OSError, IOError, M2Crypto.X509.X509Error), error:
233
		error = '\n'.join(map(str, error.args))
234
		addFile('info/ssl/' + CertificatePath.strip('/').replace('/', '_') + '.ERROR', len(error), cStringIO.StringIO(error))
235
236
def certificateValidities():
237
	_sprint( 'Checking certificate validity: ' )
238
	CertificatePatterns = [
239
		'/etc/univention/ssl/*.*/cert.pem',
240
		'/etc/univention/ssl/ucsCA/CAcert.pem',
241
		]
242
	for CertificatePattern in CertificatePatterns:
243
		for CertificatePath in glob.glob(CertificatePattern):
244
			certificateValidity(CertificatePath)
245
	print 'done.'
246
247
def simpleFiles():
248
	FilePatterns = [
249
		'/boot/config-*',
250
		'/etc/apache2/*',
251
		'/etc/apache2/*/*',
252
		'/etc/apt/*',
253
		'/etc/apt/*/*',
254
		'/etc/cron*/*',
255
		'/etc/fstab',
256
		'/etc/imapd/*',
257
		'/etc/mtab',
258
		'/etc/passwd',
259
		'/etc/procmailrc',
260
		'/etc/spamassassin/*',
261
		'/etc/univention/connector/ad/mapping.py',
262
		'/etc/univention/installation_profile',
263
		'/etc/ox-secrets/*',
264
		'/opt/open-xchange/etc/*',
265
		'/opt/open-xchange/etc/*/*',
266
		'/opt/open-xchange/etc/*/*/*',
267
		'/proc/mounts*',
268
		'/proc/mdstat',
269
		'/proc/drbd',
270
		'/proc/cmdline',
271
		'/var/lib/univention-directory-replication/failed.ldif',
272
		'/etc/postfix/*',
273
		'/etc/imapd/*',
274
		'/var/univention-backup/ad-takeover/*',
275
		'/etc/*/local.conf*',
276
		'/root/.bash_history',
277
		'/var/log/installer/*',
278
		'/etc/ldap/slapd.conf',
279
		]
280
	FileExcludePatterns = [ '/etc/apache2/mods-available/*', '/etc/apache2/sites-available/*' ]
281
282
	Files = set()
283
	ExcludeFiles = list()
284
	for FileExcludePattern in FileExcludePatterns:
285
		ExcludeFiles.extend(glob.glob(FileExcludePattern))
286
	for FilePattern in FilePatterns:
287
		for Filename in glob.glob(FilePattern):
288
			if not Filename in ExcludeFiles:
289
				Files.add(Filename)
290
291
	_sprint( 'Collecting files: ' )
292
	for Filename in sorted(list(Files)):
293
		if os.path.isfile(Filename):
294
			addFileByPath(Filename)
295
			_sprint('.')
296
	print 'done.'
297
298
def licenseObject():
299
	''' Get license object from ldap (cn=license) '''	
300
	stdout = executeCommand( 'univention-license-object', (_ldapsearchCommand(), '-x' , '-b', 'cn=license,cn=univention,'+ucr.get('ldap/base')) )
301
	addFile('info/univention-license-object', len(stdout), cStringIO.StringIO(stdout))
302
303
	
304
def checkMaintenance():
305
	''' Check if UCS-Version is in maintenance '''
306
	if ucr.get('version/version') <= '3.1' and ucr.get('server/role') != 'ucc':
307
		tmpf = tempfile.TemporaryFile(prefix='univention-support-info.')
308
		print "Please note, system is no longer maintained, security updates are no longer available for current UCS Version %s" % (ucr.get('version/version'))
309
		print >> tmpf, "Please note, system is no longer maintained, security updates are no longer available for current UCS Version %s" % (ucr.get('version/version'))
310
		addFile( 'info/no_maintenance', None, tmpf )
311
312
def checkEntryUUID():
313
	''' Check if ldap base is searchable by its entryUUID '''
314
	entryuuid=""
315
	basedn=""
316
	tmpf = tempfile.TemporaryFile(prefix='univention-support-info.')
317
	(exitcode, stdout, stderr, ) = Popen( (_ldapsearchCommand(), '-xLLL', '-sbase', 'entryUUID', ) )
318
	if exitcode == 0:
319
		entryuuid = stdout.split()[3]
320
	else:
321
		print >> tmpf, "ERROR: ldapsearch for base failed: %s" % str(stderr)
322
		addFile( 'info/entryUUID.stderr', None, tmpf )
323
		return
324
	(exitcode, stdout, stderr, ) = Popen( (_ldapsearchCommand(), '-xLLL', 'entryUUID='+entryuuid, 'dn', ) )
325
	if exitcode == 0:
326
		basedn = stdout.split()[1]
327
	else:
328
		print >> tmpf, "ERROR: ldapsearch by entryUUID failed: %s" % str(stderr)
329
		addFile( 'info/entryUUID.stderr', None, tmpf )
330
		return
331
	if ucr.get('ldap/base') == basedn:
332
		print >> tmpf, "OK: ldap base found by entryUUID"
333
	else:
334
		print >> tmpf, "ERROR: ldap base not found by entryUUID, check ldap index"
335
	addFile( 'info/entryUUID', None, tmpf )
336
337
def aptPackageList():
338
	"""List installed packages and their source repository."""
339
	_sprint( 'Collecting package lists: ' )
340
	cache = apt.Cache()
341
342
	packagesAll = tempfile.TemporaryFile(prefix='univention-support-info.')
343
	packagesUnknownSource = tempfile.TemporaryFile(prefix='univention-support-info.')
344
345
	if not hasattr(apt, 'deprecation'):  # python apt 0.7.7 in UCS < 3.0
346
		packages = [_ for _ in cache if _.isInstalled]
347
		for pkg in packages:
348
			pkg._lookupRecord(True)
349
			try:
350
				path = apt_pkg.ParseSection(pkg._records.Record)["Filename"]
351
			except KeyError:
352
				print >> packagesUnknownSource, "%s\tUNKNOWN" % (pkg.name,)
353
				continue
354
			cand = pkg._depcache.GetCandidateVer(pkg._pkg)
355
			for packagefile, _ in cand.FileList:
356
				indexfile = cache._list.FindIndex(packagefile)
357
				if indexfile:
358
					uri = indexfile.ArchiveURI(path)
359
					print >> packagesAll, "%s\t%s" % (pkg.name, uri)
360
	else:
361
		packages = [_ for _ in cache if _.is_installed]
362
		for pkg in packages:
363
			version = pkg.installed.version
364
			package = pkg.versions[version]
365
			try:
366
				uri = package.uri
367
			except StopIteration:
368
				print >> packagesUnknownSource, "%s\tUNKNOWN" % (pkg.name,)
369
				continue
370
			print >> packagesAll, "%s\t%s" % (pkg.name, uri)
371
	
372
	addFile( 'info/packages_all', None, packagesAll )
373
	addFile( 'info/packages_unknown-source', None, packagesUnknownSource )
374
	print 'done.'
375
376
def executeCommand(commandName, command, log_stderr = False):
377
	(exitcode, stdout, stderr, ) = Popen(command)
378
	if exitcode or log_stderr:
379
		if type(exitcode) is int:
380
			stderr += '\nExitcode was %d\n' % exitcode
381
		else:
382
			stderr += exitcode + '\n'
383
		addFile('info/' + commandName + '.stderr', len(stderr), cStringIO.StringIO(stderr))
384
	return stdout
385
386
def templateFiles():
387
	_sprint( 'Searching for changed template files: ' )
388
	stdout = executeCommand('check-templates', ('find', '/etc/univention/templates/files/', '(', '-name', '*.dpkg-new', '-o', '-name', '*.dpkg-dist', ')', '-print0', ))
389
	files = [templatefile for templatefile in stdout.split('\0') if templatefile]
390
	message = ('Found %d:\n' % len(files)) + '\n'.join(files) + '\n'
391
	addFile('info/check-templates', len(message), cStringIO.StringIO(message))
392
	for templatefile in files:
393
		addFileByPath(templatefile)
394
		if templatefile.endswith('.dpkg-new'):
395
			addFileByPath(templatefile[:-len('.dpkg-new')])
396
		elif templatefile.endswith('.dpkg-dist'):
397
			addFileByPath(templatefile[:-len('.dpkg-dist')])
398
		_sprint('.')
399
	print 'done.'
400
401
def collectCommandData():
402
	commands = {'hostname-f':
403
					('hostname', '--fqdn', ),
404
				'ifconfig-a':
405
					('ifconfig', '-v', '-a', ),
406
				'iptables-L_filter':
407
					('iptables', '-L', '-n', '-v', '-t', 'filter', ),
408
				'iptables-L_nat':
409
					('iptables', '-L', '-n', '-v', '-t', 'nat', ),
410
				'iptables-L_mangle':
411
					('iptables', '-L', '-n', '-v', '-t', 'mangle', ),
412
				'iptables-L_raw':
413
					('iptables', '-L', '-n', '-v', '-t', 'raw', ),
414
				'iptables-save':
415
					('iptables-save', '-c', ),
416
				'route-4':
417
					('route', '-v', '-ee', '-n', '-A', 'inet', ),
418
				'route-6':
419
					('route', '-v', '-ee', '-n', '-A', 'inet6', ),
420
				'netstat':
421
					('netstat', '--tcp', '--udp', '--listening', '--program', '--extend', '--extend', '--verbose', '--timers', '--numeric', '--wide', ),
422
				'dpkg-l':
423
					('dpkg-query', '--show', '--showformat=${Status}\t${Package}\t${Version}\n', ),
424
				'dpkg--audit':
425
					('dpkg', '--audit', ),
426
				'uname':
427
					('uname', '-a', ),
428
				'ps':
429
					('ps', '-AHFly', ),
430
				'ps-full':
431
					('ps', '-ALwwo', 'stat,pid,ppid,sid,tty,nlwp,lwp,pri,ni,sched,wchan,vsz,rss,sz,pcpu,pmem,cmd,blocked,caught,ignored,pending,lstart,cls,time,flags,uid,user,ruid,ruser,suid,suser,gid,group,rgid,rgroup,sgid,sgroup', ),
432
				'ucr-dump':
433
					('univention-config-registry', 'dump', ),
434
				'df-full':
435
					('df', '--portability', '--print-type', ),
436
				'df-i-full':
437
					('df', '--portability', '--print-type', '--inodes', ),
438
				'df':
439
					('df', '-h', ),
440
				'df-i':
441
					('df', '-h', '-i', ),
442
				'join-status':
443
					('univention-check-join-status', ),
444
				'virsh-qemu':
445
					('virsh', '-c', 'qemu:///system', 'capabilities', ),
446
				'virsh-xen':
447
					('virsh', '-c', 'xen:///',		'capabilities', ),
448
				'top':
449
					('top', '-b', '-n2', ),
450
				'testparm':
451
					(('testparm', '-s', '-vvv', ), True),
452
				'listenerID':
453
					('cat', '/var/lib/univention-directory-listener/notifier_id', ),
454
				'notifierID':
455
					('/usr/share/univention-directory-listener/get_notifier_id.py', ),
456
				'mailq':
457
					('mailq', ),
458
		   		'univention-license-check':
459
					('univention-license-check', ),
460
				'hostaccount-id':
461
					('id', ucr.get('hostname') + '$', ),
462
				'dig_AXFR':
463
					('dig', '@'+ucr.get('nameserver1'), ucr.get('domainname'), '-t', 'AXFR'),
464
				'univention-connector-list-rejected':
465
					('univention-connector-list-rejected', ),
466
				}
467
468
	# Commands depending on samba version
469
	if sambaDomainVersion == 3:
470
		commands.update({'test-join':
471
							('net', 'rpc', 'testjoin', ),	
472
						})
473
	elif sambaDomainVersion == 4:
474
		commands.update({'net-ads-info':
475
							('net', 'ads', 'info', ),
476
						'net-ads-lookup':
477
							('net', 'ads', 'lookup', ),
478
						})
479
		if ucr.get('samba4/role', None):
480
			# Run only S4
481
			commands.update({'samba-tool-drs-showrepl':
482
								('samba-tool', 'drs', 'showrepl', ),
483
							'samba-tool-domain-level-show':
484
								('samba-tool', 'domain', 'level', 'show'),
485
							'samba-tool-domain-passwordsettings':
486
								('samba-tool', 'domain', 'passwordsettings', 'show' ),
487
							'testparm-samba4':
488
								(('testparm.samba4', '-s', '-vvv'), True),
489
							'samba-tool-fsmo-show':
490
								('samba-tool', 'fsmo', 'show'),
491
							'univention-s4connector-list-rejected':
492
								('univention-s4connector-list-rejected', ),
493
							'samba-tool-processes':
494
								('samba-tool', 'processes'),
495
							})
496
			# >= Samba4 RC (UCS 3.1)
497
			if ucr.get('version/version') >= '3.1':
498
				commands.update({'samba-tool-domain-info':
499
									('samba-tool', 'domain', 'info', '127.0.0.1', ),
500
								})
501
		else:
502
			# Run only on S3 member in S4 domain
503
			commands.update({'test-join':
504
								('net', 'ads', 'testjoin', ),
505
							})
506
507
	_sprint( 'Collecting command output: ' )
508
	for commandName in commands:
509
		command = commands[commandName]
510
		if type(command[0]) == tuple:
511
			stdout = executeCommand(commandName, command[0], command[1])
512
		else:
513
			stdout = executeCommand(commandName, command)
514
515
		addFile('info/' + commandName, len(stdout), cStringIO.StringIO(stdout))
516
		_sprint('.')
517
	print 'done.'
518
519
def univentionSystemInfo():
520
	_sprint( 'Collecting hardware information: ' )
521
	manu = executeCommand('dmidecode', ('dmidecode', '-s', 'system-manufacturer'))
522
	product = executeCommand('dmidecode', ('dmidecode', '-s', 'system-product-name'))
523
	if not manu:
524
		manu = 'Unknown'
525
	if not product:
526
		product = 'Unknown'
527
	stdout = executeCommand('univention-system-info', ('univention-system-info','-u','-m',manu,'-t',product,'-c','Created by univention-support-info','-s','-',))
528
	archive = None
529
	for line in stdout.split('\n'):
530
		if line.startswith('archive'):
531
			archive = line.split(':', 1)[1]
532
	if not archive:
533
		error = 'No archive returned!'
534
		error += '\nunivention-system-info stdout:\n%s' % stdout
535
		addFile('info/univention-system-info.ERROR', len(error), cStringIO.StringIO(error))
536
		return
537
	filename =os.path.join( '/var/www/univention-management-console/system-info/', archive )
538
	# If UMC is not installed /var/www/univention-management-console/system-info/ does not exist and archive stays in /tmp
539
	if not os.path.isfile( filename ):
540
		filename = os.path.join( '/tmp/', archive )
541
	try:
542
		archive = tarfile.open(name=filename, mode='r:*')
543
		for member in archive:
544
			if member.isfile():
545
				fileobj = archive.extractfile(member)
546
				addFile('info/univention-system-info/' + member.name, member.size, fileobj)
547
				fileobj.close()
548
		archive.close()
549
	except (IOError, tarfile.TarError, ), error:
550
		error = '\n'.join(map(str, error.args))
551
		error += '\nunivention-system-info stdout:\n%s' % stdout
552
		addFile('info/univention-system-info.ERROR', len(error), cStringIO.StringIO(error))
553
	print 'done.'
554
555
def rotatedLogs():
556
	DefaultMaxLineCount = 1000
557
	FilePatterns = [
558
		('/var/log/apache/*', DefaultMaxLineCount),
559
		('/var/log/apache2/*', DefaultMaxLineCount),
560
		('/var/log/auth.log*', DefaultMaxLineCount),
561
		('/var/log/dpkg.log*', DefaultMaxLineCount),
562
		('/var/log/mail.log*', DefaultMaxLineCount),
563
		('/var/log/open-xchange/*', DefaultMaxLineCount),
564
		('/var/log/samba/log.*', DefaultMaxLineCount),
565
		('/var/log/kern*', DefaultMaxLineCount),
566
		('/var/log/univention/*', DefaultMaxLineCount),
567
		('/var/log/univention/ucc-clients/*', DefaultMaxLineCount),
568
		('/var/log/apt/term.log*', DefaultMaxLineCount),
569
		('/var/log/squid/*', DefaultMaxLineCount),
570
		('/var/log/dansguardian/*', DefaultMaxLineCount),
571
		('/var/log/squidguard/*', DefaultMaxLineCount),
572
		('/var/log/syslog*', 2000000),
573
		('/var/log/univention/system-stats.log*', 5000000),
574
		('/var/log/freeradius/*', DefaultMaxLineCount),
575
		('/var/log/cups/*', DefaultMaxLineCount),
576
		]
577
	FullLogs = set(( # for these every available log-file shall be included
578
			'/var/log/dpkg.log',
579
			'/var/log/univention/updater.log',
580
			'/var/log/apt/term.log',
581
			'/var/log/univention/ad-takeover.log',
582
			))
583
	GzipSuffix = '.gz'
584
	logs = {}
585
	for FilePattern in [fp[0] for fp in FilePatterns]:
586
		for filename in glob.glob(FilePattern):
587
			if os.stat(filename).st_size <= 0 or os.path.isdir(filename):
588
				# ignore 0 byte files
589
				continue
590
			if filename.endswith(GzipSuffix):
591
				gzipped = True
592
				filename = filename[:-len(GzipSuffix)]
593
			else:
594
				gzipped = False
595
			if not filename.endswith('.') and os.path.splitext(filename)[1].strip('0123456789') == '.': # has extension and only digits in it
596
				(filename, ext, ) = os.path.splitext(filename)
597
				number = int(ext.lstrip('.'))
598
			else:
599
				number = -1
600
			if filename not in logs:
601
				logs[filename] = {}
602
			logs[filename][number] = gzipped
603
604
	_sprint( 'Collecting logfiles: ' )
605
	for logname in sorted(logs):
606
		logLinecount = 0
607
		nonemptyNumber = 0
608
		for number in sorted(logs[logname]):
609
			# is logname gzipped?
610
			gzipped = logs[logname][number]
611
			path = logname
612
			fileLinecount = 0
613
			if number != -1:
614
				path += '.%d' % number
615
			
616
			if gzipped:
617
				try:
618
					logfile = open(path + GzipSuffix, 'rb')
619
				except (OSError, IOError, ), error:
620
					error = '\n'.join(map(str, error.args))
621
					addFile('files/' + '%s_%d.stderr' % (logname.strip('/').replace('/', '_'), number, ), len(error), cStringIO.StringIO(error))
622
					continue
623
624
				# calc bytes and linecount of logfile
625
				# last 4 bytes of a gzip file contain the size of the original (uncompressed) input data modulo 2^32.
626
				try:
627
					logfile.seek(-4, os.SEEK_END)
628
				except IOError, e:
629
					print '\n\nFilename: %s' %path + GzipSuffix
630
					raise IOError(e)
631
				fileBytes = U32( gzip.read32(logfile) )
632
				logfile.close()
633
				fileLinecount = int( subprocess.Popen( 'zcat -f %s | wc -l' % (path + GzipSuffix), stdout=subprocess.PIPE, shell=True).stdout.read().strip() )
634
			else:
635
				# addFile may calculate the size for us
636
				fileBytes = None
637
				fileLinecount = int( subprocess.Popen( ('wc', '-l', path), stdout=subprocess.PIPE).stdout.read().strip().split()[0] )
638
			logLinecount += fileLinecount
639
			#if gzipped:
640
			#	_sprint( '"%s", "%s", "%s" -> ' % (path + GzipSuffix, fileBytes, fileLinecount) )
641
			#else:
642
			#	_sprint( '"%s", "%s", "%s" -> ' % (path, fileBytes, fileLinecount) )
643
644
			if fileLinecount <= 0:
645
				# skip logname if empty
646
				#print 'ERROR: Empty file? "%s"' % path
647
				continue
648
649
650
			nonemptyNumber += 1
651
			try:
652
				if gzipped:
653
					logfile = gzip.GzipFile(path + GzipSuffix, 'rb')
654
				else:
655
					logfile = open(path, 'rb')
656
			except (OSError, IOError, ), error:
657
				error = '\n'.join(map(str, error.args))
658
				addFile('files/' + '%s_%d.stderr' % (logname.strip('/').replace('/', '_'), nonemptyNumber, ), len(error), cStringIO.StringIO(error))
659
				continue
660
661
			# Add file to archive ...
662
			addFile('files/' + '%s_%d' % (logname.strip('/').replace('/', '_'), nonemptyNumber, ), fileBytes, logfile)
663
			#print 'Added as "%s_%d"' % (logname.strip('/').replace('/', '_'), nonemptyNumber, )
664
			logfile.close()
665
666
			if logname not in FullLogs and logLinecount > filter(lambda x: logname.startswith(x[0].replace('*', '')), FilePatterns)[0][1]:
667
				break
668
669
			_sprint('.')
670
	print 'done.'
671
672
def atJobs():
673
	'''
674
	Generate a list of at-Jobs (usefull for UCS@school)
675
	'''
676
	try:
677
		from univention.lib import atjobs as at
678
	except ImportError, error:
679
		error = str(error.message)
680
		addFile('info/at-jobs' + '.ERROR', len(error), cStringIO.StringIO(error))
681
		return
682
683
	jobs = ''
684
	try:
685
		for job in at.list( extended=True ):
686
			jobs += '\n'.join( (str(job), job.command) )
687
	except OSError, error:
688
		error = str(error.message)
689
		addFile('info/at-jobs' + '.ERROR', len(error), cStringIO.StringIO(error))
690
	addFile('info/at-jobs', len(jobs), cStringIO.StringIO(jobs))
691
692
def tryDelete(filename):
693
	try:
694
		os.remove(filename)
695
	except (OSError, IOError, ):
696
		pass
697
698
def gpg(archiveFileName):
699
	_sprint( 'Encrypting file: ' )
700
	keyringFileName = tempfile.mkstemp(prefix='univention-support-info-keyring.', suffix='.gpg')[1]
701
	secringFileName = tempfile.mkstemp(prefix='univention-support-info-secring.', suffix='.gpg')[1]
702
	trustdbFileName = tempfile.mkstemp(prefix='univention-support-info-trustdb.', suffix='.gpg')[1]
703
	tryDelete(trustdbFileName) # HACK: file must not exist for gpg to work
704
	gpgFileName = archiveFileName + '.gpg'
705
	gpgBase = ('gpg',
706
			   '--batch', '--quiet', '--no-tty',
707
			   '--with-colons', '--utf8-strings',
708
			   '--no-auto-check-trustdb', '--no-auto-key-locate', '--no-use-agent',
709
			   '--no-options',
710
			   '--no-random-seed-file',
711
			   '--trust-model','always',
712
			   '--trustdb-name', trustdbFileName,
713
			   '--secret-keyring', secringFileName,
714
			   '--no-default-keyring', '--keyring', keyringFileName,
715
			   )
716
	gpgImport  = gpgBase + ('--import',
717
							)
718
	gpgEncrypt = gpgBase + ('--recipient', keyID,
719
							'--encrypt', archiveFileName,
720
							)
721
	(exitcode, stdout, stderr, ) = Popen(gpgImport, Input=keyData)
722
	if exitcode:
723
		print 'gpg-import failed with %s' % exitcode
724
		if stdout:
725
			print 'stdout: ' + repr(stdout)
726
		if stderr:
727
			print 'stderr: ' + repr(stderr)
728
		tryDelete(keyringFileName)
729
		tryDelete(keyringFileName + '~')
730
		tryDelete(secringFileName)
731
		tryDelete(trustdbFileName)
732
		tryDelete(gpgFileName)
733
		return
734
	(exitcode, stdout, stderr, ) = Popen(gpgEncrypt)
735
	if exitcode:
736
		print 'gpg-encrypt failed with %s' % exitcode
737
		if stdout:
738
			print 'stdout: ' + repr(stdout)
739
		if stderr:
740
			print 'stderr: ' + repr(stderr)
741
		tryDelete(keyringFileName)
742
		tryDelete(keyringFileName + '~')
743
		tryDelete(secringFileName)
744
		tryDelete(trustdbFileName)
745
		tryDelete(gpgFileName)
746
		return
747
	tryDelete(keyringFileName)
748
	tryDelete(keyringFileName + '~')
749
	tryDelete(secringFileName)
750
	tryDelete(trustdbFileName)
751
	os.chmod(gpgFileName, stat.S_IWUSR | stat.S_IRUSR | stat.S_IRGRP | stat.S_IROTH)
752
	print 'done.'
753
	return gpgFileName
754
755
def checkForRoot():
756
	if os.geteuid() != 0:
757
		print 'Please run this program as root!'
758
		sys.exit(3)
759
760
def prepareArchive():
761
	global archiveFileName, archiveFile, archive
762
	archiveFileName = tempfile.mkstemp(prefix='univention-support-info-%s.' % hostname, suffix='.tar.bz2')[1]
763
	archiveFile = open(archiveFileName, 'wb')
764
	archive = tarfile.open(mode='w|bz2', fileobj=archiveFile)
765
766
def closeArchive():
767
	archive.close()
768
	archiveFile.close()
769
770
def prepareEnvironment():
771
	global env
772
	env = os.environ.copy()
773
	env['LC_ALL'] = 'C'
774
	env['COLUMNS'] = '250'
775
	env['HOME'] = tempfile.mkdtemp(prefix='univention-support-info_')
776
	try:
777
		shutil.copy('/etc/skel/.bashrc', env['HOME'])
778
		shutil.copy('/etc/skel/.profile', env['HOME'])
779
		f = open(os.path.join(env['HOME'], '.toprc'), 'w')
780
		f.write(toprc)
781
		f.close()
782
	except (OSError, IOError, ):
783
		pass
784
785
def cleanup():
786
	shutil.rmtree(env['HOME'])
787
788
def main(encrypt=False):
789
	checkForRoot()
790
	global archive, env, sambaDomainVersion
791
	prepareArchive()
792
	prepareEnvironment()
793
794
	# Check Samba Version
795
	if executeCommand( 'samba4-pdc-dn', (_ldapsearchCommand(), '-xLLL', '(&(univentionService=Samba 4)(objectClass=univentionDomainController))', 'dn') ):
796
		sambaDomainVersion = 4
797
	else:
798
		sambaDomainVersion = 3
799
800
	# Place new calls below this line
801
	checkMaintenance()
802
	collectCommandData()
803
	simpleFiles()
804
	licenseObject()
805
	templateFiles()
806
	aptPackageList()
807
	atJobs()
808
	certificateValidities()
809
	univentionSystemInfo()
810
	rotatedLogs()
811
	checkEntryUUID()
812
	# Place new calls above this line
813
814
	closeArchive()
815
	print 'Data collection completed.'
816
	print
817
	print
818
	if encrypt:
819
		gpgArchiveFileName = gpg(archiveFileName)
820
		if gpgArchiveFileName:
821
			print 'The encrypted data can be found here:'
822
			print '    ' + gpgArchiveFileName
823
			print ' '
824
		else:
825
			print 'WARNING: The data could not be encrypted!'
826
		print
827
		print 'The unencrypted data can be found here:'
828
	else:
829
		print 'The data can be found here:'
830
	print '    ' + archiveFileName
831
	cleanup()
832
833
if __name__ == "__main__":
834
	parser = optparse.OptionParser()
835
	parser.add_option('--encrypt', action='store_true', dest='encrypt', default=False, help='encrypt data (can only be decrypted by Univention support)')
836
	parser.usage = '\n'.join(('%prog [options]',
837
							  'collect system information',
838
							  '',
839
							  "%prog collects information about the system's configuration.",
840
							  'The information is stored in a temporary tar archive, the path of which is printed to stdout.',
841
							  ))
842
	(options, args, ) = parser.parse_args()
843
	if args:
844
		parser.print_help()
845
		sys.exit(0)
846
847
	main(options.encrypt)
(-)a/management/univention-system-info/umc/python/sysinfo/usi.py (+58 lines)
Line 0    Link Here 
1
#! /usr/bin/python2.7
2
3
import univention.management.console.modules.sysinfo as sysinfo
4
from univention.management.console.modules import UMC_Error
5
import argparse
6
7
# TODO ask for Ticket number and / or email
8
9
10
def check_args(args):
11
	if not args.ticket and not args.email:
12
		print ("Either a ticket number or an email adress are required, please provide at least one of those")
13
		ticket = raw_input("Ticket No: ")
14
		if ticket and ticket.isdigit():
15
			args.ticket = ticket
16
		email = raw_input("Email adress: ")
17
		if email:
18
			# TODO validation
19
			args.email = email
20
	return args
21
22
23
def usi_process(userinput):
24
	print args
25
	usi = sysinfo.Instance()
26
	print ("Downloading Univention-System-Information Script")
27
	usi._download_usi_script()
28
	print ("Gathering system manufacturer information")
29
	general_info = usi.gather_general_info()
30
	print ("Executing Univention-System-Information Script")
31
	usi_file = usi._execute_usi_script(general_info.get('manufacturer'), general_info.get('model'), userinput.get('comment'), userinput.get('ticket'), userinput.get('email'))
32
	print usi_file
33
	print ("Uploading information")
34
	try:
35
		usi._upload_archive(usi_file)
36
	except(UMC_Error):
37
		print ("An error occured while uploading, you can try sending the informations by mail")
38
	else:
39
		print ("Upload successful")
40
	print ("An archive containing the information can be found at '%s'" % (usi_file,))
41
42
43
if __name__ == '__main__':
44
45
	parser = argparse.ArgumentParser(description='Univention-System-Information')
46
	parser.add_argument('--email', dest='email', action='store', default=None, help='an email adress to contact you')
47
	parser.add_argument('--ticket', dest='ticket' ,action='store', default=None, help='existing Univention-support ticket number')
48
	parser.add_argument('--comment', dest='comment' ,action='store', default=None, help='an optional comment')
49
50
	args = parser.parse_args()
51
52
	args = check_args(args)
53
	if not args.ticket and not args.email:
54
		#TODO exit
55
		print ("Error, no email or ticket number provided, will exit now")
56
		exit(1)
57
	userinput = vars(args)
58
	usi_process(userinput)
(-)a/management/univention-system-info/umc/sysinfo.xml (+2 lines)
 Lines 12-16    Link Here 
12
		<command name="sysinfo/mail" function="get_mail_info" />
12
		<command name="sysinfo/mail" function="get_mail_info" />
13
		<command name="sysinfo/upload" function="upload_archive" />
13
		<command name="sysinfo/upload" function="upload_archive" />
14
		<command name="sysinfo/traceback" function="upload_traceback" />
14
		<command name="sysinfo/traceback" function="upload_traceback" />
15
		<command name="sysinfo/download_usi" function="download_usi_script" />
16
		<command name="sysinfo/execute_usi" function="execute_usi_script" />
15
	</module>
17
	</module>
16
</umc>
18
</umc>

Return to bug 29191