1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 import traceback
19 import stat
20 import shutil
21 import sys
22 import os
23 import os.path
24 import tempfile
25
26 if sys.version_info[0] == 3:
27 import xmlrpc.client as xmlrpclib
28 else:
29 import xmlrpclib
30
31 from koan.app import Koan
32
33 SHADOW = "/tmp/ks-tree-shadow"
34
36 tmp = tempfile.mktemp()
37 status = os.system(cmd + " > " + tmp)
38 data = open(tmp).readlines()
39 ret = []
40 for l in data:
41 ret.append(l.strip())
42 if status == 0:
43 return ret
44 raise Exception('Error executing command:\n %s\noutput:\n%s' % (cmd, '\n'.join(ret)))
45
48
50 nm = execute("LANG=C ipcalc -4ms $(ip -4 -o addr show dev %s | awk '{print $4}')|awk -F= '{print $2}'" % device)
51 if nm:
52 return nm[0]
53 else:
54 return ""
55
57 nm6 = execute("LANG=C ip -6 -o addr show dev %s | perl -lne 'print $1 if m!/(.+) scope global!'" % device)
58 if nm6:
59 return nm6[0]
60 else:
61 return ""
62
64 ip = execute("LANG=C ip -4 -o addr show dev %s | perl -lne 'print $1 if m!.+\s(.+)/.+ scope global!'" % device)
65 if ip:
66 return ip[0]
67 else:
68 return ""
69
71 ip6 = execute("LANG=C ip -6 -o addr show dev %s | perl -lne 'print $1 if m!.+\s(.+)/.+ scope global!'" % device)
72 if ip6:
73 return ip6[0]
74 else:
75 return ""
76
78 servers = execute("cat /etc/resolv.conf | perl -lne '/^nameserver\s+(\S+)/ and print $1'")
79 ret = []
80 for s in servers:
81 if s not in ("127.0.0.1", "::1"):
82 ret.append(s)
83 return ret
84
91
98
100 path = "/etc/sysconfig/rhn/systemid"
101 if not os.access(path, os.R_OK):
102 return None
103 return open(path, "r").read()
104
106 path = '/boot/initrd.img'
107 if os.access(path + "_koan", os.R_OK):
108 return path + "_koan"
109 return path
110
112 client = xmlrpclib.Server("https://" + kickstart_host + "/rpc/api")
113 data = {"gateway" : find_gateway(static_device),\
114 "nameservers": find_name_servers(),\
115 "hostname" : find_host_name(),\
116 "device" : static_device,\
117 "ip": find_ip(static_device),\
118 "netmask" : find_netmask(static_device)}
119
120 data6 = {"gateway" : find_gateway6(static_device), \
121 "device" : static_device, \
122 "ip" : find_ip6(static_device), \
123 "netmask" : find_netmask6(static_device)}
124
125 api_version = client.api.get_version()
126
127
128 if float(api_version) <= 11.00:
129 client.system.setup_static_network(getSystemId(), data)
130 else:
131 client.system.setup_static_network(getSystemId(), data, data6)
132
133 -def initiate(kickstart_host, base, extra_append, static_device=None, system_record="", preserve_files=[]):
134
135 error_messages = {}
136 success = 0
137
138
139 rm_rf(SHADOW)
140 os.mkdir(SHADOW)
141
142 print("Preserve files! : %s" % preserve_files)
143
144 try:
145 if static_device:
146 update_static_device_records(kickstart_host, static_device)
147
148 k = Koan()
149 k.list_items = 0
150 k.server = kickstart_host
151 k.is_virt = 0
152 k.is_replace = 1
153 k.is_display = 0
154 k.profile = None
155
156 if system_record != "":
157 k.system = system_record
158 else:
159 k.system = None
160 k.port = 443
161 k.image = None
162 k.live_cd = None
163 k.virt_path = None
164 k.virt_type = None
165 k.virt_bridge = None
166 k.no_gfx = 1
167 k.add_reinstall_entry = None
168 k.kopts_override = None
169 k.use_kexec = None
170 k.embed_kickstart = k.embed_autoinst = None
171 if hasattr(k, 'no_copy_default'):
172 k.no_copy_default = 1
173 else:
174 k.grubby_copy_default = 0
175 if static_device:
176 k.embed_kickstart = k.embed_autoinst = 1
177 k.run()
178
179 except Exception:
180 (xa, xb, tb) = sys.exc_info()
181 try:
182 getattr(xb, "from_koan")
183 error_messages['koan'] = str(xb)[1:-1]
184 print(str(xb)[1:-1])
185 except:
186 print(xa)
187 print(xb)
188 print(" ".join(traceback.format_list(traceback.extract_tb(tb))))
189 error_messages['koan'] = " ".join(traceback.format_list(traceback.extract_tb(tb)))
190 return (1, "Kickstart failed. Koan error.", error_messages)
191
192
193 initrd = getInitrdPath()
194 if preserve_files:
195 ret = create_new_rd(initrd, preserve_files)
196 if ret:
197
198 return ret
199 initrd = initrd + ".merged"
200
201
202
203 return (0, "Kickstart initiate succeeded", error_messages)
204
205
208 self.value = disk_path
210 return "Virt Disk Path %s already exists on the host system. Please provide another disk path for the virt guest and reschedule your guest kickstart." % self.value
211
212
215 self.value = device_path
217 return "Block Device Path %s does not exist on the host system. Please create the device for the virtual guest and reschedule your guest kickstart." % self.value
218
219
220 -def initiate_guest(kickstart_host, cobbler_system_name, virt_type, name, mem_kb,
221 vcpus, disk_gb, virt_bridge, disk_path, extra_append, log_notify_handler=None):
222
223 error_messages = {}
224 success = 0
225 try:
226 if disk_path.startswith('/dev/'):
227 if not os.path.exists(disk_path):
228 raise BlockDeviceNonexistentError(disk_path)
229 else:
230 if os.path.exists(disk_path):
231 raise VirtDiskPathExistsError(disk_path)
232
233 if virt_type == "qemu":
234 if os.path.exists("/dev/kvm"):
235 virt_type = "kvm"
236 else:
237 print("Warning: KVM not available, using QEMU.")
238 k = Koan()
239 k.list_items = 0
240 k.server = kickstart_host
241 k.is_virt = 1
242 k.is_replace = 0
243 k.is_display = 0
244 k.port = 443
245 k.profile = None
246 k.system = cobbler_system_name
247 k.should_poll = 1
248 k.image = None
249 k.live_cd = None
250 k.virt_name = name
251 k.virt_path = disk_path
252 k.virt_type = virt_type
253 k.virt_bridge = virt_bridge
254 k.no_gfx = False
255 k.add_reinstall_entry = None
256 k.kopts_override = None
257 k.virt_auto_boot = None
258 if hasattr(k, 'no_copy_default'):
259 k.no_copy_default = 1
260 else:
261 k.grubby_copy_default = 0
262 if hasattr(k, 'virtinstall_wait'):
263 k.virtinstall_wait = 0
264 k.run()
265
266
267 import virtualization.support
268 virtualization.support.refresh()
269 except Exception:
270 (xa, xb, tb) = sys.exc_info()
271 if str(xb).startswith("The MAC address you entered is already in use"):
272
273 error_messages['koan'] = str(xb)
274 print(str(xb))
275 elif hasattr(xb, "from_koan") and len(str(xb)) > 1:
276 error_messages['koan'] = str(xb)[1:-1]
277 print(str(xb)[1:-1])
278 else:
279 print(xa)
280 print(xb)
281 print(" ".join(traceback.format_list(traceback.extract_tb(tb))))
282 error_messages['koan'] = str(xb) + ' ' + " ".join(traceback.format_list(traceback.extract_tb(tb)))
283 return (1, "Virtual kickstart failed. Koan error.", error_messages)
284
285 return (0, "Virtual kickstart initiate succeeded", error_messages)
286
288 """
289 Returns None if everything went well, or a tuple
290 (err_code, err_string, dict) if problems were found
291 """
292 if not initrd:
293 return (3, "Kickstart create new init failed: initrd not found: %s" %
294 initrd, {})
295
296
297 quota = 1000000
298
299
300 preserve_shadow = SHADOW + SHADOW
301
302
303
304 c = FileCopier(preserve_files, preserve_shadow, quota=quota)
305 try:
306 c.copy()
307 except QuotaExceeded:
308 return (3, "Quota of %s bytes exceeded" % quota, {})
309
310 (status, stdout, stderr) = my_popen([
311 "/usr/sbin/merge-rd.sh", initrd, initrd, SHADOW])
312 if status:
313 return (status, 'Error creating the new RAM disk',
314 _build_error(status, stdout, stderr))
315
316 return None
317
318
320 "Equivalent of rm -rf"
321
322 if os.path.islink(path):
323
324 os.unlink(path)
325 return
326
327 if os.path.exists(path):
328 return _remove_func(path)
329
330
332 "Recursive function for rm -rf; will fail if path doesn't exist"
333 if not os.path.isdir(path):
334
335 os.unlink(path)
336 return
337
338
339 files = os.listdir(path)
340
341 files = list(map(lambda x, p=path: os.path.join(p, x), files))
342
343 map(_remove_func, files)
344
345
346 os.rmdir(path)
347 return
348
350 print("CMD: %s " % cmd)
351
352 subproc = 1
353 try:
354 import subprocess
355 except ImportError:
356
357 import popen2
358 subproc = 0
359
360 if subproc:
361 c = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE,
362 stderr=subprocess.PIPE, close_fds=True, bufsize=-1)
363 c.stdin.close()
364 while 1:
365 status = c.poll()
366 if status is not None:
367
368
369 return status, c.stdout, c.stderr
370 else:
371 c = popen2.Popen3(cmd, capturestderr=1, bufsize=-1)
372 c.tochild.close()
373
374 while 1:
375 status = c.poll()
376 if os.WIFEXITED(status):
377
378
379 return os.WEXITSTATUS(status), c.fromchild, c.childerr
380
382 params = {
383 'status' : status,
384 'stdout' : stdout.read(),
385 'stderr' : stderr.read(),
386 }
387 return params
388
389
391 """A class that copies a list of files/directories to the specified
392 destination
393 """
394 - def __init__(self, files, dest, quota=None):
395 self.files = files
396 self.dest = dest
397 self.quota = quota
398 self.current_quota = 0
399
401 return self._copy(self.files)
402
404 assert(isinstance(files, list))
405 for f in files:
406 try:
407 st = os.lstat(f)
408 except OSError:
409
410 continue
411
412 st_mode = st[stat.ST_MODE]
413
414 if stat.S_ISLNK(st_mode):
415 self._copy_link(f, st)
416 elif stat.S_ISDIR(st_mode):
417 self._copy_dir(f, st)
418 elif stat.S_ISREG(st_mode):
419 self._copy_file(f, st)
420
421
434
435
437 if not self.quota:
438 return
439
440 if self.current_quota + file_size > self.quota:
441 raise QuotaExceeded(f)
442
443
445 self.current_quota = self.current_quota + file_size
446
447
449 dirname = os.path.dirname(f)
450 self._copy_dir_modes(dirname, self.dest)
451
452
454 os.chmod(dest, st[stat.ST_MODE])
455 os.chown(dest, st[stat.ST_UID], st[stat.ST_GID])
456 os.utime(dest, (st[stat.ST_ATIME], st[stat.ST_MTIME]))
457
458
464
465
477
478
480 return os.path.normpath(self.dest + f)
481
482
484 if not os.path.exists(dest):
485 os.makedirs(dest)
486 l = []
487 srcdir = os.path.normpath(srcdir)
488 while 1:
489 h, t = os.path.split(srcdir)
490 if not t:
491 break
492 l.append(t)
493 srcdir = h
494
495 l.reverse()
496 dest_dir = dest
497 src_dir = os.sep
498 for d in l:
499 src_dir = os.path.join(src_dir, d)
500 src_st = os.lstat(src_dir)
501 dest_dir = os.path.join(dest_dir, d)
502 if not os.path.exists(dest_dir):
503 os.mkdir(dest_dir)
504 os.chmod(dest_dir, src_st[stat.ST_MODE])
505 os.chown(dest_dir, src_st[stat.ST_UID], src_st[stat.ST_GID])
506
509