# PaCkAgE DaTaStReAm
opensvc 1 2605
# end of header
                                                                                                                                                                                                                                                                                                                                                                                                                                                                            070701000671a9000081a40000000000000000000000014d9d9455000000dc000000b600010002ffffffffffffffff0000001000000000opensvc/pkginfo   PKG=opensvc
NAME=opensvc Service Manager for logical servers v1.0-110407.1239
ARCH=all
VERSION=1.0
CATEGORY=application
VENDOR=http://www.opensvc.com
EMAIL=support@opensvc.com
PSTAMP=OPENSVC-1.0-110407.1239
CLASSES=none
070701000671a8000081a40000000000000000000000014d9d9455000044d9000000b600010002ffffffffffffffff0000000f00000000opensvc/pkgmap    : 1 2605
1 d none /opt/opensvc 0755 root root
1 d none /opt/opensvc/bin 0755 root root
1 s none /opt/opensvc/bin/alldownservices=svcmgr
1 s none /opt/opensvc/bin/allprimaryservices=svcmgr
1 s none /opt/opensvc/bin/allsecondaryservices=svcmgr
1 s none /opt/opensvc/bin/allservices=svcmgr
1 s none /opt/opensvc/bin/allupservices=svcmgr
1 d none /opt/opensvc/bin/cron 0755 root root
1 f none /opt/opensvc/bin/cron/opensvc 0755 root root 1465 58087 1302167150
1 f none /opt/opensvc/bin/freezer 0755 root root 1364 49689 1302167150
1 f none /opt/opensvc/bin/nodemgr 0755 root root 4346 34677 1302167150
1 f none /opt/opensvc/bin/opensvc.init.AIX 0755 root root 209 18797 1302167150
1 f none /opt/opensvc/bin/opensvc.init.Darwin 0644 root root 441 36791 1302167150
1 f none /opt/opensvc/bin/opensvc.init.FreeBSD 0755 root root 300 25712 1302167150
1 f none /opt/opensvc/bin/opensvc.init.SunOS 0755 root root 396 34372 1302167150
1 f none /opt/opensvc/bin/opensvc.init.debian 0755 root root 454 35881 1302167150
1 f none /opt/opensvc/bin/opensvc.init.hpux 0755 root root 738 60175 1302167150
1 f none /opt/opensvc/bin/opensvc.init.redhat 0755 root root 476 40877 1302167150
1 f none /opt/opensvc/bin/perfagt.Darwin 0755 root root 2538 48481 1302167150
1 f none /opt/opensvc/bin/perfagt.HP-UX 0755 root root 3056 32961 1302167150
1 f none /opt/opensvc/bin/perfagt.Linux 0755 root root 859 115 1302167150
1 d none /opt/opensvc/bin/pkg 0755 root root
1 f none /opt/opensvc/bin/pkg/make.lib 0644 root root 1808 2752 1302167150
1 f none /opt/opensvc/bin/pkg/make_deb 0755 root root 889 7276 1302167150
1 f none /opt/opensvc/bin/pkg/make_depot 0755 root root 2513 64216 1302167150
1 f none /opt/opensvc/bin/pkg/make_pkg 0755 root root 4800 35423 1302167150
1 f none /opt/opensvc/bin/pkg/make_rpm 0755 root root 886 9086 1302167150
1 f none /opt/opensvc/bin/pkg/make_tbz 0755 root root 1936 27386 1302167150
1 f none /opt/opensvc/bin/postinstall 0755 root root 15758 57179 1302167150
1 s none /opt/opensvc/bin/svcfreeze=freezer
1 s none /opt/opensvc/bin/svcfrozen=freezer
1 f none /opt/opensvc/bin/svcmgr 0755 root root 7514 36863 1302167150
1 f none /opt/opensvc/bin/svcmon 0755 root root 5396 27364 1302167150
1 s none /opt/opensvc/bin/svcthaw=freezer
1 d none /opt/opensvc/lib 0755 root root
1 f none /opt/opensvc/lib/checkFsInodeDarwin.py 0644 root root 1821 5364 1302167150
1 f none /opt/opensvc/lib/checkFsInodeHP-UX.py 0644 root root 1948 11812 1302167150
1 f none /opt/opensvc/lib/checkFsInodeLinux.py 0644 root root 1752 809 1302167150
1 s none /opt/opensvc/lib/checkFsUsageDarwin.py=checkFsUsageLinux.py
1 s none /opt/opensvc/lib/checkFsUsageFreeBSD.py=checkFsUsageLinux.py
1 f none /opt/opensvc/lib/checkFsUsageHP-UX.py 0644 root root 1889 8251 1302167150
1 f none /opt/opensvc/lib/checkFsUsageLinux.py 0644 root root 1820 5259 1302167150
1 f none /opt/opensvc/lib/checkVgUsageHP-UX.py 0644 root root 2630 64371 1302167150
1 f none /opt/opensvc/lib/checkVgUsageLinux.py 0644 root root 1954 14175 1302167150
1 f none /opt/opensvc/lib/checks.py 0644 root root 2976 17140 1302167150
1 f none /opt/opensvc/lib/compliance.py 0644 root root 14070 35385 1302167150
1 f none /opt/opensvc/lib/freezer.py 0644 root root 1780 9411 1302167150
1 f none /opt/opensvc/lib/hostidAIX.py 0644 root root 1107 26120 1302167150
1 f none /opt/opensvc/lib/hostidDarwin.py 0644 root root 888 9879 1302167150
1 s none /opt/opensvc/lib/hostidFreeBSD.py=hostidLinux.py
1 f none /opt/opensvc/lib/hostidHP-UX.py 0644 root root 1203 33767 1302167150
1 f none /opt/opensvc/lib/hostidLinux.py 0644 root root 888 9879 1302167150
1 f none /opt/opensvc/lib/hostidSunOS.py 0644 root root 888 9879 1302167150
1 f none /opt/opensvc/lib/lock.py 0644 root root 2810 17169 1302167150
1 f none /opt/opensvc/lib/loopSunOS.py 0644 root root 1439 52901 1302167150
1 f none /opt/opensvc/lib/node.py 0644 root root 22996 10909 1302167150
1 f none /opt/opensvc/lib/rcAddService.py 0644 root root 911 11569 1302167150
1 f none /opt/opensvc/lib/rcAsset.py 0644 root root 4847 42998 1302167150
1 f none /opt/opensvc/lib/rcAssetDarwin.py 0644 root root 3016 32180 1302167150
1 f none /opt/opensvc/lib/rcAssetFreeBSD.py 0644 root root 2470 53042 1302167150
1 f none /opt/opensvc/lib/rcAssetHP-UX.py 0644 root root 5880 14705 1302167150
1 f none /opt/opensvc/lib/rcAssetLinux.py 0644 root root 6526 55189 1302167150
1 f none /opt/opensvc/lib/rcAssetSunOS.py 0644 root root 3488 57771 1302167150
1 f none /opt/opensvc/lib/rcContainerLinux.py 0644 root root 5005 5438 1302167150
1 f none /opt/opensvc/lib/rcDiskInfo.py 0644 root root 1116 26183 1302167150
1 f none /opt/opensvc/lib/rcDiskInfoAIX.py 0644 root root 2372 50045 1302167150
1 f none /opt/opensvc/lib/rcDiskInfoDarwin.py 0644 root root 888 9990 1302167150
1 f none /opt/opensvc/lib/rcDiskInfoFreeBSD.py 0644 root root 1324 42833 1302167150
1 f none /opt/opensvc/lib/rcDiskInfoHP-UX.py 0644 root root 2946 21581 1302167150
1 f none /opt/opensvc/lib/rcDiskInfoLinux.py 0644 root root 3111 26273 1302167150
1 f none /opt/opensvc/lib/rcDiskInfoSunOS.py 0644 root root 888 9990 1302167150
1 f none /opt/opensvc/lib/rcExceptions.py 0644 root root 3442 19588 1302167150
1 f none /opt/opensvc/lib/rcFunctions.py 0644 root root 1284 40612 1302167150
1 f none /opt/opensvc/lib/rcGlobalEnv.py 0644 root root 5663 45699 1302167150
1 f none /opt/opensvc/lib/rcIfconfig.py 0644 root root 4124 44119 1302167150
1 f none /opt/opensvc/lib/rcIfconfigAIX.py 0644 root root 2810 69 1302167150
1 f none /opt/opensvc/lib/rcIfconfigDarwin.py 0644 root root 2631 51701 1302167150
1 f none /opt/opensvc/lib/rcIfconfigFreeBSD.py 0644 root root 2631 51701 1302167150
1 s none /opt/opensvc/lib/rcIfconfigFreeBSDhpvm.py=rcIfconfigFreeBSDkvm.py
1 f none /opt/opensvc/lib/rcIfconfigFreeBSDkvm.py 0644 root root 1266 39292 1302167150
1 s none /opt/opensvc/lib/rcIfconfigFreeBSDldom.py=rcIfconfigFreeBSDkvm.py
1 s none /opt/opensvc/lib/rcIfconfigFreeBSDxen.py=rcIfconfigFreeBSDkvm.py
1 f none /opt/opensvc/lib/rcIfconfigHP-UX.py 0644 root root 3126 21426 1302167150
1 f none /opt/opensvc/lib/rcIfconfigHP-UXhpvm.py 0644 root root 1745 5967 1302167150
1 f none /opt/opensvc/lib/rcIfconfigLinux.py 0644 root root 2878 1079 1302167150
1 s none /opt/opensvc/lib/rcIfconfigLinuxhpvm.py=rcIfconfigLinuxkvm.py
1 f none /opt/opensvc/lib/rcIfconfigLinuxkvm.py 0644 root root 1281 40272 1302167150
1 s none /opt/opensvc/lib/rcIfconfigLinuxldom.py=rcIfconfigLinuxkvm.py
1 f none /opt/opensvc/lib/rcIfconfigLinuxlxc.py 0644 root root 1563 61073 1302167150
1 f none /opt/opensvc/lib/rcIfconfigLinuxvz.py 0644 root root 1118 27400 1302167150
1 f none /opt/opensvc/lib/rcIfconfigSunOS.py 0644 root root 2855 1531 1302167150
1 s none /opt/opensvc/lib/rcIfconfigSunOSkvm.py=rcIfconfigSunOSldom.py
1 f none /opt/opensvc/lib/rcIfconfigSunOSldom.py 0644 root root 1281 40216 1302167150
1 s none /opt/opensvc/lib/rcIfconfigSunOSxen.py=rcIfconfigSunOSldom.py
1 f none /opt/opensvc/lib/rcIfconfigWindowskvm.py 0644 root root 1096 27277 1302167150
1 f none /opt/opensvc/lib/rcLogger.py 0644 root root 2265 47689 1302167150
1 f none /opt/opensvc/lib/rcMounts.py 0644 root root 1933 18912 1302167150
1 f none /opt/opensvc/lib/rcMountsAIX.py 0644 root root 3207 36501 1302167150
1 f none /opt/opensvc/lib/rcMountsDarwin.py 0644 root root 2431 54399 1302167150
1 f none /opt/opensvc/lib/rcMountsFreeBSD.py 0644 root root 2431 54399 1302167150
1 f none /opt/opensvc/lib/rcMountsHP-UX.py 0644 root root 2245 44760 1302167150
1 f none /opt/opensvc/lib/rcMountsLinux.py 0644 root root 2296 48680 1302167150
1 f none /opt/opensvc/lib/rcMountsSunOS.py 0644 root root 1933 18713 1302167150
1 f none /opt/opensvc/lib/rcNode.py 0644 root root 1241 39759 1302167150
1 f none /opt/opensvc/lib/rcOptParser.py 0644 root root 5615 28379 1302167150
1 f none /opt/opensvc/lib/rcPkgAIX.py 0644 root root 1836 15135 1302167150
1 f none /opt/opensvc/lib/rcPkgDarwin.py 0644 root root 1765 10678 1302167150
1 f none /opt/opensvc/lib/rcPkgFreeBSD.py 0644 root root 1324 40953 1302167150
1 f none /opt/opensvc/lib/rcPkgHP-UX.py 0644 root root 1287 37906 1302167150
1 f none /opt/opensvc/lib/rcPkgLinux.py 0644 root root 1833 14723 1302167150
1 f none /opt/opensvc/lib/rcPkgSunOS.py 0644 root root 2338 45249 1302167150
1 f none /opt/opensvc/lib/rcStats.py 0644 root root 3880 34092 1302167150
1 f none /opt/opensvc/lib/rcStatsAIX.py 0644 root root 4852 34525 1302167150
1 f none /opt/opensvc/lib/rcStatsDarwin.py 0644 root root 5464 37215 1302167150
1 f none /opt/opensvc/lib/rcStatsFreeBSD.py 0644 root root 5254 20799 1302167150
1 f none /opt/opensvc/lib/rcStatsHP-UX.py 0644 root root 7658 4693 1302167150
1 f none /opt/opensvc/lib/rcStatsLinux.py 0644 root root 9400 757 1302167150
1 f none /opt/opensvc/lib/rcStatsSunOS.py 0644 root root 6191 18270 1302167150
1 f none /opt/opensvc/lib/rcStatus.py 0644 root root 5827 55477 1302167150
1 f none /opt/opensvc/lib/rcSymmetrix.py 0644 root root 5572 9151 1302167150
1 f none /opt/opensvc/lib/rcUtilities.py 0644 root root 6909 57376 1302167150
1 f none /opt/opensvc/lib/rcUtilitiesAIX.py 0644 root root 321 23163 1302167150
1 f none /opt/opensvc/lib/rcUtilitiesDarwin.py 0644 root root 371 25288 1302167150
1 f none /opt/opensvc/lib/rcUtilitiesFreeBSD.py 0644 root root 325 22467 1302167150
1 f none /opt/opensvc/lib/rcUtilitiesHP-UX.py 0644 root root 257 18122 1302167150
1 f none /opt/opensvc/lib/rcUtilitiesLinux.py 0644 root root 2554 57834 1302167150
1 f none /opt/opensvc/lib/rcUtilitiesSunOS.py 0644 root root 195 14981 1302167150
1 f none /opt/opensvc/lib/rcZfs.py 0644 root root 2267 46171 1302167150
1 f none /opt/opensvc/lib/resApp.py 0644 root root 7980 5289 1302167150
1 f none /opt/opensvc/lib/resAppVm.py 0644 root root 3446 463 1302167150
1 f none /opt/opensvc/lib/resContainer.py 0644 root root 5752 41909 1302167150
1 f none /opt/opensvc/lib/resContainerHpVm.py 0644 root root 3784 28362 1302167150
1 f none /opt/opensvc/lib/resContainerJail.py 0644 root root 3774 22137 1302167150
1 f none /opt/opensvc/lib/resContainerKvm.py 0644 root root 5082 60300 1302167150
1 f none /opt/opensvc/lib/resContainerLdom.py 0644 root root 4856 31033 1302167150
1 f none /opt/opensvc/lib/resContainerLxc.py 0644 root root 5482 59588 1302167150
1 f none /opt/opensvc/lib/resContainerVbox.py 0644 root root 4389 63843 1302167150
1 f none /opt/opensvc/lib/resContainerVz.py 0644 root root 4306 53269 1302167150
1 f none /opt/opensvc/lib/resContainerXen.py 0644 root root 3863 33185 1302167150
1 f none /opt/opensvc/lib/resContainerZone.py 0644 root root 6408 17065 1302167150
1 f none /opt/opensvc/lib/resDg.py 0644 root root 2707 20450 1302167150
1 f none /opt/opensvc/lib/resDrbd.py 0644 root root 6361 18007 1302167150
1 f none /opt/opensvc/lib/resHbLinuxHA.py 0644 root root 2107 38659 1302167150
1 f none /opt/opensvc/lib/resHbOpenHA.py 0644 root root 5179 232 1302167150
1 f none /opt/opensvc/lib/resIp.py 0644 root root 7333 12698 1302167150
1 f none /opt/opensvc/lib/resIpAIX.py 0644 root root 1918 23091 1302167150
1 f none /opt/opensvc/lib/resIpDarwin.py 0644 root root 1926 23304 1302167150
1 f none /opt/opensvc/lib/resIpFreeBSD.py 0644 root root 1926 23304 1302167150
1 f none /opt/opensvc/lib/resIpHP-UX.py 0644 root root 1937 21509 1302167150
1 f none /opt/opensvc/lib/resIpHpVm.py 0644 root root 1512 57538 1302167150
1 f none /opt/opensvc/lib/resIpKvm.py 0644 root root 1495 57174 1302167150
1 f none /opt/opensvc/lib/resIpLdom.py 0644 root root 1513 57650 1302167150
1 f none /opt/opensvc/lib/resIpLinux.py 0644 root root 1859 18556 1302167150
1 f none /opt/opensvc/lib/resIpLinuxLxc.py 0644 root root 1513 57706 1302167150
1 f none /opt/opensvc/lib/resIpSunOS.py 0644 root root 1644 4270 1302167150
1 f none /opt/opensvc/lib/resIpVbox.py 0644 root root 1493 56574 1302167150
1 f none /opt/opensvc/lib/resIpVm.py 0644 root root 2995 39872 1302167150
1 f none /opt/opensvc/lib/resIpXen.py 0644 root root 1552 61367 1302167150
1 f none /opt/opensvc/lib/resIpZone.py 0644 root root 1667 4237 1302167150
1 f none /opt/opensvc/lib/resLoop.py 0644 root root 1839 16266 1302167150
1 f none /opt/opensvc/lib/resLoopFreeBSD.py 0644 root root 3128 44009 1302167150
1 f none /opt/opensvc/lib/resLoopLinux.py 0644 root root 3026 36707 1302167150
1 f none /opt/opensvc/lib/resMount.py 0644 root root 4934 50295 1302167150
1 f none /opt/opensvc/lib/resMountAIX.py 0644 root root 5193 63635 1302167150
1 f none /opt/opensvc/lib/resMountDarwin.py 0644 root root 5527 23122 1302167150
1 f none /opt/opensvc/lib/resMountFreeBSD.py 0644 root root 5527 23122 1302167150
1 f none /opt/opensvc/lib/resMountHP-UX.py 0644 root root 3788 29683 1302167150
1 f none /opt/opensvc/lib/resMountLinux.py 0644 root root 8353 18356 1302167150
1 f none /opt/opensvc/lib/resMountSunOS.py 0644 root root 5352 58633 1302167150
1 f none /opt/opensvc/lib/resScsiReserv.py 0644 root root 6482 21269 1302167150
1 s none /opt/opensvc/lib/resScsiReservFreeBSD.py=resScsiReservLinux.py
1 f none /opt/opensvc/lib/resScsiReservHP-UX.py 0644 root root 5678 38031 1302167150
1 f none /opt/opensvc/lib/resScsiReservLinux.py 0644 root root 4750 35982 1302167150
1 s none /opt/opensvc/lib/resScsiReservSunOS.py=resScsiReservLinux.py
1 f none /opt/opensvc/lib/resSync.py 0644 root root 5373 12042 1302167150
1 f none /opt/opensvc/lib/resSyncDds.py 0644 root root 14900 53961 1302167150
1 f none /opt/opensvc/lib/resSyncEvasnap.py 0644 root root 10635 9562 1302167150
1 f none /opt/opensvc/lib/resSyncNetapp.py 0644 root root 10877 19240 1302167150
1 f none /opt/opensvc/lib/resSyncRsync.py 0644 root root 15177 36318 1302167150
1 f none /opt/opensvc/lib/resSyncSymclone.py 0644 root root 8582 45793 1302167150
1 f none /opt/opensvc/lib/resSyncSymcloneLinux.py 0644 root root 2789 21192 1302167150
1 f none /opt/opensvc/lib/resSyncZfs.py 0644 root root 13705 44428 1302167150
1 f none /opt/opensvc/lib/resVdisk.py 0644 root root 2826 25518 1302167150
1 f none /opt/opensvc/lib/resVgAIX.py 0644 root root 3940 29546 1302167150
1 f none /opt/opensvc/lib/resVgHP-UX.py 0644 root root 8877 40583 1302167150
1 f none /opt/opensvc/lib/resVgHpVm.py 0644 root root 5123 35364 1302167150
1 f none /opt/opensvc/lib/resVgLdom.py 0644 root root 4052 23806 1302167150
1 f none /opt/opensvc/lib/resVgLibvirtVm.py 0644 root root 2346 52054 1302167150
1 f none /opt/opensvc/lib/resVgLinux.py 0644 root root 4809 21923 1302167150
1 f none /opt/opensvc/lib/resVgVeritas.py 0644 root root 4165 40056 1302167150
1 f none /opt/opensvc/lib/resVgZfs.py 0644 root root 5235 40944 1302167150
1 f none /opt/opensvc/lib/resources.py 0644 root root 10727 22317 1302167150
1 f none /opt/opensvc/lib/snap.py 0644 root root 5121 58279 1302167150
1 f none /opt/opensvc/lib/snapJfs2AIX.py 0644 root root 4890 34106 1302167150
1 f none /opt/opensvc/lib/snapLvmLinux.py 0644 root root 3389 759 1302167150
1 f none /opt/opensvc/lib/snapVxfsHP-UX.py 0644 root root 3544 8380 1302167150
1 f none /opt/opensvc/lib/snapZfsSunOS.py 0644 root root 2174 42273 1302167150
1 f none /opt/opensvc/lib/svc.py 0644 root root 36020 63863 1302167150
1 f none /opt/opensvc/lib/svcBuilder.py 0644 root root 51805 49651 1302167150
1 f none /opt/opensvc/lib/svcDict.py 0644 root root 43129 9246 1302167150
1 f none /opt/opensvc/lib/svcHosted.py 0644 root root 1753 7454 1302167150
1 f none /opt/opensvc/lib/svcHpVm.py 0644 root root 1487 60069 1302167150
1 f none /opt/opensvc/lib/svcJail.py 0644 root root 1656 4642 1302167150
1 f none /opt/opensvc/lib/svcKvm.py 0644 root root 1482 59521 1302167150
1 f none /opt/opensvc/lib/svcLdom.py 0644 root root 1487 60075 1302167150
1 f none /opt/opensvc/lib/svcLxc.py 0644 root root 2220 44425 1302167150
1 f none /opt/opensvc/lib/svcVbox.py 0644 root root 1396 50313 1302167150
1 f none /opt/opensvc/lib/svcVz.py 0644 root root 1944 22472 1302167150
1 f none /opt/opensvc/lib/svcXen.py 0644 root root 1440 55428 1302167150
1 f none /opt/opensvc/lib/svcZone.py 0644 root root 4427 21577 1302167150
1 f none /opt/opensvc/lib/version.py 0644 root root 28 1711 1302172757
1 f none /opt/opensvc/lib/xmlrpcClient.py 0644 root root 14406 46837 1302167150
1 d none /opt/opensvc/usr 0755 root root
1 d none /opt/opensvc/usr/share 0755 root root
1 f none /opt/opensvc/usr/share/AUTHORS 0644 root root 48 4634 1302167150
1 f none /opt/opensvc/usr/share/BANNER 0644 root root 830 5155 1302167150
1 f none /opt/opensvc/usr/share/COPYING 0644 root root 26436 9725 1302167150
1 d none /opt/opensvc/usr/share/bash_completion.d 0755 root root
1 f none /opt/opensvc/usr/share/bash_completion.d/opensvc 0644 root root 1489 53839 1302167150
1 d none /opt/opensvc/usr/share/doc 0755 root root
1 f none /opt/opensvc/usr/share/doc/node.conf 0644 root root 2950 39506 1302167150
1 f none /opt/opensvc/usr/share/doc/opensvc.haresource 0644 root root 506 43100 1302167150
1 f none /opt/opensvc/usr/share/doc/template.env 0644 root root 26999 60129 1302167150
1 d none /opt/opensvc/var 0755 root root
1 d none /opt/opensvc/var/compliance 0755 root root
1 f none /opt/opensvc/var/compliance/49-com.opensvc.sys.group 0755 root root 4132 54495 1302167150
1 f none /opt/opensvc/var/compliance/50-com.opensvc.sys.cron 0755 root root 6236 60765 1302167150
1 f none /opt/opensvc/var/compliance/50-com.opensvc.sys.files 0755 root root 6568 31768 1302167150
1 f none /opt/opensvc/var/compliance/50-com.opensvc.sys.packages 0755 root root 3110 44986 1302167150
1 f none /opt/opensvc/var/compliance/50-com.opensvc.sys.user 0755 root root 4229 60500 1302167150
1 f none /opt/opensvc/var/compliance/51-com.opensvc.sys.group.membership 0755 root root 4233 2779 1302167150
1 i pkginfo 220 17768 1302172757
1 i postinstall 302 26825 1302172757
   07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000b00000000TRAILER!!!                                                                                                                                                                                                                070701000671a9000081a40000000000000000000000014d9d9455000000dc000000b600010002ffffffffffffffff0000000800000000pkginfo   PKG=opensvc
NAME=opensvc Service Manager for logical servers v1.0-110407.1239
ARCH=all
VERSION=1.0
CATEGORY=application
VENDOR=http://www.opensvc.com
EMAIL=support@opensvc.com
PSTAMP=OPENSVC-1.0-110407.1239
CLASSES=none
070701000671a8000081a40000000000000000000000014d9d9455000044d9000000b600010002ffffffffffffffff0000000700000000pkgmap    : 1 2605
1 d none /opt/opensvc 0755 root root
1 d none /opt/opensvc/bin 0755 root root
1 s none /opt/opensvc/bin/alldownservices=svcmgr
1 s none /opt/opensvc/bin/allprimaryservices=svcmgr
1 s none /opt/opensvc/bin/allsecondaryservices=svcmgr
1 s none /opt/opensvc/bin/allservices=svcmgr
1 s none /opt/opensvc/bin/allupservices=svcmgr
1 d none /opt/opensvc/bin/cron 0755 root root
1 f none /opt/opensvc/bin/cron/opensvc 0755 root root 1465 58087 1302167150
1 f none /opt/opensvc/bin/freezer 0755 root root 1364 49689 1302167150
1 f none /opt/opensvc/bin/nodemgr 0755 root root 4346 34677 1302167150
1 f none /opt/opensvc/bin/opensvc.init.AIX 0755 root root 209 18797 1302167150
1 f none /opt/opensvc/bin/opensvc.init.Darwin 0644 root root 441 36791 1302167150
1 f none /opt/opensvc/bin/opensvc.init.FreeBSD 0755 root root 300 25712 1302167150
1 f none /opt/opensvc/bin/opensvc.init.SunOS 0755 root root 396 34372 1302167150
1 f none /opt/opensvc/bin/opensvc.init.debian 0755 root root 454 35881 1302167150
1 f none /opt/opensvc/bin/opensvc.init.hpux 0755 root root 738 60175 1302167150
1 f none /opt/opensvc/bin/opensvc.init.redhat 0755 root root 476 40877 1302167150
1 f none /opt/opensvc/bin/perfagt.Darwin 0755 root root 2538 48481 1302167150
1 f none /opt/opensvc/bin/perfagt.HP-UX 0755 root root 3056 32961 1302167150
1 f none /opt/opensvc/bin/perfagt.Linux 0755 root root 859 115 1302167150
1 d none /opt/opensvc/bin/pkg 0755 root root
1 f none /opt/opensvc/bin/pkg/make.lib 0644 root root 1808 2752 1302167150
1 f none /opt/opensvc/bin/pkg/make_deb 0755 root root 889 7276 1302167150
1 f none /opt/opensvc/bin/pkg/make_depot 0755 root root 2513 64216 1302167150
1 f none /opt/opensvc/bin/pkg/make_pkg 0755 root root 4800 35423 1302167150
1 f none /opt/opensvc/bin/pkg/make_rpm 0755 root root 886 9086 1302167150
1 f none /opt/opensvc/bin/pkg/make_tbz 0755 root root 1936 27386 1302167150
1 f none /opt/opensvc/bin/postinstall 0755 root root 15758 57179 1302167150
1 s none /opt/opensvc/bin/svcfreeze=freezer
1 s none /opt/opensvc/bin/svcfrozen=freezer
1 f none /opt/opensvc/bin/svcmgr 0755 root root 7514 36863 1302167150
1 f none /opt/opensvc/bin/svcmon 0755 root root 5396 27364 1302167150
1 s none /opt/opensvc/bin/svcthaw=freezer
1 d none /opt/opensvc/lib 0755 root root
1 f none /opt/opensvc/lib/checkFsInodeDarwin.py 0644 root root 1821 5364 1302167150
1 f none /opt/opensvc/lib/checkFsInodeHP-UX.py 0644 root root 1948 11812 1302167150
1 f none /opt/opensvc/lib/checkFsInodeLinux.py 0644 root root 1752 809 1302167150
1 s none /opt/opensvc/lib/checkFsUsageDarwin.py=checkFsUsageLinux.py
1 s none /opt/opensvc/lib/checkFsUsageFreeBSD.py=checkFsUsageLinux.py
1 f none /opt/opensvc/lib/checkFsUsageHP-UX.py 0644 root root 1889 8251 1302167150
1 f none /opt/opensvc/lib/checkFsUsageLinux.py 0644 root root 1820 5259 1302167150
1 f none /opt/opensvc/lib/checkVgUsageHP-UX.py 0644 root root 2630 64371 1302167150
1 f none /opt/opensvc/lib/checkVgUsageLinux.py 0644 root root 1954 14175 1302167150
1 f none /opt/opensvc/lib/checks.py 0644 root root 2976 17140 1302167150
1 f none /opt/opensvc/lib/compliance.py 0644 root root 14070 35385 1302167150
1 f none /opt/opensvc/lib/freezer.py 0644 root root 1780 9411 1302167150
1 f none /opt/opensvc/lib/hostidAIX.py 0644 root root 1107 26120 1302167150
1 f none /opt/opensvc/lib/hostidDarwin.py 0644 root root 888 9879 1302167150
1 s none /opt/opensvc/lib/hostidFreeBSD.py=hostidLinux.py
1 f none /opt/opensvc/lib/hostidHP-UX.py 0644 root root 1203 33767 1302167150
1 f none /opt/opensvc/lib/hostidLinux.py 0644 root root 888 9879 1302167150
1 f none /opt/opensvc/lib/hostidSunOS.py 0644 root root 888 9879 1302167150
1 f none /opt/opensvc/lib/lock.py 0644 root root 2810 17169 1302167150
1 f none /opt/opensvc/lib/loopSunOS.py 0644 root root 1439 52901 1302167150
1 f none /opt/opensvc/lib/node.py 0644 root root 22996 10909 1302167150
1 f none /opt/opensvc/lib/rcAddService.py 0644 root root 911 11569 1302167150
1 f none /opt/opensvc/lib/rcAsset.py 0644 root root 4847 42998 1302167150
1 f none /opt/opensvc/lib/rcAssetDarwin.py 0644 root root 3016 32180 1302167150
1 f none /opt/opensvc/lib/rcAssetFreeBSD.py 0644 root root 2470 53042 1302167150
1 f none /opt/opensvc/lib/rcAssetHP-UX.py 0644 root root 5880 14705 1302167150
1 f none /opt/opensvc/lib/rcAssetLinux.py 0644 root root 6526 55189 1302167150
1 f none /opt/opensvc/lib/rcAssetSunOS.py 0644 root root 3488 57771 1302167150
1 f none /opt/opensvc/lib/rcContainerLinux.py 0644 root root 5005 5438 1302167150
1 f none /opt/opensvc/lib/rcDiskInfo.py 0644 root root 1116 26183 1302167150
1 f none /opt/opensvc/lib/rcDiskInfoAIX.py 0644 root root 2372 50045 1302167150
1 f none /opt/opensvc/lib/rcDiskInfoDarwin.py 0644 root root 888 9990 1302167150
1 f none /opt/opensvc/lib/rcDiskInfoFreeBSD.py 0644 root root 1324 42833 1302167150
1 f none /opt/opensvc/lib/rcDiskInfoHP-UX.py 0644 root root 2946 21581 1302167150
1 f none /opt/opensvc/lib/rcDiskInfoLinux.py 0644 root root 3111 26273 1302167150
1 f none /opt/opensvc/lib/rcDiskInfoSunOS.py 0644 root root 888 9990 1302167150
1 f none /opt/opensvc/lib/rcExceptions.py 0644 root root 3442 19588 1302167150
1 f none /opt/opensvc/lib/rcFunctions.py 0644 root root 1284 40612 1302167150
1 f none /opt/opensvc/lib/rcGlobalEnv.py 0644 root root 5663 45699 1302167150
1 f none /opt/opensvc/lib/rcIfconfig.py 0644 root root 4124 44119 1302167150
1 f none /opt/opensvc/lib/rcIfconfigAIX.py 0644 root root 2810 69 1302167150
1 f none /opt/opensvc/lib/rcIfconfigDarwin.py 0644 root root 2631 51701 1302167150
1 f none /opt/opensvc/lib/rcIfconfigFreeBSD.py 0644 root root 2631 51701 1302167150
1 s none /opt/opensvc/lib/rcIfconfigFreeBSDhpvm.py=rcIfconfigFreeBSDkvm.py
1 f none /opt/opensvc/lib/rcIfconfigFreeBSDkvm.py 0644 root root 1266 39292 1302167150
1 s none /opt/opensvc/lib/rcIfconfigFreeBSDldom.py=rcIfconfigFreeBSDkvm.py
1 s none /opt/opensvc/lib/rcIfconfigFreeBSDxen.py=rcIfconfigFreeBSDkvm.py
1 f none /opt/opensvc/lib/rcIfconfigHP-UX.py 0644 root root 3126 21426 1302167150
1 f none /opt/opensvc/lib/rcIfconfigHP-UXhpvm.py 0644 root root 1745 5967 1302167150
1 f none /opt/opensvc/lib/rcIfconfigLinux.py 0644 root root 2878 1079 1302167150
1 s none /opt/opensvc/lib/rcIfconfigLinuxhpvm.py=rcIfconfigLinuxkvm.py
1 f none /opt/opensvc/lib/rcIfconfigLinuxkvm.py 0644 root root 1281 40272 1302167150
1 s none /opt/opensvc/lib/rcIfconfigLinuxldom.py=rcIfconfigLinuxkvm.py
1 f none /opt/opensvc/lib/rcIfconfigLinuxlxc.py 0644 root root 1563 61073 1302167150
1 f none /opt/opensvc/lib/rcIfconfigLinuxvz.py 0644 root root 1118 27400 1302167150
1 f none /opt/opensvc/lib/rcIfconfigSunOS.py 0644 root root 2855 1531 1302167150
1 s none /opt/opensvc/lib/rcIfconfigSunOSkvm.py=rcIfconfigSunOSldom.py
1 f none /opt/opensvc/lib/rcIfconfigSunOSldom.py 0644 root root 1281 40216 1302167150
1 s none /opt/opensvc/lib/rcIfconfigSunOSxen.py=rcIfconfigSunOSldom.py
1 f none /opt/opensvc/lib/rcIfconfigWindowskvm.py 0644 root root 1096 27277 1302167150
1 f none /opt/opensvc/lib/rcLogger.py 0644 root root 2265 47689 1302167150
1 f none /opt/opensvc/lib/rcMounts.py 0644 root root 1933 18912 1302167150
1 f none /opt/opensvc/lib/rcMountsAIX.py 0644 root root 3207 36501 1302167150
1 f none /opt/opensvc/lib/rcMountsDarwin.py 0644 root root 2431 54399 1302167150
1 f none /opt/opensvc/lib/rcMountsFreeBSD.py 0644 root root 2431 54399 1302167150
1 f none /opt/opensvc/lib/rcMountsHP-UX.py 0644 root root 2245 44760 1302167150
1 f none /opt/opensvc/lib/rcMountsLinux.py 0644 root root 2296 48680 1302167150
1 f none /opt/opensvc/lib/rcMountsSunOS.py 0644 root root 1933 18713 1302167150
1 f none /opt/opensvc/lib/rcNode.py 0644 root root 1241 39759 1302167150
1 f none /opt/opensvc/lib/rcOptParser.py 0644 root root 5615 28379 1302167150
1 f none /opt/opensvc/lib/rcPkgAIX.py 0644 root root 1836 15135 1302167150
1 f none /opt/opensvc/lib/rcPkgDarwin.py 0644 root root 1765 10678 1302167150
1 f none /opt/opensvc/lib/rcPkgFreeBSD.py 0644 root root 1324 40953 1302167150
1 f none /opt/opensvc/lib/rcPkgHP-UX.py 0644 root root 1287 37906 1302167150
1 f none /opt/opensvc/lib/rcPkgLinux.py 0644 root root 1833 14723 1302167150
1 f none /opt/opensvc/lib/rcPkgSunOS.py 0644 root root 2338 45249 1302167150
1 f none /opt/opensvc/lib/rcStats.py 0644 root root 3880 34092 1302167150
1 f none /opt/opensvc/lib/rcStatsAIX.py 0644 root root 4852 34525 1302167150
1 f none /opt/opensvc/lib/rcStatsDarwin.py 0644 root root 5464 37215 1302167150
1 f none /opt/opensvc/lib/rcStatsFreeBSD.py 0644 root root 5254 20799 1302167150
1 f none /opt/opensvc/lib/rcStatsHP-UX.py 0644 root root 7658 4693 1302167150
1 f none /opt/opensvc/lib/rcStatsLinux.py 0644 root root 9400 757 1302167150
1 f none /opt/opensvc/lib/rcStatsSunOS.py 0644 root root 6191 18270 1302167150
1 f none /opt/opensvc/lib/rcStatus.py 0644 root root 5827 55477 1302167150
1 f none /opt/opensvc/lib/rcSymmetrix.py 0644 root root 5572 9151 1302167150
1 f none /opt/opensvc/lib/rcUtilities.py 0644 root root 6909 57376 1302167150
1 f none /opt/opensvc/lib/rcUtilitiesAIX.py 0644 root root 321 23163 1302167150
1 f none /opt/opensvc/lib/rcUtilitiesDarwin.py 0644 root root 371 25288 1302167150
1 f none /opt/opensvc/lib/rcUtilitiesFreeBSD.py 0644 root root 325 22467 1302167150
1 f none /opt/opensvc/lib/rcUtilitiesHP-UX.py 0644 root root 257 18122 1302167150
1 f none /opt/opensvc/lib/rcUtilitiesLinux.py 0644 root root 2554 57834 1302167150
1 f none /opt/opensvc/lib/rcUtilitiesSunOS.py 0644 root root 195 14981 1302167150
1 f none /opt/opensvc/lib/rcZfs.py 0644 root root 2267 46171 1302167150
1 f none /opt/opensvc/lib/resApp.py 0644 root root 7980 5289 1302167150
1 f none /opt/opensvc/lib/resAppVm.py 0644 root root 3446 463 1302167150
1 f none /opt/opensvc/lib/resContainer.py 0644 root root 5752 41909 1302167150
1 f none /opt/opensvc/lib/resContainerHpVm.py 0644 root root 3784 28362 1302167150
1 f none /opt/opensvc/lib/resContainerJail.py 0644 root root 3774 22137 1302167150
1 f none /opt/opensvc/lib/resContainerKvm.py 0644 root root 5082 60300 1302167150
1 f none /opt/opensvc/lib/resContainerLdom.py 0644 root root 4856 31033 1302167150
1 f none /opt/opensvc/lib/resContainerLxc.py 0644 root root 5482 59588 1302167150
1 f none /opt/opensvc/lib/resContainerVbox.py 0644 root root 4389 63843 1302167150
1 f none /opt/opensvc/lib/resContainerVz.py 0644 root root 4306 53269 1302167150
1 f none /opt/opensvc/lib/resContainerXen.py 0644 root root 3863 33185 1302167150
1 f none /opt/opensvc/lib/resContainerZone.py 0644 root root 6408 17065 1302167150
1 f none /opt/opensvc/lib/resDg.py 0644 root root 2707 20450 1302167150
1 f none /opt/opensvc/lib/resDrbd.py 0644 root root 6361 18007 1302167150
1 f none /opt/opensvc/lib/resHbLinuxHA.py 0644 root root 2107 38659 1302167150
1 f none /opt/opensvc/lib/resHbOpenHA.py 0644 root root 5179 232 1302167150
1 f none /opt/opensvc/lib/resIp.py 0644 root root 7333 12698 1302167150
1 f none /opt/opensvc/lib/resIpAIX.py 0644 root root 1918 23091 1302167150
1 f none /opt/opensvc/lib/resIpDarwin.py 0644 root root 1926 23304 1302167150
1 f none /opt/opensvc/lib/resIpFreeBSD.py 0644 root root 1926 23304 1302167150
1 f none /opt/opensvc/lib/resIpHP-UX.py 0644 root root 1937 21509 1302167150
1 f none /opt/opensvc/lib/resIpHpVm.py 0644 root root 1512 57538 1302167150
1 f none /opt/opensvc/lib/resIpKvm.py 0644 root root 1495 57174 1302167150
1 f none /opt/opensvc/lib/resIpLdom.py 0644 root root 1513 57650 1302167150
1 f none /opt/opensvc/lib/resIpLinux.py 0644 root root 1859 18556 1302167150
1 f none /opt/opensvc/lib/resIpLinuxLxc.py 0644 root root 1513 57706 1302167150
1 f none /opt/opensvc/lib/resIpSunOS.py 0644 root root 1644 4270 1302167150
1 f none /opt/opensvc/lib/resIpVbox.py 0644 root root 1493 56574 1302167150
1 f none /opt/opensvc/lib/resIpVm.py 0644 root root 2995 39872 1302167150
1 f none /opt/opensvc/lib/resIpXen.py 0644 root root 1552 61367 1302167150
1 f none /opt/opensvc/lib/resIpZone.py 0644 root root 1667 4237 1302167150
1 f none /opt/opensvc/lib/resLoop.py 0644 root root 1839 16266 1302167150
1 f none /opt/opensvc/lib/resLoopFreeBSD.py 0644 root root 3128 44009 1302167150
1 f none /opt/opensvc/lib/resLoopLinux.py 0644 root root 3026 36707 1302167150
1 f none /opt/opensvc/lib/resMount.py 0644 root root 4934 50295 1302167150
1 f none /opt/opensvc/lib/resMountAIX.py 0644 root root 5193 63635 1302167150
1 f none /opt/opensvc/lib/resMountDarwin.py 0644 root root 5527 23122 1302167150
1 f none /opt/opensvc/lib/resMountFreeBSD.py 0644 root root 5527 23122 1302167150
1 f none /opt/opensvc/lib/resMountHP-UX.py 0644 root root 3788 29683 1302167150
1 f none /opt/opensvc/lib/resMountLinux.py 0644 root root 8353 18356 1302167150
1 f none /opt/opensvc/lib/resMountSunOS.py 0644 root root 5352 58633 1302167150
1 f none /opt/opensvc/lib/resScsiReserv.py 0644 root root 6482 21269 1302167150
1 s none /opt/opensvc/lib/resScsiReservFreeBSD.py=resScsiReservLinux.py
1 f none /opt/opensvc/lib/resScsiReservHP-UX.py 0644 root root 5678 38031 1302167150
1 f none /opt/opensvc/lib/resScsiReservLinux.py 0644 root root 4750 35982 1302167150
1 s none /opt/opensvc/lib/resScsiReservSunOS.py=resScsiReservLinux.py
1 f none /opt/opensvc/lib/resSync.py 0644 root root 5373 12042 1302167150
1 f none /opt/opensvc/lib/resSyncDds.py 0644 root root 14900 53961 1302167150
1 f none /opt/opensvc/lib/resSyncEvasnap.py 0644 root root 10635 9562 1302167150
1 f none /opt/opensvc/lib/resSyncNetapp.py 0644 root root 10877 19240 1302167150
1 f none /opt/opensvc/lib/resSyncRsync.py 0644 root root 15177 36318 1302167150
1 f none /opt/opensvc/lib/resSyncSymclone.py 0644 root root 8582 45793 1302167150
1 f none /opt/opensvc/lib/resSyncSymcloneLinux.py 0644 root root 2789 21192 1302167150
1 f none /opt/opensvc/lib/resSyncZfs.py 0644 root root 13705 44428 1302167150
1 f none /opt/opensvc/lib/resVdisk.py 0644 root root 2826 25518 1302167150
1 f none /opt/opensvc/lib/resVgAIX.py 0644 root root 3940 29546 1302167150
1 f none /opt/opensvc/lib/resVgHP-UX.py 0644 root root 8877 40583 1302167150
1 f none /opt/opensvc/lib/resVgHpVm.py 0644 root root 5123 35364 1302167150
1 f none /opt/opensvc/lib/resVgLdom.py 0644 root root 4052 23806 1302167150
1 f none /opt/opensvc/lib/resVgLibvirtVm.py 0644 root root 2346 52054 1302167150
1 f none /opt/opensvc/lib/resVgLinux.py 0644 root root 4809 21923 1302167150
1 f none /opt/opensvc/lib/resVgVeritas.py 0644 root root 4165 40056 1302167150
1 f none /opt/opensvc/lib/resVgZfs.py 0644 root root 5235 40944 1302167150
1 f none /opt/opensvc/lib/resources.py 0644 root root 10727 22317 1302167150
1 f none /opt/opensvc/lib/snap.py 0644 root root 5121 58279 1302167150
1 f none /opt/opensvc/lib/snapJfs2AIX.py 0644 root root 4890 34106 1302167150
1 f none /opt/opensvc/lib/snapLvmLinux.py 0644 root root 3389 759 1302167150
1 f none /opt/opensvc/lib/snapVxfsHP-UX.py 0644 root root 3544 8380 1302167150
1 f none /opt/opensvc/lib/snapZfsSunOS.py 0644 root root 2174 42273 1302167150
1 f none /opt/opensvc/lib/svc.py 0644 root root 36020 63863 1302167150
1 f none /opt/opensvc/lib/svcBuilder.py 0644 root root 51805 49651 1302167150
1 f none /opt/opensvc/lib/svcDict.py 0644 root root 43129 9246 1302167150
1 f none /opt/opensvc/lib/svcHosted.py 0644 root root 1753 7454 1302167150
1 f none /opt/opensvc/lib/svcHpVm.py 0644 root root 1487 60069 1302167150
1 f none /opt/opensvc/lib/svcJail.py 0644 root root 1656 4642 1302167150
1 f none /opt/opensvc/lib/svcKvm.py 0644 root root 1482 59521 1302167150
1 f none /opt/opensvc/lib/svcLdom.py 0644 root root 1487 60075 1302167150
1 f none /opt/opensvc/lib/svcLxc.py 0644 root root 2220 44425 1302167150
1 f none /opt/opensvc/lib/svcVbox.py 0644 root root 1396 50313 1302167150
1 f none /opt/opensvc/lib/svcVz.py 0644 root root 1944 22472 1302167150
1 f none /opt/opensvc/lib/svcXen.py 0644 root root 1440 55428 1302167150
1 f none /opt/opensvc/lib/svcZone.py 0644 root root 4427 21577 1302167150
1 f none /opt/opensvc/lib/version.py 0644 root root 28 1711 1302172757
1 f none /opt/opensvc/lib/xmlrpcClient.py 0644 root root 14406 46837 1302167150
1 d none /opt/opensvc/usr 0755 root root
1 d none /opt/opensvc/usr/share 0755 root root
1 f none /opt/opensvc/usr/share/AUTHORS 0644 root root 48 4634 1302167150
1 f none /opt/opensvc/usr/share/BANNER 0644 root root 830 5155 1302167150
1 f none /opt/opensvc/usr/share/COPYING 0644 root root 26436 9725 1302167150
1 d none /opt/opensvc/usr/share/bash_completion.d 0755 root root
1 f none /opt/opensvc/usr/share/bash_completion.d/opensvc 0644 root root 1489 53839 1302167150
1 d none /opt/opensvc/usr/share/doc 0755 root root
1 f none /opt/opensvc/usr/share/doc/node.conf 0644 root root 2950 39506 1302167150
1 f none /opt/opensvc/usr/share/doc/opensvc.haresource 0644 root root 506 43100 1302167150
1 f none /opt/opensvc/usr/share/doc/template.env 0644 root root 26999 60129 1302167150
1 d none /opt/opensvc/var 0755 root root
1 d none /opt/opensvc/var/compliance 0755 root root
1 f none /opt/opensvc/var/compliance/49-com.opensvc.sys.group 0755 root root 4132 54495 1302167150
1 f none /opt/opensvc/var/compliance/50-com.opensvc.sys.cron 0755 root root 6236 60765 1302167150
1 f none /opt/opensvc/var/compliance/50-com.opensvc.sys.files 0755 root root 6568 31768 1302167150
1 f none /opt/opensvc/var/compliance/50-com.opensvc.sys.packages 0755 root root 3110 44986 1302167150
1 f none /opt/opensvc/var/compliance/50-com.opensvc.sys.user 0755 root root 4229 60500 1302167150
1 f none /opt/opensvc/var/compliance/51-com.opensvc.sys.group.membership 0755 root root 4233 2779 1302167150
1 i pkginfo 220 17768 1302172757
1 i postinstall 302 26825 1302172757
   0707010006727f000041ed0000000000000000000000024d9d945500000000000000b600010002ffffffffffffffff0000000800000000install   07070100067280000081a40000000000000000000000014d9d94550000012e000000b600010002ffffffffffffffff0000001400000000install/postinstall   #!/sbin/sh

su - root -c "LD_LIBRARY_PATH=/opt/opensvc/usr/local/lib:$LD_LIBRARY_PATH PATH=/opt/opensvc/usr/local/bin:/opt/opensvc:/usr/gnu/bin:/usr/bin:/usr/X11/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/opensvc/bin:/opt/opensvc/etc:/opt/sfw/bin:/usr/sfw/bin:/usr/local/bin /opt/opensvc/bin/postinstall"
  070701000671aa000041ed0000000000000000000000034d9d945500000000000000b600010002ffffffffffffffff0000000500000000root  070701000671ab000041ed0000000000000000000000034d9d945500000000000000b600010002ffffffffffffffff0000000900000000root/opt  070701000671ac000041ed0000000000000000000000064d9d945500000000000000b600010002ffffffffffffffff0000001100000000root/opt/opensvc  0707010006726c000041ed0000000000000000000000034d9d945500000000000000b600010002ffffffffffffffff0000001500000000root/opt/opensvc/usr  0707010006726d000041ed0000000000000000000000044d9d945500000000000000b600010002ffffffffffffffff0000001b00000000root/opt/opensvc/usr/share    07070100067270000081a40000000000000000000000014d9d7e6e00006744000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/usr/share/COPYING    		  GNU LESSER GENERAL PUBLIC LICENSE
		       Version 2.1, February 1999

 Copyright (C) 1991, 1999 Free Software Foundation, Inc.
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

[This is the first released version of the Lesser GPL.  It also counts
 as the successor of the GNU Library Public License, version 2, hence
 the version number 2.1.]

			    Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.

  This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it.  You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.

  When we speak of free software, we are referring to freedom of use,
not price.  Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.

  To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights.  These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.

  For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you.  You must make sure that they, too, receive or can get the source
code.  If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it.  And you must show them these terms so they know their rights.

  We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.

  To protect each distributor, we want to make it very clear that
there is no warranty for the free library.  Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.

  Finally, software patents pose a constant threat to the existence of
any free program.  We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder.  Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.

  Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License.  This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License.  We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.

  When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library.  The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom.  The Lesser General
Public License permits more lax criteria for linking other code with
the library.

  We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License.  It also provides other free software developers Less
of an advantage over competing non-free programs.  These disadvantages
are the reason we use the ordinary General Public License for many
libraries.  However, the Lesser license provides advantages in certain
special circumstances.

  For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard.  To achieve this, non-free programs must be
allowed to use the library.  A more frequent case is that a free
library does the same job as widely used non-free libraries.  In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.

  In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software.  For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.

  Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.

  The precise terms and conditions for copying, distribution and
modification follow.  Pay close attention to the difference between a
"work based on the library" and a "work that uses the library".  The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.

		  GNU LESSER GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".

  A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.

  The "Library", below, refers to any such software library or work
which has been distributed under these terms.  A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language.  (Hereinafter, translation is
included without limitation in the term "modification".)

  "Source code" for a work means the preferred form of the work for
making modifications to it.  For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.

  Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it).  Whether that is true depends on what the Library does
and what the program that uses the Library does.
  
  1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.

  You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.

  2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) The modified work must itself be a software library.

    b) You must cause the files modified to carry prominent notices
    stating that you changed the files and the date of any change.

    c) You must cause the whole of the work to be licensed at no
    charge to all third parties under the terms of this License.

    d) If a facility in the modified Library refers to a function or a
    table of data to be supplied by an application program that uses
    the facility, other than as an argument passed when the facility
    is invoked, then you must make a good faith effort to ensure that,
    in the event an application does not supply such function or
    table, the facility still operates, and performs whatever part of
    its purpose remains meaningful.

    (For example, a function in a library to compute square roots has
    a purpose that is entirely well-defined independent of the
    application.  Therefore, Subsection 2d requires that any
    application-supplied function or table used by this function must
    be optional: if the application does not supply it, the square
    root function must still compute square roots.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.

In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library.  To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License.  (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.)  Do not make any other change in
these notices.

  Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.

  This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.

  4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.

  If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.

  5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library".  Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.

  However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library".  The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.

  When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library.  The
threshold for this to be true is not precisely defined by law.

  If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work.  (Executables containing this object code plus portions of the
Library will still fall under Section 6.)

  Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.

  6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.

  You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License.  You must supply a copy of this License.  If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License.  Also, you must do one
of these things:

    a) Accompany the work with the complete corresponding
    machine-readable source code for the Library including whatever
    changes were used in the work (which must be distributed under
    Sections 1 and 2 above); and, if the work is an executable linked
    with the Library, with the complete machine-readable "work that
    uses the Library", as object code and/or source code, so that the
    user can modify the Library and then relink to produce a modified
    executable containing the modified Library.  (It is understood
    that the user who changes the contents of definitions files in the
    Library will not necessarily be able to recompile the application
    to use the modified definitions.)

    b) Use a suitable shared library mechanism for linking with the
    Library.  A suitable mechanism is one that (1) uses at run time a
    copy of the library already present on the user's computer system,
    rather than copying library functions into the executable, and (2)
    will operate properly with a modified version of the library, if
    the user installs one, as long as the modified version is
    interface-compatible with the version that the work was made with.

    c) Accompany the work with a written offer, valid for at
    least three years, to give the same user the materials
    specified in Subsection 6a, above, for a charge no more
    than the cost of performing this distribution.

    d) If distribution of the work is made by offering access to copy
    from a designated place, offer equivalent access to copy the above
    specified materials from the same place.

    e) Verify that the user has already received a copy of these
    materials or that you have already sent this user a copy.

  For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it.  However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.

  It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system.  Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.

  7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:

    a) Accompany the combined library with a copy of the same work
    based on the Library, uncombined with any other library
    facilities.  This must be distributed under the terms of the
    Sections above.

    b) Give prominent notice with the combined library of the fact
    that part of it is a work based on the Library, and explaining
    where to find the accompanying uncombined form of the same work.

  8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License.  Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License.  However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.

  9. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Library or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.

  10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.

  11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all.  For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.

If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded.  In such case, this License incorporates the limitation as if
written in the body of this License.

  13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number.  If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation.  If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.

  14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission.  For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this.  Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.

			    NO WARRANTY

  15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU.  SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

  16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.

		     END OF TERMS AND CONDITIONS

           How to Apply These Terms to Your New Libraries

  If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change.  You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).

  To apply these terms, attach the following notices to the library.  It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.

    <one line to give the library's name and a brief idea of what it does.>
    Copyright (C) <year>  <name of author>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

Also add information on how to contact you by electronic and paper mail.

You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary.  Here is a sample; alter the names:

  Yoyodyne, Inc., hereby disclaims all copyright interest in the
  library `Frob' (a library for tweaking knobs) written by James Random Hacker.

  <signature of Ty Coon>, 1 April 1990
  Ty Coon, President of Vice

That's all there is to it!


07070100067271000041ed0000000000000000000000024d9d945500000000000000b600010002ffffffffffffffff0000002d00000000root/opt/opensvc/usr/share/bash_completion.d  07070100067272000081a40000000000000000000000014d9d7e6e000005d1000000b600010002ffffffffffffffff0000003500000000root/opt/opensvc/usr/share/bash_completion.d/opensvc  svcs=$(ls /opt/opensvc/etc/*env 2>/dev/null|xargs -n1 basename 2>/dev/null|sed -e "s/.env//")

service_opts="configure create disklist freeze frozen mount postsync presync print_status printsvc prstart prstatus prstop push restart start startapp startcontainer startdisk startip startloop startpool startstandby startvg status stop stopapp stopcontainer stopdisk stopip stoploop stoppool stopvg syncall syncbreak syncdrp syncfullsync syncnodes syncquiesce syncresync syncupdate syncverify thaw umount --force --waitlock --debug --rid --tags"

svcmgr_opts="$service_opts --service"

_svcmgr() 
{
    local cur prev base
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"

    #
    #  Complete the arguments to some of the basic commands.
    #
    case "${prev}" in
	--tags)
	    local tags=$(grep -h "tag" /opt/opensvc/etc/*env|cut -d= -f2)
	    COMPREPLY=( $(compgen -W "${tags}" -- ${cur}) )
            return 0
            ;;
        --rid)
	    local rid=$(grep -h "\[.*\]" /opt/opensvc/etc/*env|sed -e "s/\[//"|sed -e "s/\]//")
	    COMPREPLY=( $(compgen -W "${rid}" -- ${cur}) )
            return 0
            ;;
        --service)
	    COMPREPLY=( $(compgen -W "${svcs}" -- ${cur}) )
            return 0
            ;;
        *)
        ;;
    esac

   COMPREPLY=($(compgen -W "${opts}" -- ${cur}))  
   return 0
}

opts=$svcmgr_opts
complete -F _svcmgr svcmgr

opts=$service_opts
for s in ${svcs} ; do
    complete -F _svcmgr $s
done
   0707010006726e000081a40000000000000000000000014d9d7e6e00000030000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/usr/share/AUTHORS    Christophe Varoqui <christophe.varoqui@free.fr>
07070100067273000041ed0000000000000000000000024d9d945500000000000000b600010002ffffffffffffffff0000001f00000000root/opt/opensvc/usr/share/doc    07070100067274000081a40000000000000000000000014d9d7e6e00000b86000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/usr/share/doc/node.conf  #
# Template etc/node.conf
#
#   This configuration file describes node-wide parameters.
#
#   The interval-days-period tuple is used to tune the schedule of
#   jobs run by the 'opensvc' cron-job.
#
#   This file can be left empty except for node.host_mode. The sync
#   schedule is autogenerated, based on the schedules described in the
#   sync#* resources defined in the service configurations. So no
#   sync schedule should be explicitely defined here.
#
#   The internal schedule defaults for sync and push* actions are:
#     days:     all
#     period:   4am to 6am
#     interval: 1 day
#
#   The internal schedule defaults for 'compliance check' action are:
#     days:     sunday
#     period:   5am to 6am
#     interval: 1 week
#
#   Schedule parameters details:
#     interval
#        type: integer
#        unit: minutes
#     days
#        type: json list
#        unit: weekday in C locale (%A)
#     period
#        type: json list or list of list
#        unit: %H:%M
#

[node]
#
# A PRD host mode will only allow PRD services to run. A not-PRD mode
# allows any service to run.
#
;host_mode = DEV

#
# The team responsible set here will be pushed to the collector's asset
# table. An admin allowed to edit opensvc configuration files on a node
# can set this team_responsible and gain the edit privilege on the asset
# in the collector.
#
;team_responsible = Homies

#
# You can optionally define asset information. They will be pushed to the
# collector, so that the compliance ruleset can use this information just
# after opensvc is bootstraped.
#
# A postinstall workflow would look like this: 
#
#   vanilla install
#   install opensvc
#   nodemgr set --param node.loc_city = Paris
#   nodemgr set --param node.team_responsible = Homies
#   nodemgr pushasset --force
#   nodemgr compliance attach moduleset --moduleset sys.core
#   nodemgr compliance fix
#
;loc_country = France
;loc_city = Paris
;loc_zip = 75017
;loc_addr = 7 rue blanche
;loc_building = crystal
;loc_floor = 21
;loc_room = 102
;loc_rack = R42

#
# Schedule parameters for the 'compliance check' node action
#
[compliance]
;interval = 1439
;period = ["00:00", "23:59"]
;days = ["saturday", "sunday"]

[stats]
;interval = 30
;period = [["04:00", "08:00"], ["23:00", "01:30"]]
;days = ["saturday", "sunday"]

[checks]
;interval = 120
;period = [["04:00", "08:00"], ["23:00", "01:30"]]
;days = ["saturday", "sunday"]

[packages]
;interval = 120
;period = [["04:00", "08:00"], ["23:00", "01:30"]]
;days = ["saturday", "sunday"]

[patches]
;interval = 120
;period = [["04:00", "08:00"], ["23:00", "01:30"]]
;days = ["saturday", "sunday"]

[asset]
;interval = 120
;period = [["04:00", "08:00"], ["23:00", "01:30"]]
;days = ["saturday", "sunday"]

[sym]
;interval = 120
;period = [["04:00", "08:00"], ["23:00", "01:30"]]
;days = ["saturday", "sunday"]

[svcconf]
;interval = 120
;period = [["04:00", "08:00"], ["23:00", "01:30"]]
;days = ["saturday", "sunday"]

  07070100067275000081a40000000000000000000000014d9d7e6e000001fa000000b600010002ffffffffffffffff0000003200000000root/opt/opensvc/usr/share/doc/opensvc.haresource #!/bin/sh -e
#
# This script is to be copied to /etc/ha.d/resource.d/ in
# LinuxHA cluster setup and referenced in /etc/ha.d/haresources
# with the line:
#
# node1 opensvc MailTo::root@localhost::Alert_Cluster_Failover
#
# (replace node1 with the appropriate node name)
#

osvc_path=/opt/opensvc/bin
osvc_opts="--parallel --cluster"
allservices=${osvc_path}/allservices

case $1 in
start)
        ${allservices} ${osvc_opts} start
        ;;
stop)
        ${allservices} ${osvc_opts} stop
        ;;
esac

  07070100067276000081a40000000000000000000000014d9d7e6e00006977000000b600010002ffffffffffffffff0000002c00000000root/opt/opensvc/usr/share/doc/template.env   #
# OpenSVC config files are written in standard ini file format:
#
# "The configuration file consists of sections, led by a [section] header and
# followed by name: value entries, with continuations in the style of RFC 822
# (see section 3.1.1, “LONG HEADER FIELDS”); name=value is also accepted. Note
# that leading whitespace is removed from values.
# Lines beginning with '#' or ';' are ignored and may be used to provide
# comments."
#               extract from http://docs.python.org/library/configparser.html
#
# Resource are label [resource_name#index_in_resourse_set], like [ip#1],
# [ip#2], [fs#1], [fs#2]...
#
# Every resource accept these options:
# 'disable'
#   optional. Possible values are 'true' or 'false'.
#   A disabled resource will be ignored on service startup and shutdown.
#
# 'disable_on'
#   optional. A list of nodenames where to consider the 'disable' value is
#   True.
#
# 'optional'
#   optional. Possible values are 'true' or 'false'.
#   Actions on resource will be tried upon service startup and shutdown,
#   but action failures will be logged and passed over. Useful for resources
#   like dump filesystems for example.
#
# Every service config file must have a DEFAULT section.
#

##############################################################################
#
# Main service definition
#
##############################################################################

[DEFAULT]
#
# 'app'
#   is used to identify who is responsible for is service, who is billable
#   and provides a most useful filtering key. Better keep it a short code.
#
;app = OSVC

#
# 'comment'
#   is optional, but helps users understand the role of the service, 
#   which is nice to on-call support people having to operate on a
#   service they are usualy responsible for.
#
;comment = opensvc web front-end

#
# 'mode'
#   supported modes are 'lxc', 'zone', 'kvm', 'ldom', 'xen', 'hpvm' or
#   'hosted'. The default is 'hosted'.
#   the mode decides upon disposition OpenSVC takes to bring a service up
#   or down : virtualized services need special actions to prepare and boot
#   the container for example, which is not needed for 'hosted' services.
#
;mode = lxc

#
# 'drp_type'
#   supported values are 'standby' or 'srdf'. The default is 'standby'.
#   Not used for the moment.
#
;drp_type = standby

#
# 'service_type'
#   supported values are 'DEV' and 'PRD'. There is no default, and this
#   setting is mandatory, as important rules apply to it :
#   1/ a DEV service can not be brought up on a PRD node, but a PRD service
#      can be startup on a DEV node (in a DRP situation).
#
;service_type = DEV

#
# 'nodes'
#   mandatory list of cluster nodes able to start the service when not in
#   a DRP situation
#
;nodes =  zezette

#
# 'autostart_node'
#   A subset of 'nodes' where the service will try to start on upon node
#   reboot. On a failover cluster only one autostart_node should be
#   defined, and the start-up will fail if the service is already up on another
#   node.
#   If not specified, the service will never be started at node boot-time,
#   which is rarely the expected behaviour.
#
;autostart_node = zezette

#
# 'cluster_type'
#   Optional. Defaults to 'failover'.
#   Allowed values:
#
#   'failover'
#      The service can be up only on one node at a time. 
#
#   'flex'
#      The service can be up on multiple nodes simultaneously.
#
#   'autoflex'
#      Like flex, and allows the collector to start and stop instances.
#
#
;cluster_type = failover

#
# 'flex_primary'
#   the nodename of the node allowed to sync to other flex nodes.
#
;flex_primary = zezette

#
# 'flex_min_nodes'
#   Default: 1
#   the minimum number of nodes where the service should be up.
#   Alerts are raised on the collector upon crossing this limit.
#   On autoflex, the collector would not trigger actions that would
#   put the service out of bounds.
#
;flex_min_nodes = 1

#
# 'flex_max_nodes'
#   Default: the total number of nodes
#   the maximum number of nodes where the service should be up.
#   Alerts are raised on the collector upon crossing this limit.
#   On autoflex, the collector would not trigger actions that would
#   put the service out of bounds.
#
;flex_max_nodes = 10

#
# 'flex_cpu_low_threshold'
#   Default: 10
#   the minimum percentile of average node cpu usage.
#   Alerts are raised on the collector upon crossing this limit.
#   On autoflex, the collector would trigger actions to keep the cpu
#   usage in bounds.
#
;flex_cpu_low_threshold = 10

#
# 'flex_cpu_high_threshold'
#   Default: 10
#   the maximum percentile of average node cpu usage.
#   Alerts are raised on the collector upon crossing this limit.
#   On autoflex, the collector would trigger actions to keep the cpu
#   usage in bounds.
#
;flex_cpu_high_threshold = 90

#
# 'drpnode'
#   optional. The backup node where the service is activated in a DRP
#   situation. This node is also a data synchronization target for 'sync'
#   resources (see below)
#
;drpnode = vm5

#
# 'drpnodes'
#   optional. Alternate backup nodes, where the service could be activated
#   in a DRP situation if the 'drpnode' is not available. These nodes are
#   also data synchronization targets for 'sync' resources (see below)
#
;drpnodes = vm6 vm7

#
# 'scsireserv'
#   optional. Possible values are 'true' or 'false'. Default is 'false'.
#   If set to 'true', OpenSVC will try to acquire a type-5 (write exclusive,
#   registrant only) scsi3 persistent reservation on every path to disks of
#   every disk group attached to this service. Existing reservations are
#   preempted to not block service start-up. If the start-up was not
#   legitimate the data are still protected from being written over from both
#   nodes.
#   If set to 'false' or not set, 'scsireserv' can be activated on a per-
#   resource basis.
#
;scsireserv = false

#
# 'bwlimit'
#   optional. Bandwidth limit in KB applied to all rsync transfers
#
;bwlimit = 3000

#
# 'sync_interval'
#   optional. Set the minimum delay between syncs in minutes. If a sync is
#   triggered through crond or manually, it is skipped if last sync occured
#   less than 'sync_interval' ago. 
#   The mecanism is enforced by a timestamp created upon each sync completion
#   in /opt/opensvc/var/sync/[service]![dst]
#
;sync_interval = 30

#
# 'sync_days'
#   optional. Defaults to 'every week day'.
#   Set the days this resource synchronization is allowed.
#
;sync_days = ["monday", "friday"]

#
# 'sync_period'
#   optional. Defaults to 4am to 6am.
#   Set the time ranges this resource synchronization is allowed.
#
;sync_period = ["04:00", "06:00"]
;sync_period = [["04:00", "06:00"], ["18:00", "20:00"]]

#
# 'sync_interval'
#   optional. Set the minimum delay between syncs in minutes. If a sync is
#   triggered through crond or manually, it is skipped if last sync occured
#   less than 'sync_interval' ago. 
#   The mecanism is enforced by a timestamp created upon each sync completion
#   in /opt/opensvc/var/sync/[service]![dst]
#
;sync_interval = 30

#
# 'sync_max_delay'
#   optional. Default value is 1440 minutes (1 day). Unit is minutes.
#   This sets to delay above which the sync status of the resource is to be
#   considered down. Should be set according to your application service
#   level agreement. The cron job frequency should be set between
#   'sync_interval' and 'sync_max_delay'.
#
;sync_max_delay = 1440

#
# 'vm_name'
#   optional. Defaults to service name. This need to be set if the virtual
#   machine name is different from the service name.
# 
;vm_name = teddybear

#
# 'presnap_trigger'
#   optional. Defaults to None. Define a command to run before creating
#   snapshots. This is most likely what you need to use plug a script to
#   put you data in a coherent state (alter begin backup and the like).
# 
;presnap_trigger = /bin/true

#
# 'postsnap_trigger'
#   optional. Defaults to None. Define a command to run after snapshots are
#   created. This is most likely what you need to use plug a script to
#   undo the actions of 'presnap_trigger'.
# 
;postsnap_trigger = /bin/true

#
# 'containerize'
#   optional. Defaults to true. Use process containers when possible.
#   Containers allow capping memory, swap and cpu usage per service.
#   Lxc containers are naturally containerized, so skip containerization
#   of their startapp.
# 
;containerize = false

#
# 'container_cpus'
#   optional. Defaults to all cpus. Allow service process to bind only
#   the specified cpus. Cpus are specified as list or range : 0,1,2 or
#   0-2
# 
;container_cpus = 0-1

#
# 'container_mems'
#   optional. Defaults to all memory nodes. Allow service process to bind
#   only the specified memory nodes. Memory nodes are specified as list or
#   range : 0,1,2 or 0-2
# 
;container_mems = 0

#
# 'container_cpu_share'
#   optional. No default, kernel default value is used, which usually is
#   1024 shares. In a cpu-bound situation, ensure the service does not
#   use more than its share of cpu ressource. The actual percentile depends
#   on shares allowed to other services.
# 
;container_cpu_share = 1024

#
# 'container_mem_limit'
#   optional. Defaults to all available memory. Ensures the service does
#   not use more than specified memory (in bytes). The Out-Of-Memory killer
#   get triggered in case of tresspassing.
# 
;container_mem_limit = 100000000

#
# 'container_vmem_limit'
#   optional. Defaults to all available memory+swap. Ensures the service does
#   not use more than specified memory+swap (in bytes). The Out-Of-Memory killer
#   get triggered in case of tresspassing. The specified value must be greater
#   than container_mem_limit
# 
;container_vmem_limit = 200000000


##############################################################################
#
# Service resources
#
##############################################################################


##############################################################################
#
# 'ip' resources
#   describe which ip to plumb for the service. Any number of ips can be
#   attached to the service, but ips are to be uniquely assigned to it.
#   In case of ip conflict, the service refuses to start.
#
;[ip#1]
;disable = true
;disable_on = node12 node21
;optional = true

#
# 'ipname'
#   the DNS name of the ip resource. Can be different from one node to the
#   other, in which case '@nodename' can be specified. This is most
#   useful to specify a different ip when the service starts in DRP mode,
#   where subnets are likely to be different than those of the production
#   datacenter.
#
;ipname@zezette = unxdevweb
;ipname@vm5 = unxdrpweb

#
# 'ipdev'
#   the interface name over which OpenSVC will try to stack the service
#   ip. Can be different from one node to the other, in which case the
#   '@nodename' can be specified.
#
;ipdev@zezette = br0
;ipdev@vm5 = eth0

#
# 'netmask'
#   optional if an ip is already plumbed on the root interface (if which
#   case the netmask is deduced from this ip). Mandatory if the interface
#   is dedicated to the service (dummy interface are likely to be in this
#   case).
#   the format is decimal, ex: 255.255.252.0
#
;netmask = 255.255.255.0

#
# 'always_on'
#   optional. Possible values are 'nodes', 'drpnodes' or 'nodes drpnodes',
#   or a list of nodes.
#   Sets the nodes on which the resource is always kept up. Primary usage is
#   file synchronization receiving on non-shared disks. Don't set this on
#   shared disk !! danger !!
#
;always_on = drpnodes


##############################################################################
#
# 'vg' resource
#   Disk group in the sense of volume managers, whatever the implementation.
#   Attaching a 'vg' to a service will make OpenSVC check and drive its
#   imported/exported status.
#
;[vg#1]
;disable = true
;disable_on = node12 node21
;optional = true

#
# 'vgname'
#   nothing special there
#
;vgname = unxtstsvc02

#
# 'dsf'
#   optional. Boolean. HP-UX only. Default value is True.
#   'dsf' must be set to false for LVM to use never-multipathed /dev/dsk/...
#   devices. Otherwize, ad-hoc multipathed /dev/disk/... devices.
#
;dsf = true

#
# 'scsireserv'
#   optional. Possible values are 'true' or 'false'. Default is 'false'.
#   If set to 'true', OpenSVC will try to acquire a type-5 (write exclusive,
#   registrant only) scsi3 persistent reservation on every path to disks of
#   every disk group attached to this service. Existing reservations are
#   preempted to not block service start-up. If the start-up was not
#   legitimate the data are still protected from being written over from both
#   nodes.
#   If set to 'false' or not set, 'scsireserv' can still be activated globally
#   from the 'default' section.
#
;scsireserv = false

#
# 'always_on'
#   optional. Possible values are 'nodes', 'drpnodes' or 'nodes drpnodes',
#   or a list of nodes.
#   Sets the nodes on which the resource is always kept up. Primary usage is
#   file synchronization receiving on non-shared disks. Don't set this on
#   shared disk !! danger !!
#
;always_on = drpnodes

#
# 'vgtype'
#   optional.
#   'vgtype' may be set to veritas to use veritas volume group instead of native
#   os volume group
#
;vgtype = veritas

##############################################################################
#
# 'pool' resource
#   zfs pool the sense of volume managers, whatever the implementation.
#   Attaching a ZFS 'pool' to a service will make OpenSVC check and drive its
#   imported/exported status.
#
;[pool#1]
;disable = true
;disable_on = node12 node21
;optional = true

#
# 'poolname'
#   nothing special there
#
;poolname = zpool

#
# tags  = preboot may be used when zfs pool is required before container boot
# else postboot is presumed
#
;tags = preboot

#
# 'scsireserv'
#   optional. Possible values are 'true' or 'false'. Default is 'false'.
#   If set to 'true', OpenSVC will try to acquire a type-5 (write exclusive,
#   registrant only) scsi3 persistent reservation on every path to disks of
#   every disk group attached to this service. Existing reservations are
#   preempted to not block service start-up. If the start-up was not
#   legitimate the data are still protected from being written over from both
#   nodes.
#   If set to 'false' or not set, 'scsireserv' can still be activated globally
#   from the 'default' section.
#
;scsireserv = false

#
# 'always_on'
#   optional. Possible values are 'nodes', 'drpnodes' or 'nodes drpnodes',
#   or a list of nodes.
#   Sets the nodes on which the resource is always kept up. Primary usage is
#   file synchronization receiving on non-shared disks. Don't set this on
#   shared disk !! danger !!
#
;always_on = drpnodes

##############################################################################
#
# 'vmdg' resource
#   HP-UX only, HP-VM only. The virtual machine disk group is the group of
#   disks given to a VM (pass-through device). As such, there can be only one
#   vmdg section for a hpvm-mode service.
#   This resource type is only present to allow setting the scsireserv option.
#
;[vmdg]
;scsireserv = false


##############################################################################
#
# 'drbd' resource
#   Linux only. Set up the attachment, connection and role of a defined drbd
#   resource. Depending on weather this resource is stacked over or under
#   other disk group resources we need to start it respectively late or early.
#   This is controlled by a set of tags: 'prevg', 'postvg'.
#
[drbd#0]

#
# 'res'
#   mandatory. String. The name of the drbd resource associated with this
#   service resource. OpenSVC expect the resource configuration file to
#   reside in '/etc/drbd.d/resname.res'. The 'sync#i0' resource will take
#   care of replicating this file to remote nodes.
#
res = data

#
# 'always_on'
#   state the expected status on nodes specified as value is 'up'. With drbd
#   the 'up' status is granted when the drbd driver reports UpToDate/UpToDate,
#   so always_on should point to all nodes participating in the drbd resource.
#
always_on = drpnodes nodes

#
# 'tags'
#    prevg:  upon service 'start', drbd 'start' is scheduled before volume
#            group 'start'. To use when the volume group is layered over the
#            drbd.
#    postvg: upon service 'start', drbd 'start' is scheduled after volume 
#            group 'start'. To use when the the drbd is layered over the
#            volume group.
#
tags = prevg


##############################################################################
#
# 'fs' resource
#   describes filesystems to mount on service startup and umount on service
#   shutdown.
#   The options are aligned to the Unix fstab fields. Whatever is possibly
#   described in the fstab should be supported in there.
#
;[fs#1]
;disable = true
;disable_on = node12 node21
;optional = true
;dev = /opt/unxtstsvc01.img
;mnt = /opt/unxtstsvc01
;mnt_opt = rw,loop
;type = ext4

;[fs#2]
;dev = zpool/app
;mnt = /unxtstsvc01/app
;type = zfs

#
# 'type'
#   possible values:
#       zfs lofs ext3 ext4 ...
#

#
# 'dev'
#   can have per-node value, using the 'dev@node' parameter syntax for
#   each node. You can mix 'dev' with 'dev@node' syntax to obtain a default
#   plus exceptions behaviour. This facility is most useful for replicating
#   nas heads, when you want the nodes to use the closest head.
# 
;dev@prdnode = prdnas:/vol/vol1
;dev@drpnode = drpnas:/vol/vol1


#
# 'always_on'
#   optional. Possible values are 'nodes', 'drpnodes' or 'nodes drpnodes',
#   or a list of nodes.
#   Sets the nodes on which the resource is always kept up. Primary usage is
#   file synchronization receiving on non-shared disks. Don't set this on
#   shared disk !! danger !!
#
;always_on = drpnodes


##############################################################################
#
# 'loop' resource
#   linux-only.
#   describes a loop device attached to the service. startup triggers the
#   allocation of a block device (usualy major 7) mapped over the specified
#   file. The created loop dev can be used to stack disk group also attached
#   to the service.
#
;[loop#1]
;disable = true
;disable_on = node12 node21
;optional = true
;file = /opt/unxtstsvc02.img


##############################################################################
#
# 'sync' resource
#   describes a rsync-based data synchronization job. By default the sync
#   is run daily.
#
;[sync#1]
;disable = true
;disable_on = node12 node21
;optional = true

#
# 'tags'
#   the sync resource supports the 'delay_snap' tag. This tag is used to
#   delay the snapshot creation just before the rsync, thus after 'postsnap_trigger'
#   execution. The default behaviour (no tags) is to group all snapshots creation
#   before copying data to remote nodes, thus between 'presnap_trigger' and
#   'postsnap_trigger'.
#
;tags = delay_snap

#
# 'src'
#   source of the sync. Can be a whitespace-separated list of files or dirs
#   passed as-is to rsync. Beware of the meaningful ending '/'. Refer to
#   the rsync man page for details.
#
;src = /unxdevweb/

#
# 'dst'
#   destination of the sync. Beware of the meaningful ending '/'. Refer to
#   the rsync man page for details.
#
;dst = /unxdevweb

#
# 'exclude'
#   !deprecated!, optional. A whitespace-separated list of --exclude params
#   passed unchanged to rsync. The 'options' keyword is preferred now.
#
;exclude = --exclude=cache

#
# 'options'
#   optional. A whitespace-separated list of params passed unchanged to rsync.
#   Typical usage is ACL preservation activation.
#
;options = -A

#
# 'target'
#   mandatory. Possible values are 'nodes', 'drpnodes' or 'nodes drpnodes'.
#   Describes which nodes should receive this data sync from the PRD node
#   where the service is up and running.
#
#   SAN storage shared 'nodes' must not be sync to 'nodes'.
#   SRDF-like paired storage must not be sync to 'drpnodes'.
#
;target = nodes drpnodes

#
# 'snap'
#   optional. Possible values are 'true' or 'false'. Default is 'false'.
#   If set to true, OpenSVC will try to snapshot the first snapshottable
#   parent of the source of the sync and try to sync from the snap.
#
;snap = true

#
# 'dstfs'
#   optional. If set to a remote mount point, OpenSVC will verify that the
#   specified mount point is really hosting a mounted FS. This can be used
#   as a safety net to not overflow the parent FS (may be root).
#
;dstfs = /remote/dir

#
# 'bwlimit'
#   optional. Bandwidth limit in KB applied to this rsync transfer. Takes
#   precedence over 'bwlimit' set in [DEFAULT].
#
;bwlimit = 3000

#
# 'sync_interval'
#   optional. Set the minimum delay between syncs in minutes. If a sync is
#   triggered through crond or manually, it is skipped if last sync occured
#   less than 'sync_interval' ago. If no set in a resource section, fallback
#   to the value set in the 'default' section. The mecanism is enforced by a
#   timestamp created upon each sync completion in
#   /opt/opensvc/var/sync/[service]![dst]
#
;sync_interval = 30

#
# 'type'
#   optional. Default is 'rsync'. Specify a data sync mode. Supported values
#   are: zfs, netapp, rsync, dds
#
;type = netapp
;type = zfs

#
# 'zfs' type specific parameter.
#   The synchronization mecanism used is zfs send / zfs receive.
#   src and dst may refer a dataset instead of directory
#   src and dst can be different from one node to the
#   other, in which case '@nodename' can be specified.
#

#
# 'recursive'
#   optional. (used when type = 'zfs')
#   Default is 'True'. So snapshots are created recursivly
#
;recursive = False

#
# 'netapp' type specific parameter.
#   The synchronization mecanism used is snapmirror.
#

#
# 'filer'
#   mandatory. 'filer' points the nas head to pass commands to. In most case
#   you need to specify localized filers using the 'filer@node' syntax.
#
;filer@vm4 = nasprd
;filer@vm5 = nasdrp

#
# 'path'
#   mandatory. Specifies the volume or qtree to drive snapmirror on.
#
;path = /vol/vol1

#
# 'user'
#   mandatory. Specifies the user used to ssh connect the filers. Nodes should
#   be trusted by keys to access the filer with this user.
#
;user = nasadm


##############################################################################
#
# Symmetrix clones
#
;[sync#2]
;type = symclone

#
# 'symdg'
#   mandatory. name of the symmetrix device group where the source and target
#   devices are grouped.
#
;symdg = DGCVI

#
# 'precopy_timeout'
#   optional. default 300 secs. seconds to wait for a precopy (syncresync) to
#   finish before returning with an error. In this case, the precopy proceeds
#   normally, but the opensvc leftover actions must be retried. The precopy
#   time depends on the amount of changes logged at the source, which is
#   context-dependent. Tune to your needs.
#
;precopy_timeout = 300

#
# 'symdevs'
# 'symdevs@node'
#   mandatory. whitespace-separated list of devices to drive with this resource.
#   devices are specified as 'symmetrix identifier:symmetrix device identifier'
#
;symdevs@lmwbica0 = 000290101370:380D
;sync_interval = 30
;sync_max_delay = 1440


##############################################################################
#
# HP StorageWorks EVA snapshots
#   (Re)create snapshots of Logical Units in a EVA class HP storage array.
#   Snap wwid and lu number are static so that the OS does not have to handle
#   device renamings. If those snaps are presented on the same host than source
#   logical units and are used in a volume group, a trigger should take care
#   of relabelling the PV and VG.
#
#   All EVA commands are submitted to the Command View server (manager). It's
#   location and privileged account must be described per-EVA in the
#   etc/sssu.conf configuration file (which should be root/600).
#
#   ex:
#     [EVA11]
#     manager = manager.opensvc.com
#     username = hpadmin
#     password = xxxxxxx
#
#   The sssu binary is expected to be /opt/opensvc/bin/sssu. A symlink is fair
#   enough.
#
;[sync#1]
;type = evasnap
;sync_interval = 5
;sync_max_delay = 60

#
# 'eva_name'
#   mandatory. The name of the EVA storage array, as seen by the manager.
#   Also used as a section name in etc/sssu.conf
#
;eva_name = EVA11

#
# 'pairs'
#   mandatory. A JSON-serialized list descibing the origin-snap relationships.
#   Also used as a section name in etc/sssu.conf
#
;eva_name = EVA11
;pairs = [
;         {
;	   "src": "6001438005ffffff0000800003ee0000",
;	   "dst": "6001438005ffffff00008000040f0000",
;	   "mask": ["\\Hosts\\Opensvc\\n1\\101",
;                   "\\Hosts\\Opensvc\\n2\\106"]
;         },
;         {
;	   "src": "6001438005ffffff0000800003f80000",
;	   "dst": "6001438005ffffff0000800004130000",
;	   "mask": ["\\Hosts\\Opensvc\\n1\\102"]
;         }
;        ]


##############################################################################
#
# Binary deltas based sync resource for Linux LVM.
#
;[sync#3]
;type = dds

#
# 'src'
#   source logical volume. Mandatory. Points the origin of the snapshots to
#   replicate from.
#
;src = /dev/mapper/unxtstsvc02-data

#
# 'dst'
#   target file or block device. Optional. Defaults to src. Points the media
#   to replay the binary-delta received from source node to. This media must have 
#   a size superior or equal to source.
#
;dst = /tmp/dds.img

#
# 'target'
#   Mandatory. Accepted values are 'drpnodes', 'nodes' or both, whitespace-separated.
#   Points the target nodes to replay the binary-deltas on. Be warned that starting
#   the service on a target node without a 'stop-syncupdate-start cycle, will break 
#   the synchronization, so this mode is usually restricted to drpnodes sync, and
#   should not be used to replicate data between nodes with automated services failover.
#   
;target = drpnodes

#
# 'snap_size'
#   Optional. Default to 10% of origin. In MB, rounded to physical extent boundaries
#   by lvm tools.
#   Size of the snapshots created by OpenSVC to extract binary deltas from. Opensvc
#   creates at most 2 snapshots : one short-lived to gather changed data from, and one
#   long-lived to gather changed chunks list from. Volume groups should have the
#   necessary space always available.
#
;snap_size = 4

;sync_interval = 1450
;sync_max_delay = 1


##############################################################################
#
# Virtual disk.
#  remap devices or files used as virtual machines devices
#
;[vdisk#1]
#
# 'path@node'
#   Mandatory.
#   path of the device or file used as a virtual machine disk on node 'node'
#
;path@node1 = /dev/mapper/unxtstsvc02-data
;path@node2 = /dev/mapper/vg0-unxtstsvc02_data


##############################################################################
#
# Heart beat.
#  check the status of a clusterware piloting the service
#
;[hb#1]
#
# 'type'
#   Mandatory.
#   Specify the heartbeat driver to use. Supported driver are 'OpenHA' and
#   'LinuxHA'.
#
;type = OpenHA

#
# 'name'
#   Optional. Applies to the OpenHA driver
#   Specify the service name used by the heartbeat. Defaults to the service name.
#
;name = SVCNAME

 0707010006726f000081a40000000000000000000000014d9d7e6e0000033e000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/usr/share/BANNER #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
  070701000671ad000041ed0000000000000000000000044d9d945500000000000000b600010002ffffffffffffffff0000001500000000root/opt/opensvc/bin  070701000671c4000081ed0000000000000000000000014d9d7e6e00001d5a000000b600010002ffffffffffffffff0000001c00000000root/opt/opensvc/bin/svcmgr   #!/opt/opensvc/bin/python
#
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import sys
import os
import optparse

#
# add project lib to path
#
pathsvc = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
pathetc = os.path.join(pathsvc, 'etc')
sys.path.append(os.path.join(pathsvc, 'lib'))
prog = os.path.basename(__file__)

import svcBuilder
import rcStatus
import rcOptParser
try:
    from version import version
except:
    version = "dev"

svcs = None
__ver = prog + " version " + version
__usage = "%prog [options] command\n\n" + rcOptParser.format_desc()
parser = optparse.OptionParser(version=__ver, usage=__usage)
parser.add_option("--debug", default=False,
		  action="store_true", dest="debug",
                  help="debug mode")
parser.add_option("-p", "--parallel", default=False, action="store_true", dest="parallel",
                  help="start actions on specified services in parallel")
parser.add_option("-f", "--force", default=False, action="store_true", dest="force",
                  help="force action, ignore sanity check warnings")
parser.add_option("-c", "--cluster", default=False, action="store_true", dest="cluster",
                  help="option to set when excuting from a clusterware to disable safety net")
parser.add_option("-i", "--interactive", default=False, action="store_true", dest="interactive",
                  help="prompt user for a choice instead of going for defaults or failing")
parser.add_option("--rid", default=None, action="store", dest="parm_rid",
                  help="comma-separated list of resource to limit action to")
parser.add_option("--tags", default=None, action="store", dest="parm_tags",
                  help="comma-separated list of resource tags to limit action to")
parser.add_option("--resource", default=[], action="append",
                  help="a resource definition in json dictionary format fed to create or update")
parser.add_option("--waitlock", default=60, action="store", dest="parm_waitlock", type="int",
                  help="comma-separated list of resource tags to limit action to")
parser.add_option("--to", default=None, action="store", dest="parm_destination_node",
                  help="remote node to start or migrate the service to")


cluster = False
cmd = os.path.basename(__file__)
if cmd == 'allservices':
    svcs = svcBuilder.build_services()
elif cmd == 'allupservices':
    svcs = svcBuilder.build_services(status=rcStatus.UP)
    svcs += svcBuilder.build_services(status=rcStatus.WARN)
elif cmd == 'alldownservices':
    svcs = svcBuilder.build_services(status=rcStatus.DOWN)
elif cmd == 'allprimaryservices':
    svcs = svcBuilder.build_services(onlyprimary=True)
elif cmd == 'allsecondaryservices':
    svcs = svcBuilder.build_services(onlysecondary=True)
elif cmd == 'svcmgr':
    parser.add_option("-s", "--service", default=None, action="store", dest="parm_svcs",
              help="comma-separated list of service to operate on")
    parser.add_option("--status", default=None, action="store", dest="parm_status",
              help="operate only on service in the specified status (up/down/warn)")
    parser.add_option("--onlyprimary", default=None, action="store_true", dest="parm_primary",
              help="operate only on service flagged for autostart on this node")
    parser.add_option("--onlysecondary", default=None, action="store_true", dest="parm_secondary",
              help="operate only on service not flagged for autostart on this node")
else:
    svcname = cmd.split('.')
    if len(svcname) == 2 and svcname[1] == 'cluster':
        cluster = True
        svcname = svcname[0]
    else:
        svcname = cmd
    svcs = svcBuilder.build_services(svcnames=[svcname])

(options, args) = parser.parse_args()

if svcs is None:
    parm_primary = False
    parm_secondary = False
    parm_status = None

    if hasattr(options, "parm_svcs") and options.parm_svcs is not None:
        svcnames = options.parm_svcs.split(',')
    else:
        svcnames = []

    if hasattr(options, "parm_status") and options.parm_status is not None:
        status = rcStatus.status_value(options.parm_status)
    else:
        status = None

    if hasattr(options, "parm_primary") and options.parm_primary is not None and \
       hasattr(options, "parm_secondary") and options.parm_secondary is not None:
        parser.error("--onlyprimary and --onlysecondary are exclusive")

    if hasattr(options, "parm_primary") and options.parm_primary is not None:
        onlyprimary = options.parm_primary
    else:
        onlyprimary = False

    if hasattr(options, "parm_secondary") and options.parm_secondary is not None:
        onlysecondary = options.parm_secondary
    else:
        onlysecondary = False

    svcs = svcBuilder.build_services(svcnames=svcnames,
                                     status=status,
                                     onlyprimary=onlyprimary,
                                     onlysecondary=onlysecondary,
                                    )

if len(args) > 1:
    parser.error("More than one action")
if len(args) is 0:
    parser.error("Missing action")
action = args[0]
if not action in rcOptParser.action_desc.keys():
    parser.error("unsupported action")

if hasattr(options, "parm_rid") and options.parm_rid is not None:
   rid = options.parm_rid.split(',')
else:
   rid = []

if hasattr(options, "parm_tags") and options.parm_tags is not None:
   tags = set(options.parm_tags.split(','))
else:
   tags = set([])

if options.parallel:
    from multiprocessing import Process
    p = {}

if action in ['create', 'update']:
    r = getattr(svcBuilder, action)(svcnames, options.resource, interactive=options.interactive)
    sys.exit(r)
elif action in ['disable', 'enable', 'delete']:
    r = getattr(svcBuilder, action)(svcnames, rid)
    sys.exit(r)

err = 0
for s in svcs:
    s.force = options.force
    s.parallel = options.parallel
    if cluster:
        s.cluster = cluster
    else:
        s.cluster = options.cluster
    s.destination_node = options.parm_destination_node
    if options.parallel:
        d = {'action':action, 'rid':rid, 'tags':tags, 'waitlock':options.parm_waitlock}
        p[s.svcname] = Process(target=s.action, name='worker_'+s.svcname, kwargs=d)
        p[s.svcname].start()
    else:
        err += s.action(action, rid=rid, tags=tags, waitlock=options.parm_waitlock)

if options.parallel:
    for svcname in p:
        p[svcname].join()
        r = p[svcname].exitcode
        if r > 0:
           # r is negative when p[svcname] is killed by signal.
           # in this case, we don't want to decrement the err counter.
           err += r

try:
    import logging
    logging.shutdown()
except:
    pass

sys.exit(err)
  070701000671c3000081ed0000000000000000000000014d9d7e6e00003d8e000000b600010002ffffffffffffffff0000002100000000root/opt/opensvc/bin/postinstall  #!/usr/bin/env python2.6

import os
import shutil
import glob
from subprocess import *

python_name = 'python2.6'

sysname, nodename, x, x, machine = os.uname()

def python_path():
    python_exe = python_name
    for path in os.environ["PATH"].split(os.pathsep):
        exe_file = os.path.join(path, python_exe)
        if os.path.exists(exe_file) and os.access(exe_file, os.X_OK):
            return os.path.dirname(exe_file)
    return None

def install_cron():
    """install opensvc cron jobs
    """

    agt = '/opt/opensvc/bin/perfagt.'+sysname
    ce = [{
           'sched': "0,10,20,30,40,50 * * * *",
           'reset_sched': False,
           'user': "",
           'cmd': "[ -x /opt/opensvc/bin/svcmon ] && /opt/opensvc/bin/svcmon --updatedb --maxdelaydb 120 >/dev/null 2>&1",
           'marker': 'svcmon --updatedb',
           'ok': False
    },{
           'sched': "0,10,20,30,40,50 * * * *",
           'reset_sched': True,
           'user': "",
           'cmd': "[ -x /opt/opensvc/bin/cron/opensvc ] && /opt/opensvc/bin/cron/opensvc >/dev/null 2>&1",
           'marker': '/opt/opensvc/bin/cron/opensvc',
           'ok': False
    },{
           'sched': "0,10,20,30,40,50 * * * *",
           'reset_sched': False,
           'user': "",
           'cmd': "[ -x %(agt)s ] && %(agt)s >/dev/null 2>&1"%dict(agt=agt),
           'marker': agt,
           'ok': False
    }]
    remove_entries = ['bin/nodemgr compliance check']

    purge = []
    root_crontab = False

    """ order of preference
    """
    if sysname == 'SunOS' :
        root_crontab_locs = [
            '/var/spool/cron/crontabs/root'
        ]
    else:
        root_crontab_locs = [
            '/etc/cron.d/opensvc',
            '/var/spool/cron/crontabs/root',
            '/var/spool/cron/root',
            '/var/cron/tabs/root',
            '/usr/lib/cron/tabs/root',
        ]
    for loc in root_crontab_locs:
        if os.path.exists(os.path.dirname(loc)):
            if not root_crontab:
                root_crontab = loc
                if root_crontab == '/etc/cron.d/opensvc':
                    ce[0]['user'] = "root"
                    ce[1]['user'] = "root"
                    ce[2]['user'] = "root"
            elif os.path.exists(loc):
                purge.append(loc)

    if not root_crontab:
        print "no root crontab found in usual locations %s"%str(root_crontab_locs)
        return False

    ce[0]['full'] = ' '.join([ce[0]['sched'], ce[0]['user'], ce[0]['cmd']])
    ce[1]['full'] = ' '.join([ce[1]['sched'], ce[1]['user'], ce[1]['cmd']])

    if os.path.exists(agt):
        ce[2]['full'] = ' '.join([ce[2]['sched'], ce[2]['user'], ce[2]['cmd']])
    else:
        ce[2]['full'] = None

    new = False
    if os.path.exists(root_crontab):
        with open(root_crontab, 'r') as f:
            new = f.readlines()
            for i, line in enumerate(new):
                for c in ce:
                    if c['full'] is None:
                        continue
                    if c['marker'] in line:
                        if c['cmd'] in line:
			    sched = ' '.join(line.split()[:5])
                            if c['reset_sched'] and sched != c['sched']:
                                new[i] = ' '.join([c['sched'], c['user'], c['cmd']])+'\n'
                            c['ok'] = True
                        else:
                            # preserve scheduling
                            if c['reset_sched']:
                                sched = c['sched']
                            else:
                                sched = ' '.join(line.split()[:5])
                            new[i] = ' '.join([sched, c['user'], c['cmd']])+'\n'
                            c['ok'] = True
	    for c in ce:
                if c['full'] is not None and not c['ok']:
                    new.append(c['full']+'\n')
    else:
        new = []
        for c in ce:
            if c['full'] is not None and not c['ok']:
                new.append(c['full']+'\n')

    if not new:
        print "problem preparing the new crontab"
        return False
 
    for i, line in enumerate(new):
        for re in remove_entries:
            if re in line:
                print 'delete line "%s" from %s'%(re,root_crontab)
                del new[i]

    with open(root_crontab, 'w') as f:
        f.write(''.join(new))

    """ Activate changes (actually only needed on HP-UX)
    """
    if '/var/spool/' in root_crontab:
        cmd = ['crontab', root_crontab]
        process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
        buff = process.communicate()

    for loc in purge:
        with open(loc, 'r') as f:
            new = [ line for line in f.readlines() if not 'opensvc.daily' in line and not  'svcmon --updatedb' in line ]
        with open(loc, 'w') as f:
            f.write(''.join(new))

    """ Clean up old standard file locations
    """
    for f in ['/etc/cron.daily/opensvc', '/etc/cron.daily/opensvc.daily']:
        if os.path.exists(f):
            os.unlink(f)

def activate_redhat():
    cmd = ['chkconfig', '--add', 'opensvc']
    process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
    buff = process.communicate()
    if process.returncode > 0:
        print buff[1]
        return False
    return True

def activate_debian():
    cmd = ['update-rc.d', '-f', 'opensvc', 'remove']
    process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
    buff = process.communicate()
    if process.returncode > 0:
        print buff[1]
        return False
    cmd = ['update-rc.d', 'opensvc', 'defaults', '99', '01']
    process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
    buff = process.communicate()
    if process.returncode > 0:
        print buff[1]
        return False
    return True

def activate_hpux():
    rc = "/sbin/init.d/opensvc"
    links = ["/sbin/rc1.d/K010opensvc", "/sbin/rc2.d/K010opensvc", "/sbin/rc3.d/S990opensvc"]
    if os.path.exists("/sbin/rc2.d/S990opensvc"):
        os.unlink("/sbin/rc2.d/S990opensvc")
    for l in links:
        if not os.path.islink(l):
            if os.path.exists(l):
                os.unlink(l)
            os.symlink(rc, l)
    with open("/etc/rc.config.d/opensvc", "w") as f:
        f.write("RUN_OPENSVC=1\n")
        f.close()
    return True

def activate_AIX():
    rc = "/etc/rc.d/init.d/opensvc"
    links = ["/etc/rc.d/rc2.d/S990opensvc"]
    for l in links:
        if not os.path.islink(l):
            if os.path.exists(l):
                os.unlink(l)
            print "create link %s -> %s"%(l, rc)
            os.symlink(rc, l)
    return True

def activate_SunOS():
    rc = "/etc/init.d/opensvc"
    links = ["/etc/rc0.d/K00opensvc", "/etc/rc3.d/S99opensvc"]
    for l in links:
        if not os.path.islink(l):
            if os.path.exists(l):
                os.unlink(l)
            os.symlink(rc, l)
    return True

def activate_FreeBSD():
    return True

def activate_Darwin():
    return True

def update_file(filename, srctext, replacetext):
    """ replace into filename srctext by replacetext
    """
    import fileinput
    for line in fileinput.input(filename, inplace=1):
        if line.rstrip('\n') == srctext.rstrip('\n') :
            line = replacetext
        print line.rstrip('\n')
    fileinput.close()

def install_rc():
    """install startup script
    """

    if os.path.exists('/etc/debian_version'):
        rc = '/etc/init.d/opensvc'
        src = '/opt/opensvc/bin/opensvc.init.debian'
        activate = activate_debian
    elif os.path.exists('/etc/SuSE-release'):
        rc = '/etc/init.d/opensvc'
        src = '/opt/opensvc/bin/opensvc.init.debian'
        activate = activate_redhat
    elif os.path.exists('/etc/redhat-release'):
        rc = '/etc/init.d/opensvc'
        src = '/opt/opensvc/bin/opensvc.init.redhat'
        activate = activate_redhat
    elif sysname == "HP-UX":
        rc = '/sbin/init.d/opensvc'
        src = '/opt/opensvc/bin/opensvc.init.hpux'
        activate = activate_hpux
    elif sysname == "SunOS":
        rc = '/etc/init.d/opensvc'
        src = '/opt/opensvc/bin/opensvc.init.SunOS'
        activate = activate_SunOS
    elif sysname == "FreeBSD":
        rc = '/etc/rc.d/opensvc'
        src = '/opt/opensvc/bin/opensvc.init.FreeBSD'
        activate = activate_FreeBSD
    elif sysname == "AIX":
        rc = '/etc/rc.d/init.d/opensvc'
        src = '/opt/opensvc/bin/opensvc.init.AIX'
        activate = activate_AIX
    elif sysname == "Darwin":
        rc = '/System/Library/LaunchDaemons/opensvc.plist'
        src = '/opt/opensvc/bin/opensvc.init.Darwin'
        activate = activate_Darwin
    else:
        print "could not select an init script: unsupported operating system"
        return False

    if os.path.islink(rc):
        os.unlink(rc)

    shutil.copyfile(src, rc)
    os.chmod(rc, 0755)
    activate()

def gen_keys():
    home = os.environ['HOME']
    priv = os.path.join(home, ".ssh", "id_dsa")
    pub = os.path.join(home, ".ssh", "id_dsa.pub")
    if os.path.exists(pub) or os.path.exists(priv):
        return
    cmd = ['ssh-keygen', '-t', 'dsa', '-b', '1024', '-P', '', '-f', priv]
    process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
    buff = process.communicate()

def missing_dir(sub):
    pathd = os.path.join(os.sep, 'opt', 'opensvc', sub)
    if not os.path.exists(pathd):
	os.makedirs(pathd, 755)

def missing_dirs():
    missing_dir('log')
    missing_dir('tmp')

def convert_svclinks():
    missing_dir('etc')
    svcmgr = os.path.join('..', 'bin', 'svcmgr')
    if not os.path.exists(svcmgr):
	return 1
    rcService = os.path.realpath(os.path.join(os.sep, 'opt', 'opensvc', 'bin', 'rcService'))
    if not os.path.exists(rcService):
	return 1
    for fname in os.listdir(pathetc):
        fpath = os.path.join(pathetc, fname)
        if not os.path.islink(fpath):
            continue
        rpath = os.path.realpath(fpath)
        if rpath != rcService:
            continue
        os.unlink(fpath)
        os.symlink(svcmgr, fpath)

def move_usr_to_opt():
    linksvc = os.path.join(os.sep, 'service')
    pathsvc = os.path.join(os.sep, 'opt', 'opensvc')
    pathvar = os.path.join(pathsvc, 'var')
    pathetc = os.path.join(pathsvc, 'etc')
    old_pathsvc = os.path.join(os.sep, 'usr', 'local', 'opensvc')
    old_pathvar = os.path.join(old_pathsvc, 'var')
    old_pathetc = os.path.join(old_pathsvc, 'etc')

    if os.path.exists(old_pathvar):
        for f in glob.glob(old_pathvar+'/*'):
            dst = os.path.join(pathvar, os.path.basename(f))
            if os.path.exists(dst) and 'host_mode' not in dst:
                continue
            if os.path.isdir(f):
                shutil.copytree(f, dst, symlinks=True)
            elif os.path.islink(f):
                linkto = os.readlink(f)
                os.symlink(linkto, dst)
            else:
                shutil.copy2(f, dst)

    if os.path.exists(old_pathetc):
        for f in glob.glob(old_pathetc+'/*'):
            dst = os.path.join(pathetc, os.path.basename(f))
            if os.path.exists(dst):
                continue
            if os.path.islink(f):
                linkto = os.readlink(f)
                os.symlink(linkto, dst)
            elif os.path.isdir(f):
                shutil.copytree(f, dst, symlinks=True)
            else:
                shutil.copy2(f, dst)

    if os.path.exists(old_pathsvc):
        shutil.rmtree(old_pathsvc)

    if os.path.islink(linksvc) and os.path.realpath(linksvc) == old_pathsvc:
        os.unlink(linksvc)

def install_profile():
    prof_d = os.path.join(os.sep, 'etc', 'profile.d')
    prof = os.path.join(prof_d, 'opensvc.sh')
    buff = "export PATH=$PATH:/opt/opensvc/bin:/opt/opensvc/etc\n"
    if not os.path.exists(prof_d):
        return
    with open(prof, 'w') as f:
        f.write(buff)

def install_user_linux():
    cmd = ['useradd', '-m', 'opensvc', '-s', '/bin/bash']
    process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
    buff = process.communicate()

def install_user():
    cmd = ['id', 'opensvc']
    process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
    buff = process.communicate()
    if process.returncode == 0:
        return

    if sysname == 'Linux':
        install_user_linux()

def install_bash_completion():
    src = '/opt/opensvc/usr/share/bash_completion.d/opensvc'
    ds = [os.path.join(os.sep, 'etc', 'bash_completion.d'),
          os.path.join(os.sep, 'etc', 'bash', 'bash_completion.d')]
    for d in ds:
        dst = os.path.join(d, 'opensvc')
        if not os.path.exists(d):
            d = None
            continue
        else:
            break
    if d is None:
        return
    shutil.copyfile(src, dst)
    os.chmod(dst, 0644)

def install_link(source, target):
    if source == '' or target == '':
        return False
    if os.path.realpath(source) == os.path.realpath(target):
        return True
    if os.path.exists(target):
        os.unlink(target)
    os.symlink(source,target)

def install_pythonlink():
    source =  os.path.join(python_path(), python_name)
    target = '/opt/opensvc/bin/python'
    return install_link(source=source, target=target)

def move_host_mode():
    hm = '/opt/opensvc/var/host_mode'
    cf = '/opt/opensvc/etc/node.conf'
    if not os.path.exists(hm):
        return
    try:
        fp = open(hm, 'r')
        mode = fp.read().split()[0]
        fp.close()
    except:
        print 'failed to read old host_mode. renamed to', hm+'.old'
        shutil.move(hm, hm+'.old')
        return
    cmd = ['/opt/opensvc/bin/nodemgr', 'set', '--param', 'node.host_mode', '--value', mode]
    process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
    buff = process.communicate()
    if process.returncode != 0:
        print 'failed to set host_mode in node.conf'
        return
    shutil.move(hm, hm+'.old')
 
def nodeconf_params():
    nodeconf = os.path.join(os.sep, 'opt', 'opensvc', 'etc', 'node.conf')
    if not os.path.exists(nodeconf):
        return
    import ConfigParser
    import copy
    config = ConfigParser.RawConfigParser()
    config.read(nodeconf)
    changed = False

    # no DEFAULT in etc/node.conf
    for o in copy.copy(config.defaults()):
        config.remove_option('DEFAULT', o)
        changed = True

    # sync section goes to etc/.node.conf
    if config.has_section('sync'):
        config.remove_section('sync')
        changed = True

    for s in config.sections():
        for o in config.options(s):
            if o in ['sync_interval', 'push_interval', 'comp_check_interval']:
                v = config.getint(s, o)
                config.remove_option(s, o)
                config.set(s, 'interval', v)
                changed = True
            if o in ['sync_days', 'push_days', 'comp_check_days']:
                v = config.get(s, o)
                config.remove_option(s, o)
                config.set(s, 'days', v)
                changed = True
            if o in ['sync_period', 'push_period', 'comp_check_period']:
                v = config.get(s, o)
                config.remove_option(s, o)
                config.set(s, 'period', v)
                changed = True

    if changed:
        try:
            fp = open(nodeconf, 'w')
            config.write(fp)
            fp.close()
        except:
            print >>sys.stderr, "failed to write new %s"%nodeconf

try:
    install_pythonlink()
    move_usr_to_opt()
    missing_dirs()
    convert_svclinks()
    install_cron()
    install_rc()
    gen_keys()
    install_profile()
    install_user()
    install_bash_completion()
    move_host_mode()
    nodeconf_params()
except:
    import traceback
    traceback.print_exc()
    import sys
    sys.exit(1)
  070701000671ae000041ed0000000000000000000000024d9d945500000000000000b600010002ffffffffffffffff0000001a00000000root/opt/opensvc/bin/cron 070701000671af000081ed0000000000000000000000014d9d7e6e000005b9000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/bin/cron/opensvc #!/opt/opensvc/bin/python
#
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import sys
import os

"""
When installed in /etc/cron.daily/ this must be a symlink to the
file in the opensvc distrib, wherever installed, so that we can compute
relative paths to locate libs
"""

pathsvc = os.path.realpath(os.path.join(os.path.dirname(__file__), '..', '..'))
pathlib = os.path.join(pathsvc, 'lib')
sys.path.append(pathlib)

import node
n = node.Node()

for action in ["pushstats", "pushpkg", "pushpatch", "pushservices",
               "pushasset", "checks", "syncservices", "compliance_check"]:
    try:
        n.action(action)
    except:
        import traceback
        traceback.print_exc()

   070701000671b4000081ed0000000000000000000000014d9d7e6e0000012c000000b600010002ffffffffffffffff0000002a00000000root/opt/opensvc/bin/opensvc.init.FreeBSD #!/bin/sh
#

# PROVIDE: opensvc
# REQUIRE: LOGIN sshd cleanvar
# BEFORE: 
# KEYWORD: shutdown

osvc_path=/opt/opensvc/bin
osvc_opts="--parallel"
allservices=${osvc_path}/allservices

case $1 in
faststart)
	${allservices} ${osvc_opts} boot
	;;
faststop)
	${allservices} ${osvc_opts} shutdown
	;;
esac
070701000671b3000081a40000000000000000000000014d9d7e6e000001b9000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/bin/opensvc.init.Darwin  <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Disabled</key>
	<false/>
	<key>Label</key>
	<string>com.opensvc.svcmgr</string>
	<key>ProgramArguments</key>
	<array>
		<string>/opt/opensvc/bin/allprimaryservices</string>
		<string>--parallel</string>
		<string>boot</string>
	</array>
</dict>
</plist>

   070701000671b5000081ed0000000000000000000000014d9d7e6e0000018c000000b600010002ffffffffffffffff0000002800000000root/opt/opensvc/bin/opensvc.init.SunOS   #!/bin/bash
#
#	/etc/init.d/opensvc
#
# Starts the services driven by OpenSVC
#
# description: Starts the services driven by OpenSVC whose
#              autostart node is this node.
# processname:

osvc_path=/opt/opensvc/bin
osvc_opts="--parallel"
allservices=${osvc_path}/allservices

case $1 in
start)
	${allservices} ${osvc_opts} boot
	;;
stop)
	${allservices} ${osvc_opts} shutdown
	;;
esac
070701000671b6000081ed0000000000000000000000014d9d7e6e000001c6000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/bin/opensvc.init.debian  #!/bin/sh -e

### BEGIN INIT INFO
# Provides:             opensvc
# Required-Start:       $all
# Required-Stop:        
# Default-Start:        2 3 4 5
# Default-Stop:         0 1 6
# Short-Description:    OpenSVC services startup script
### END INIT INFO

osvc_path=/opt/opensvc/bin
osvc_opts="--parallel"
allservices=${osvc_path}/allservices

case $1 in
start)
	${allservices} ${osvc_opts} boot
	;;
stop)
	${allservices} ${osvc_opts} shutdown
	;;
esac
  070701000671b7000081ed0000000000000000000000014d9d7e6e000002e2000000b600010002ffffffffffffffff0000002700000000root/opt/opensvc/bin/opensvc.init.hpux    #!/bin/sh

PATH=/sbin:/usr/sbin:/bin:/usr/bin
export PATH

if [ -r /etc/rc.config.d/opensvc ] ; then 
    . /etc/rc.config.d/opensvc
fi

osvc_path=/opt/opensvc/bin
osvc_opts="--parallel"
allservices=${osvc_path}/allservices
agt=${osvc_path}/perfagt.`uname -s`

case $1 in
start_msg)
	if [ "$RUN_OPENSVC" -ne 0 ] ; then
		echo "Starting opensvc services"
	fi
	;;
start)
	if [ "$RUN_OPENSVC" -ne 0 ] ; then
		echo "Starting opensvc services"
	fi
	if [ -x $agt ] ; then
		$agt
	fi
	${allservices} ${osvc_opts} boot
	;;
stop_msg)
	if [ "$RUN_OPENSVC" -ne 0 ] ; then
		echo "Shutting down opensvc services"
	fi
	;;
stop)
	if [ "$RUN_OPENSVC" -ne 0 ] ; then
		echo "Starting opensvc services"
	fi
	${allservices} ${osvc_opts} shutdown
	;;
esac
  070701000671ba000081ed0000000000000000000000014d9d7e6e00000bf0000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/bin/perfagt.HP-UX    #!/opt/opensvc/bin/python

import os
import sys
import socket
import datetime
from subprocess import *

pathsvc = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(os.path.join(pathsvc, 'lib'))

import xmlrpcClient
from rcUtilities import justcall, is_exe

nodename = socket.gethostname()
now = str(datetime.datetime.now())

def fs_u():
    vars = ['date',
            'nodename',
            'mntpt',
            'size',
            'used']

    cmd = ['bdf', '-l']
    (out, err, ret) = justcall(cmd)
    if ret != 0:
        return self.undef
    lines = out.split('\n')
    if len(lines) < 2:
        return self.undef
    vals = []
    for line in lines[1:]:
        l = line.split()
        if len(l) != 6:
            continue
        vals.append([now, nodename, l[5], l[1], l[4].replace('%','')])
    return (vars, vals)

def glance_running(cmd_str):
    (out, err, ret) = justcall(['ps', '-ef'])
    if ret != 0:
        print 'ps error'
        return

    for line in out.split('\n'):
        l = line.split()
        if len(l) < 6:
            continue
        if cmd_str in ' '.join(l[6:]):
            return True

    return False

def run_glance():
    glance = '/opt/perf/bin/glance'
    syn = '/opt/opensvc/tmp/glance.syntax'
    now = datetime.datetime.now()
    iterations = (23-now.hour)*6+(60-now.minute)//10
    cmd = ['/opt/perf/bin/glance', '-aos', syn, '-j', '600', '-iterations']
    cmd_str = ' '.join(cmd)

    if not is_exe(glance):
        print 'glance executable not found'
        return

    if glance_running(cmd_str):
        print 'glance is already running'
        return

    buff = """print GBL_STATTIME,
// usr
0.00+GBL_CPU_NORMAL_UTIL+GBL_CPU_REALTIME_UTIL,
// nice
0.00+GBL_CPU_NICE_UTIL+GBL_CPU_NNICE_UTIL,
// sys
0.00+GBL_CPU_SYSCALL_UTIL+GBL_CPU_CSWITCH_UTIL+GBL_CPU_TRAP_UTIL+GBL_CPU_VFAULT_UTIL,
// irq
0.00+GBL_CPU_INTERRUPT_UTIL,
// wait
0.00+GBL_CPU_WAIT_UTIL,
// idle
0.00+GBL_CPU_IDLE_UTIL-GBL_CPU_WAIT_UTIL,

// mem
0+GBL_MEM_PHYS,
0+GBL_MEM_FREE,
0+GBL_MEM_CACHE,
0+GBL_MEM_FILE_PAGE_CACHE,
0+GBL_MEM_SYS,
0+GBL_MEM_USER,

// swap
0+GBL_MEM_SWAP,
0+GBL_SWAP_SPACE_AVAIL-GBL_MEM_PHYS,

// load
GBL_LOADAVG,
GBL_LOADAVG5,
GBL_LOADAVG15,
GBL_CPU_QUEUE,

// process list
TBL_PROC_TABLE_USED,

// disk io
GBL_DISK_PHYS_READ_RATE,
GBL_DISK_PHYS_WRITE_RATE,

// disk kB/s
GBL_DISK_PHYS_READ_BYTE_RATE,
GBL_DISK_PHYS_WRITE_BYTE_RATE
"""
    try:
        with open(syn, 'w') as f:
            f.write(buff)
    except:
        print 'error writing %s'%syn
        return

    collect_d = '/opt/opensvc/var/'
    collect_f = 'glance%0.2d'%now.day
    collect_p = os.path.join(collect_d, collect_f)

    if os.path.exists(collect_p):
        mtime = os.stat(collect_p).st_mtime
        if datetime.datetime.fromtimestamp(mtime) < now - datetime.timedelta(days=1):
            os.unlink(collect_p)

    _cmd = 'nohup %s %d >>%s &'%(cmd_str, iterations, collect_p)
    process = Popen(_cmd, shell=True, stdout=PIPE, stderr=PIPE)


run_glance()
xmlrpcClient.push_stats_fs_u(fs_u())

070701000671b0000081ed0000000000000000000000014d9d7e6e00000554000000b600010002ffffffffffffffff0000001d00000000root/opt/opensvc/bin/freezer  #!/opt/opensvc/bin/python
#
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import sys
import os

#
# add project lib to path
#
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'lib'))

from freezer import Freezer
from rcUtilities import check_privs

check_privs()

if len(sys.argv) == 1:
	f = Freezer()
elif len(sys.argv) == 2:
	f = Freezer(sys.argv[1])
else:
	print __file__ + " [service]"
	sys.exit(1)

cmd = os.path.basename(__file__)
if cmd == 'svcfreeze':
	sys.exit(f.freeze())
elif cmd == 'svcthaw':
	sys.exit(f.thaw())
elif cmd == 'svcfrozen':
	sys.exit(int(f.frozen()))
070701000671b2000081ed0000000000000000000000014d9d7e6e000000d1000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/bin/opensvc.init.AIX #!/bin/ksh

osvc_path=/opt/opensvc/bin
osvc_opts="--parallel"
allservices=${osvc_path}/allservices

case $1 in
start)
	${allservices} ${osvc_opts} boot
	;;
stop)
	${allservices} ${osvc_opts} shutdown
	;;
esac
   070701000671b1000081ed0000000000000000000000014d9d7e6e000010fa000000b600010002ffffffffffffffff0000001d00000000root/opt/opensvc/bin/nodemgr  #!/opt/opensvc/bin/python
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import sys
import os
import optparse

#
# add project lib to path
#
pathsvc = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
pathetc = os.path.join(pathsvc, 'etc')
sys.path.append(os.path.join(pathsvc, 'lib'))
prog = os.path.basename(__file__)

import rcExceptions as ex
import node
from rcGlobalEnv import *

try:
    from version import version
except:
    version = "dev"

n = node.Node()
__ver = prog + " version " + version
__usage = "%prog [options] command\n\n" + n.format_desc()
parser = optparse.OptionParser(version=__ver, usage=__usage)
parser.add_option("--debug", default=False,
		  action="store_true", dest="debug",
                  help="debug mode")
parser.add_option("--stats-dir", default=None,
		  action="store", dest="stats_dir",
                  help="points the directory where the metrics files are stored for pushstats")
parser.add_option("--stats-start", default=None,
		  action="store", dest="stats_start",
                  help="stats analysis start date in YYYY-MM-DD HH:MM format")
parser.add_option("--stats-end", default=None,
		  action="store", dest="stats_end",
                  help="stats analysis end date in YYYY-MM-DD HH:MM format")
parser.add_option("--module", default="",
		  action="store", dest="module",
                  help="compliance, set module list")
parser.add_option("--moduleset", default="",
		  action="store", dest="moduleset",
                  help="compliance, set moduleset list. The 'all' value can be used in conjonction with detach.")
parser.add_option("--ruleset", default="",
		  action="store", dest="ruleset",
                  help="compliance, set ruleset list. The 'all' value can be used in conjonction with detach.")
parser.add_option("--ruleset-date", default="",
		  action="store", dest="ruleset_date",
                  help="compliance, use rulesets valid on specified date")
parser.add_option("--force", default=False,
		  action="store_true", dest="force",
                  help="force action")
parser.add_option("--symcli-db-file", default=None,
		  action="store", dest="symcli_db_file",
                  help="[pushsym option] use symcli offline mode with the specified file. aclx files are expected to be found in the same directory and named either <symid>.aclx or <same_prefix_as_bin_file>.aclx")
parser.add_option("--param", default=None,
		  action="store", dest="param",
                  help="point a node configuration parameter for the 'get' and 'set' actions")
parser.add_option("--value", default=None,
		  action="store", dest="value",
                  help="set a node configuration parameter value for the 'set --param' action")

(options, args) = parser.parse_args()

n.options = options

def do_symcli_db_file(symcli_db_file):
    if symcli_db_file is None:
        return
    if not os.path.exists(symcli_db_file):
        print "File does not exist: %s"%symcli_db_file
        return
    os.environ['SYMCLI_DB_FILE'] = symcli_db_file
    os.environ['SYMCLI_OFFLINE'] = '1'
    
do_symcli_db_file(options.symcli_db_file)

if len(args) is 0:
    parser.error("Missing action")
action = '_'.join(args)
if not action in n.action_desc:
    parser.error("unsupported action: %s"%action)

try:
    n.action(action)
except ex.excError:
    import traceback
    exc_type, exc_value, exc_traceback = sys.exc_info()
    sys.stderr.write(str(exc_value)+'\n')
    sys.exit(1)
except KeyboardInterrupt:
    sys.stderr.write("Keybord Interrupt\n")
    sys.exit(1)
except:
    raise

  070701000671b9000081ed0000000000000000000000014d9d7e6e000009ea000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/bin/perfagt.Darwin   #!/usr/bin/python2.6

import os
import sys
import socket
import datetime

pathsvc = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(os.path.join(pathsvc, 'lib'))

import xmlrpcClient
from rcUtilities import justcall

nodename = socket.gethostname()
now = datetime.datetime.now()

def fs_u():
    vars = ['date',
            'nodename',
            'mntpt',
            'size',
            'used']

    cmd = ['df', '-lkP']
    (out, err, ret) = justcall(cmd)
    if ret != 0:
        return self.undef
    lines = out.split('\n')
    if len(lines) < 2:
        return self.undef
    vals = []
    for line in lines[1:]:
        l = line.split()
        if len(l) != 6:
            continue
        if l[5].startswith('/Volumes'):
            # Darwin automount package files under /Volumes
            continue
        vals.append([str(now), nodename, l[5], l[1], l[4].replace('%','')])
    return (vars, vals)

def mem_u():
    basedir = os.path.join(pathsvc, 'var', 'stats')
    if not os.path.exists(basedir):
        os.makedirs(basedir)
    fname = os.path.join(basedir, 'mem_u%0.2d'%now.day)
    if not os.path.exists(fname):
        try:
            f = open(fname, 'w')
        except:
            return
    else:
        mtime = os.stat(fname).st_mtime
        if datetime.datetime.fromtimestamp(mtime) < now - datetime.timedelta(days=1):
            os.unlink(fname)
            try:
                f = open(fname, 'w')
            except:
                return
        else:
            try:
                f = open(fname, 'a')
            except:
                return
 

    cmd = ['/usr/sbin/sysctl', '-n', 'hw.pagesize']
    (out, err, ret) = justcall(cmd)
    if ret != 0:
        return
    pagesize = int(out.split()[0])

    cmd = ['vm_stat']
    (out, err, ret) = justcall(cmd)
    if ret != 0:
        return
    h = {}
    for line in out.split('\n'):
        l = line.split(':')
        if len(l) != 2:
            continue
        key = l[0]
        try:
            val = int(l[1].strip(' .'))
        except:
            continue
        h[key] = val
    f.write(' '.join((now.strftime('%H:%M:%S'),
                      str(h['Pages free']*pagesize/1024),
                      str(h['Pages active']*pagesize/1024),
                      str(h['Pages inactive']*pagesize/1024),
                      str(h['Pages speculative']*pagesize/1024),
                      str(h['Pages wired down']*pagesize/1024)
            ))+'\n')


xmlrpcClient.push_stats_fs_u(fs_u())
mem_u()
  070701000671bb000081ed0000000000000000000000014d9d7e6e0000035b000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/bin/perfagt.Linux    #!/usr/bin/python2.6

import os
import sys
import socket
import datetime

pathsvc = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
sys.path.append(os.path.join(pathsvc, 'lib'))

import xmlrpcClient
from rcUtilities import justcall

nodename = socket.gethostname()
now = str(datetime.datetime.now())

def fs_u():
    vars = ['date',
            'nodename',
            'mntpt',
            'size',
            'used']

    cmd = ['df', '-lP']
    (out, err, ret) = justcall(cmd)
    if ret != 0:
        return self.undef
    lines = out.split('\n')
    if len(lines) < 2:
        return self.undef
    vals = []
    for line in lines[1:]:
        l = line.split()
        if len(l) != 6:
            continue
        vals.append([now, nodename, l[5], l[1], l[4].replace('%','')])
    return (vars, vals)

xmlrpcClient.push_stats_fs_u(fs_u())
 070701000671bc000041ed0000000000000000000000024d9d945500000000000000b600010002ffffffffffffffff0000001900000000root/opt/opensvc/bin/pkg  070701000671c2000081ed0000000000000000000000014d9d7e6e00000790000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/bin/pkg/make_tbz #!/usr/bin/env bash

PATH_SCRIPT="$(cd $(/usr/bin/dirname $(type -p -- $0 || echo $0));pwd)"
. $PATH_SCRIPT/make.lib

TBZ=$CHROOT/opensvc-$VERSION.$RELEASE.tbz
CHROOT=$CHROOT/opensvc-$VERSION.$RELEASE
DISTFILES_D=/usr/ports/distfiles
TAR=opensvc-$VERSION.$RELEASE.tar.gz

prepare_chroot || exit 1

cd $CHROOT/.. || exit 1
tar czf $DISTFILES_D/$TAR opensvc-$VERSION.$RELEASE || exit 1

cat - <<EOF >Makefile
# New ports collection makefile for:   opensvc
# Date created:        $(date +"%d %B %Y")
# Whom:                opensvc
#
# \$FreeBSD$
#

PORTNAME=      opensvc
PORTVERSION=   $VERSION.$RELEASE
CATEGORIES=    sysutils
MASTER_SITES=  http://repo.opensvc.com/tgz

MAINTAINER=    admin@opensvc.com
COMMENT=       OpenSVC service manager

#MAN1=          svcmgr.3
#MANCOMPRESSED= yes

USE_PYTHON=    2.6+
DEST_DIR=      /
PREFIX=        /
NO_BUILD=      yes

do-install:
	\${CP} -a \${WRKSRC}/* \${PREFIX}/
	\${PREFIX}/opt/opensvc/bin/postinstall

.include <bsd.port.mk>

EOF

cat - <<-EOF >pkg-descr
OpenSVC is a 'service' manager, as in clustered service manager, designed for real-world heterogeneous datacenters and large-scale operations like disaster recovery.

Services are collections of resources (virtual machine, ip, disk groups, filesystems, file synchronizations, and application launchers).

Services can be started, stopped and queried for status, providing a consistent command set for wildly different service integration types.

Service configurations, status and logs are pushed to a central database coupled to a web front-end (collector).

Services can be administered using the stand-alone GPLv2 software stack deployed on the nodes (nodeware), or through the web-front end.

WWW: http://www.opensvc.com/
EOF

cd $CHROOT
find opt -type f -o -type l >../pkg-plist
find opt/opensvc -type d | sed "s/^/@dirrm /" >>../pkg-plist
cd ..

make package

[ -x $PATH_SCRIPT/release_tbz ] && $PATH_SCRIPT/release_tbz $TBZ
070701000671c1000081ed0000000000000000000000014d9d7e6e00000376000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/bin/pkg/make_rpm #!/bin/bash

PATH_SCRIPT="$(cd $(/usr/bin/dirname $(type -p -- $0 || echo $0));pwd)"
. $PATH_SCRIPT/make.lib

prepare_chroot || exit 1

SPEC=$OSVC/tmp/SPECS/opensvc.spec

cat - <<-EOF >$SPEC
Summary: OpenSVC node tools
Name: opensvc
Version: $VERSION
Release: $RELEASE
License: GPLv2
Group: Administration/Tools
BuildRoot: $CHROOT
Requires: /usr/bin/python2.6

%description
These are the tools to drive OpenSVC services
%post
/opt/opensvc/bin/postinstall
%files
%docdir /opt/opensvc/usr/share
%defattr(-,root,root)
%attr(0755,root,root) /opt/opensvc/bin
/opt/opensvc/lib
/opt/opensvc/etc
/opt/opensvc/log
/opt/opensvc/tmp
/opt/opensvc/var
/opt/opensvc/usr

#%changelog
#\$(changelog)
EOF

sudo rpmbuild --target=noarch --define "_topdir $OSVC/tmp" --clean -bb $SPEC

[ -x $PATH_SCRIPT/release_rpm ] && $PATH_SCRIPT/release_rpm $OSVC/tmp/RPMS/noarch/opensvc-$VERSION-$RELEASE.noarch.rpm
  070701000671be000081ed0000000000000000000000014d9d7e6e00000379000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/bin/pkg/make_deb #!/bin/bash
PATH_SCRIPT="$(cd $(/usr/bin/dirname $(type -p -- $0 || echo $0));pwd)"
. $PATH_SCRIPT/make.lib

DEB=opensvc-$VERSION-$RELEASE.noarch.deb

prepare_chroot || exit 1

# prepare control.tar.gz
mkdir -p $CHROOT/DEBIAN || exit 1

cat - <<-EOF >$CHROOT/DEBIAN/conffiles
EOF

cat - <<-EOF >$CHROOT/DEBIAN/postinst
#!/bin/sh
/opt/opensvc/bin/postinstall
EOF
chmod 755 $CHROOT/DEBIAN/postinst

cat - <<-EOF >$CHROOT/DEBIAN/control
Package: opensvc
Version: $RELEASE-$VERSION
Section: system 
Priority: optional
Architecture: all
Essential: no
Depends: python2.6
Pre-Depends: 
Recommends: sg3-utils
Suggests: 
Installed-Size: 50
Maintainer: Christophe Varoqui [christophe.varoqui@opensvc.com]
Conflicts: 
Replaces: 
Provides: opensvc
Description: tools to drive OpenSVC services
EOF

dpkg -b $CHROOT || exit 1

[ -x $PATH_SCRIPT/release_deb ] && $PATH_SCRIPT/release_deb $CHROOT/../$DEB
   070701000671bf000081ed0000000000000000000000014d9d7e6e000009d1000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/bin/pkg/make_depot   #!/bin/bash

PATH_SCRIPT="$(cd $(/usr/bin/dirname $(type -p -- $0 || echo $0));pwd)"

function date_to_release {
	date -d "$*" +%y%m%d.%H%M
}

HEAD=$(git log -1 --pretty=format:%aD || exit 1)
VERSION=1.0
RELEASE=$(date_to_release $HEAD)
OSVC=$PATH_SCRIPT/../..
CHROOT_BN=opensvc-$VERSION-$RELEASE.noarch
CHROOT=$OSVC/tmp/BUILDROOT/$CHROOT_BN
PSF=opensvc.psf
DEPOTDIR=$OSVC/tmp/DEB
DEPOT=opensvc-$VERSION-$RELEASE.depot
REMOTEHOST=${1:-s64lmwbicb6.dsit.sncf.fr}

#
# prepare skeleton (data.tar.gz)
#
[ "${CHROOT%%noarch}" != "$CHROOT" ] && rm -rf $CHROOT
mkdir -p $CHROOT/opt/opensvc/etc || exit 1
mkdir -p $CHROOT/opt/opensvc/var || exit 1
mkdir -p $CHROOT/opt/opensvc/log || exit 1
mkdir -p $CHROOT/opt/opensvc/tmp || exit 1
mkdir -p $CHROOT/opt/opensvc/var/cache || exit 1

# install tracked files
EXCL=
EXCL="$EXCL --exclude=bin/pkg"
EXCL="$EXCL --exclude=*.pyc"
EXCL="$EXCL --exclude='log/*'"
EXCL="$EXCL --exclude='etc/*'"
EXCL="$EXCL --exclude='tmp/*'"
EXCL="$EXCL --exclude=var/host_mode"
EXCL="$EXCL --exclude='var/lock/*'"
EXCL="$EXCL --exclude='var/cache/*'"
EXCL="$EXCL --exclude=lib/rcLocalEnv.py"
cd $OSVC || exit 1
tar cf - $EXCL bin lib usr var/compliance/*com.opensvc.*| tar xf - -C $CHROOT/opt/opensvc || exit 1
#touch $CHROOT/opt/opensvc/var/host_mode || exit 1
echo "version = \"$VERSION-$RELEASE\"" > $CHROOT/opt/opensvc/lib/version.py || exit 1

# symbolic links
cd $CHROOT || exit 1

cat - <<-EOF >$CHROOT/../$PSF
vendor
  tag           opensvc
  title         Opensvc SARL
  description   opensvc nodeware
end
product
  tag            opensvc
  title          opensvc
  revision       $VERSION-$RELEASE
  category       system_management
  description    tools to drive OpenSVC services
  copyright      Opensvc SARL
  architecture   HP-UX_10.20_700/800
  machine_type   *
  os_name        HP-UX
  os_release     *
  directory      /
  is_locatable   false
  fileset
    tag          commands
    title        Commands (management utilities)
    revision     1.0
    prerequisite Python.PYTHON-RUN
    postinstall  /tmp/$CHROOT_BN/opt/opensvc/bin/postinstall
    file_permissions -o root -g sys
    directory    /tmp/$CHROOT_BN=/
    file         *
  end
end
EOF

cd $CHROOT/.. || exit 1
tar cf - $CHROOT_BN $PSF | ssh root@$REMOTEHOST "cd /tmp && tar xf -"
ssh root@$REMOTEHOST "cd /tmp && swpackage -vv -s opensvc.psf -x target_type=tape @/tmp/$DEPOT"
scp root@$REMOTEHOST:/tmp/$DEPOT $OSVC/tmp/ || exit 1

[ -x $PATH_SCRIPT/release_depot ] && $PATH_SCRIPT/release_depot $OSVC/tmp/$DEPOT
   070701000671bd000081a40000000000000000000000014d9d7e6e00000710000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/bin/pkg/make.lib function changelog {
        git log --pretty=format:"* %ad - %ae%n- %s" | sed -e "s/ [0-9]*:[0-9]*:[0-9]*//" -e "s/ +[0-9]* -/ -/"
}

function date_to_release {
        if [ "$(uname -s)" == "FreeBSD" ] ; then
		date -f "%a, %d %b %Y %H:%M:%S %z" "$*" +%y%m%d.%H%M
	else
		date -d "$*" +%y%m%d.%H%M
	fi
}

HEAD=$(git log -1 --pretty=format:%aD || exit 1)
VERSION=$(git describe --tags --abbrev=0)
MASTER=0
git branch | grep "\* master" >/dev/null 2>&1 && MASTER=1
if [ $MASTER -eq 1 ] ; then
	RELEASE=$(date_to_release $HEAD)
else
	RELEASE=$(git describe --tags|cut -d- -f2)
        if [ "$RELEASE" = "$VERSION" ] ; then
            RELEASE="0"
        fi   
fi
OSVC=$PATH_SCRIPT/../..
CHROOT=$OSVC/tmp/BUILDROOT/opensvc-$VERSION-$RELEASE.noarch

if [ "$(id -u)" == "0" ] ; then
	SUDO=""
else
	SUDO="sudo"
fi

function prepare_chroot {
	#
	# prepare skeleton (data.tar.gz)
	#
	[ "${CHROOT%%noarch}" != "$CHROOT" ] && $SUDO rm -rf $CHROOT
	mkdir -p $CHROOT/opt/opensvc/etc || return 1
	mkdir -p $CHROOT/opt/opensvc/var || return 1
	mkdir -p $CHROOT/opt/opensvc/log || return 1
	mkdir -p $CHROOT/opt/opensvc/tmp || return 1
	mkdir -p $CHROOT/opt/opensvc/var/cache || return 1

	# install tracked files
	EXCL=
	EXCL="$EXCL --exclude=bin/pkg"
	EXCL="$EXCL --exclude=*.pyc"
	EXCL="$EXCL --exclude='log/*'"
	EXCL="$EXCL --exclude='etc/*'"
	EXCL="$EXCL --exclude='tmp/*'"
	EXCL="$EXCL --exclude=var/host_mode"
	EXCL="$EXCL --exclude='var/lock/*'"
	EXCL="$EXCL --exclude='var/cache/*'"
	EXCL="$EXCL --exclude=lib/rcLocalEnv.py"
	cd $OSVC || return 1
	tar cf - $EXCL bin lib usr var/compliance/*com.opensvc.* | tar xf - -C $CHROOT/opt/opensvc || return 1
	echo "version = \"$VERSION-$RELEASE\"" > $CHROOT/opt/opensvc/lib/version.py || return 1
        $SUDO chown -R 0:0 $CHROOT/opt/opensvc || return 1
	return 0
}

070701000671c0000081ed0000000000000000000000014d9d7e6e000012c0000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/bin/pkg/make_pkg #!/bin/ksh -p

NAWK=nawk;
PKGNAME=opensvc
VERSION=1.0
ARCH=${ARCH:-all}
BASE=/opt/opensvc
REV=$(date +%y%m%d.%H%M)
IPSREV=$(date +%y%m%d%H%M)
P=${PKGNAME}-$VERSION-$REV.SunOS.pkg
IPSP=${PKGNAME}@$(uname -r),$(uname -r)-$VERSION.$IPSREV
#IPSP=pkgname@osrev,osrev,version[:timestampiso8601]
REPODIR=$(cd $(dirname $0);pwd)
export REPODIR
PATH=$PWD:$PATH:/opt/sfw/bin

TMPARCHIVE=/var/tmp/tmparchive$$
TMPROOT=$TMPARCHIVE

LANG=C
export LANG

function date_to_release {
        date -d "$*" +%y%m%d.%H%M
}

HEAD=$(git log -1 --pretty=format:%aD  || exit 1)
RELEASE=$(date_to_release $HEAD)

function my_log {
	echo $@
}

function question {
	# usage: question default_value Comment 
	typeset DEFAULT=$1
	typeset READ
	shift
	read READ?"$* [${SGRAS}$DEFAULT${EGRAS}]:"
	echo ${READ:-$DEFAULT}
}

function create_pkg {
	typeset SGRAS="[1m"
	typeset EGRAS="[0m"

	typeset POSTINSTALL=""
	typeset PREINSTALL=""
	typeset PRE_REMOVE=""
	typeset POST_REMOVE=""

	while getopts hp:P:r:R: ARGS
	do
	  case $ARGS in
	  h) usage
	     return 1
	     ;;
	  p) PREINSTALL="$OPTARG"
	     ;;
	  P) POSTINSTALL="$OPTARG"
	     ;;
	  r) PRE_REMOVE="$OPTARG"
	     ;;
	  R) POST_REMOVE="$OPTARG"
	     ;;
	  ?) usage
	     ;;
	  esac
	done
	shift `expr $OPTIND - 1`

	set -- $*
	[ $# -lt 2 ] && usage
	PROTOTYPE=/tmp/prototype.$$
	PKGINFO=/tmp/pkginfo.$$
	PKG_FILE_NAME=$1
	shift
	FILES=$*
	if [ "$FILES" = "" ] ; then
		my_log "no file names..."
		usage
	fi

	[ -f $PROTOTYPE ] && my_log "deleting $PROTOTYPE" && rm $PROTOTYPE


	PKG=`question $PKG_FILE_NAME "The name you have chosen for the pkg directory"`
	NAME=`question $PKG "The program name"`
	ARCH=`question sparc "The operating systeme version"`
	VERSION=`question "1" "The version number for your program"`
	CATEGORY=`question application "The program is an application"`
	VENDOR=`question "$LOGNAME@$(uname -n)" "whoever wrote the software"`
	EMAIL=`question "$VENDOR" "An email contact"`
	PSTAMP=`question "$VENDOR" "The person who did the port perhaps"`
	RULES=`question "$FILES=$FILES" "rules for source->dest ex: /usrlocalbin=/usr/local/bin /optlocal=/opt/local "`
	CLASSES=`question "none" "Classe"`

	my_log "creating prototype in $PROTOTYPE"
	> $PROTOTYPE
	[ "$PKGINFO" != "" ] && echo "i pkginfo=$PKGINFO" >> $PROTOTYPE
	[ "$POSTINSTALL" != "" ] && echo "i postinstall=$POSTINSTALL" >> $PROTOTYPE
	[ "$PREINSTALL" != "" ] && echo "i preinstall=$PREINSTALL" >> $PROTOTYPE
	[ "$PRE_REMOVE" != "" ] && echo "i preremove=$PRE_REMOVE" >> $PROTOTYPE
	[ "$POST_REMOVE" != "" ] && echo "i postremove=$POST_REMOVE" >> $PROTOTYPE
	[ ! -s $PROTOTYPE ] && my_log "warning $PROTOTYPE size null" && return 1

	pkgproto $RULES >> $PROTOTYPE

	my_log "creating pkginfo file : $PKGINFO"
	echo "PKG=$PKG\nNAME=$NAME\nARCH=$ARCH\nVERSION=$VERSION\nCATEGORY=$CATEGORY" > $PKGINFO
	echo "VENDOR=$VENDOR\nEMAIL=$EMAIL\nPSTAMP=$PSTAMP\nCLASSES=$CLASSES" >> $PKGINFO

	my_log "running pkgmk to create /var/spool/pkg/$PKG : pkgmk -o -f $PROTOTYPE"
	pkgmk -o -f $PROTOTYPE

	my_log "running pkgtrans to create /tmp/$PKG_FILE_NAME : pkgtrans -s /var/spool/pkg /tmp/$PKG_FILE_NAME $PKG"
	pkgtrans -s /var/spool/pkg /tmp/$PKG_FILE_NAME $PKG
	STATUS=$?

	if [ $STATUS -eq 0 ] ; then
		echo "Cleaning temp files: $PROTOTYPE $PKGINFO" 
		rm $PKGINFO $PROTOTYPE
		echo
		echo "Package $PKG created successfully"
		pkginfo -d /tmp/$PKG_FILE_NAME -l
	else
		echo
		echo "Warning some errors in create_pkg"
	fi
	return $STATUS
}

if [ -d $TMPARCHIVE ] ; then
	echo "Error $TMPARCHIVE already exists"
	echo "It should be removed first"       
	exit 1
fi

echo "----- git archive current to $TMPARCHIVE ..."
mkdir $TMPARCHIVE
cd $BASE && git archive --format=tar HEAD | (
	cd $TMPARCHIVE && tar xf - 			\
	&& rm $TMPARCHIVE/.gitignore			\
	&& chown -R root:root $TMPARCHIVE		\
	&& chmod -R og-w $TMPARCHIVE
	)
cd $REPODIR 

echo "version = \"$VERSION-$RELEASE\"" > $TMPARCHIVE/lib/version.py

cat > $REPODIR/postinstall <<EOF
#!/sbin/sh

su - root -c "LD_LIBRARY_PATH=/opt/opensvc/usr/local/lib:\$LD_LIBRARY_PATH PATH=/opt/opensvc/usr/local/bin:$PATH:/usr/sfw/bin:/usr/local/bin $BASE/bin/postinstall"
EOF

echo "----- Creating $PKGNAME build-$REV ..."
create_pkg -P $REPODIR/postinstall $PKGNAME $TMPROOT=$BASE 2> /dev/null <<EOF

opensvc Service Manager for logical servers v${VERSION}-$REV
$ARCH
$VERSION

http://www.opensvc.com
support@opensvc.com
OPENSVC-${VERSION}-${REV}
$TMPROOT=$BASE

EOF

echo "----- Cleaning /var/spool/pkg/$PKGNAME $TMPARCHIVE $REPODIR/postinstall"
[ "$PKGNAME" != "" ] && [ -d /var/spool/pkg/$PKGNAME ] && rm -r /var/spool/pkg/$PKGNAME
[ -d $TMPARCHIVE ] && rm -r $TMPARCHIVE
rm $REPODIR/postinstall

echo "----- New package available into /tmp/$P"
cp /tmp/$PKGNAME /tmp/$P && rm /tmp/$PKGNAME

[ -x $REPODIR/release_pkg ] && $REPODIR/release_pkg $P $IPSP
070701000671b8000081ed0000000000000000000000014d9d7e6e000001dc000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/bin/opensvc.init.redhat  #!/bin/bash
#
#	/etc/rc.d/init.d/opensvc
#
# Starts the services driven by OpenSVC
#
# chkconfig: 345 99 01
# description: Starts the services driven by OpenSVC whose
#              autostart node is this node.
# processname:

# Source function library.
. /etc/init.d/functions

osvc_path=/opt/opensvc/bin
osvc_opts="--parallel"
allservices=${osvc_path}/allservices

case $1 in
start)
	${allservices} ${osvc_opts} boot
	;;
stop)
	${allservices} ${osvc_opts} shutdown
	;;
esac
070701000671c5000081ed0000000000000000000000014d9d7e6e00001514000000b600010002ffffffffffffffff0000001c00000000root/opt/opensvc/bin/svcmon   #!/opt/opensvc/bin/python
#
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import sys
import os
import optparse
import string

#
# add project lib to path
#
pathsvc = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
pathetc = os.path.join(pathsvc, 'etc')
sys.path.append(os.path.join(pathsvc, 'lib'))
prog = os.path.basename(__file__)

import svcBuilder
import xmlrpcClient
import rcExceptions as ex
from rcUtilities import *
from lock import *

try:
    from version import version
except:
    version = "dev"

def svcmon_verbose(svcs):
    for svc in svcs:
        print banner(svc.svcname)
        try:
            svc.print_status()
        except:
            pass

def max_len(svcs, attr):
    _len = 7
    for svc in svcs:
        if _len < len(getattr(svc, attr)):
            _len = len(getattr(svc, attr))
    return _len

def svcmon_normal1(svc, upddb=False, fmt=None, queue=None):
    status = svc.group_status()
    print fmt % (
              svc.svcname,
              svc.svctype,
              svc.svcmode,
              status["container"],
              status["ip"],
              status["disk"],
              status["fs"],
              status["app"],
              status["hb"],
              status["sync"],
              status["avail"],
              status["overall"],
              svc.frozen())
    if upddb:
        lockf = 'svcmon.'+svc.svcname+'.lock'
	try:
	    lockfd = monlock(fname=lockf)
	except ex.excError:
	    sys.exit(1)

        if queue is None:
            # multiprocess Queue not supported, can't combine results
            g_vars, g_vals, r_vars, r_vals = svc.svcmon_push_lists(status)
            xmlrpcClient.svcmon_update_combo(g_vars, g_vals, r_vars, r_vals)
        else:
            queue.put(svc.svcmon_push_lists(status))

	try:
	    monunlock(lockfd)
	except ex.excError:
	    sys.exit(1)

def svcmon_normal(svcs, upddb=False):
    fmt = '%-' + str(max_len(svcs, "svcname")) + 's'
    fmt += ' %-7s %-9s %-9s %-9s %-10s %-10s %-10s %-9s %-9s %-10s %-10s %-6s'

    print fmt % ("service", "service", "container", "container", "ip    ", "disk  ", "fs    ", "app   ", "hb    ", "sync  ", "avail ", "overall", "      ")
    print fmt % ("name   ", "type   ", "type     ", "status   ", "status", "status", "status", "status", "status", "status", "status", "status ", "frozen")
    print fmt % ("-------", "-------", "---------", "---------", "------", "------", "------", "------", "------", "------", "------", "-------", "------")
    from multiprocessing import Process, Queue
    ps = []
    queues = {}
    for svc in svcs:
        try:
            queues[svc.svcname] = Queue()
        except:
            # some platform don't support Queue's synchronize (bug 3770)
            queues[svc.svcname] = None
        p = Process(target=svcmon_normal1, args=(svc, upddb, fmt, queues[svc.svcname]))
        p.start()
        ps.append(p)
    for p in ps:
        p.join()

    if upddb:
        g_vals = []
        r_vals = []
        if options.delay > 0:
            import random
            import time
            delay = int(random.random()*options.delay)
            time.sleep(delay)

        for svc in svcs:
            if queues[svc.svcname] is None:
                continue
            g_vars, _g_vals, r_vars, _r_vals = queues[svc.svcname].get()
            g_vals.append(_g_vals)
            r_vals.append(_r_vals)
        if len(g_vals) > 0:
            xmlrpcClient.svcmon_update_combo(g_vars, g_vals, r_vars, r_vals)

svcs = []
__ver = prog + " version " + version
__usage = "%prog [options]\n\nDisplay services status"
parser = optparse.OptionParser(version=__ver, usage=__usage)
parser.add_option("--service", default="", action="store", dest="parm_svcs",
                  help="comma-separated list of service to display status of")
parser.add_option("--updatedb", default=False, action="store_true", dest="upddb",
                  help="update resource status in central database")
parser.add_option("--verbose", default=False, action="store_true", dest="verbose",
                  help="display per-resource status for each selected service")
parser.add_option("--maxdelaydb", default=0, action="store", type="int", dest="delay",
                  help="introduce a random delay before pushing to database to level the load on the collector")

(options, args) = parser.parse_args()

if len(options.parm_svcs) > 0:
    svcs = svcBuilder.build_services(svcnames=options.parm_svcs.split(','))
else:
    svcs = svcBuilder.build_services()

if options.verbose:
    svcmon_verbose(svcs)
else:
    svcmon_normal(svcs, options.upddb)

070701000671c6000041ed0000000000000000000000024d9d945500000000000000b600010002ffffffffffffffff0000001500000000root/opt/opensvc/lib  07070100067221000081a40000000000000000000000014d9d7e6e0000156a000000b600010002ffffffffffffffff0000002800000000root/opt/opensvc/lib/resContainerLxc.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
from datetime import datetime
from subprocess import *

import rcStatus
import resources as Res
from rcUtilitiesLinux import check_ping
from rcUtilities import which
import resContainer
import rcExceptions as ex

class Lxc(resContainer.Container):
    """
     container status transition diagram :
       ---------
      | STOPPED |<---------------
       ---------                 |
           |                     |
         start                   |
           |                     |
           V                     |
       ----------                |
      | STARTING |--error-       |
       ----------         |      |
           |              |      |
           V              V      |
       ---------    ----------   |
      | RUNNING |  | ABORTING |  |
       ---------    ----------   |
           |              |      |
      no process          |      |
           |              |      |
           V              |      |
       ----------         |      |
      | STOPPING |<-------       |
       ----------                |
           |                     |
            ---------------------
    """

    def files_to_sync(self):
        return [self.cf]

    def lxc(self, action):
        outf = '/var/tmp/svc_'+self.name+'_lxc_'+action+'.log'
        if action == 'start':
            cmd = ['lxc-start', '-d', '-n', self.name, '-o', outf]
        elif action == 'stop':
            cmd = ['lxc-stop', '-n', self.name, '-o', outf]
        else:
            self.log.error("unsupported lxc action: %s" % action)
            return 1

        t = datetime.now()
        (ret, out) = self.vcall(cmd)
        len = datetime.now() - t
        self.log.info('%s done in %s - ret %i - logs in %s' % (action, len, ret, outf))
        if ret != 0:
            raise ex.excError

    def get_cf_value(self, param):
        value = None
        with open(self.cf, 'r') as f:
            for line in f.readlines():
                if param not in line:
                    continue
                if line.strip()[0] == '#':
                    continue
                l = line.replace('\n', '').split('=')
                if len(l) < 2:
                    continue
                if l[0].strip() != param:
                    continue
                value = ' '.join(l[1:]).strip()
                break
        return value

    def get_rootfs(self):
        rootfs = self.get_cf_value("lxc.rootfs")
        if rootfs is None:
            self.log.error("could not determine lxc container rootfs")
            raise ex.excError
        return rootfs

    def install_drp_flag(self):
        rootfs = self.get_rootfs()
        flag = os.path.join(rootfs, ".drp_flag")
        self.log.info("install drp flag in container : %s"%flag)
        with open(flag, 'w') as f:
            f.write(' ')
            f.close()

    def container_start(self):
        self.lxc('start')

    def container_stop(self):
        self.lxc('stop')

    def container_forcestop(self):
        """ no harder way to stop a lxc container, raise to signal our
            helplessness
        """
        raise ex.excError

    def ping(self):
        return check_ping(self.addr, timeout=1)

    def is_up(self):
        self.log.debug("call: lxc-ps --name %s | grep %s" % (self.name, self.name))
        p1 = Popen(['lxc-ps', '--name', self.name], stdout=PIPE)
        p2 = Popen(["grep", self.name], stdin=p1.stdout, stdout=PIPE)
        p2.communicate()[0]
        if p2.returncode == 0:
            return True
        return False

    def get_container_info(self):
        cpu_set = self.get_cf_value("lxc.cgroup.cpuset.cpus")
        if cpu_set is None:
            vcpus = 0
        else:
            vcpus = len(cpu_set.split(','))
        return {'vcpus': str(vcpus), 'vmem': '0'}

    def check_manual_boot(self):
        return True

    def check_capabilities(self):
        if not which('lxc-info'):
            self.log.debug("lxc-info is not in PATH")
            return False
        return True

    def __init__(self, name, optional=False, disabled=False, tags=set([])):
        resContainer.Container.__init__(self, rid="lxc", name=name, type="container.lxc",
                                        optional=optional, disabled=disabled, tags=tags)
        self.cf = os.path.join(os.sep, 'var', 'lib', 'lxc', name, 'config')
        if not os.path.exists(self.cf):
            self.cf = os.path.join(os.sep, 'usr', 'local', 'var', 'lib', 'lxc', name, 'config')
        if not os.path.exists(self.cf):
            raise ex.excInitError

    def __str__(self):
        return "%s name=%s" % (Res.Resource.__str__(self), self.name)

  070701000671d9000081a40000000000000000000000014d9d7e6e0000038f000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/rcAddService.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import logging

def addservice():
	log = logging.getLogger('CREATE')
	log.info('enter')

 07070100067262000081a40000000000000000000000014d9d7e6e00000678000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/svcJail.py   #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import svc
import resContainerJail as jail

class SvcJail(svc.Svc):
    """ Define Jail services"""

    def __init__(self, svcname, vmname=None, guestos=None, jailroot=None,
                 optional=False, disabled=False, tags=set([])):
        svc.Svc.__init__(self, svcname, optional=optional, disabled=disabled, tags=tags)
        if vmname is None:
            vmname = svcname
        self.vmname = vmname
        self.guestos = guestos
        self.jailroot = jailroot
        self += jail.Jail(vmname)

        """ jail names cannot have dots
        """
        self.basevmname = vmname.split('.')[0]
        self.runmethod = ['jexec', self.basevmname]

if __name__ == "__main__":
    for c in (SvcJail,) :
        help(c)

07070100067251000081a40000000000000000000000014d9d7e6e00001403000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/lib/resVgHpVm.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import re
import os
import rcExceptions as ex
import rcStatus
resVg = __import__("resVgHP-UX")
from subprocess import *
from rcUtilities import qcall
from rcGlobalEnv import rcEnv
from subprocess import *

class Vg(resVg.Vg):
    def __init__(self, rid=None, name=None, type=None,
                 optional=False, disabled=False, tags=set([])):
        self.label = name
        resVg.Vg.__init__(self, rid=rid, name=name,
                          type='disk.vg',
                          optional=optional, disabled=disabled, tags=tags)

    def has_it(self):
        return True

    def is_up(self):
        return True

    def _status(self, verbose=False):
        return rcStatus.NA

    def do_start(self):
        self.do_mksf()

    def do_stop(self):
        pass

    def files_to_sync(self):
        return [self.sharefile_name(), self.mkfsfile_name()]

    def postsync(self):
        s = self.svc.group_status(excluded_groups=set(["sync", "hb"]))
        if s['overall'].status != rcStatus.UP:
            self.do_mksf()
            self.do_share()

    def presync(self):
        s = self.svc.group_status(excluded_groups=set(["sync", "hb"]))
        if self.svc.force or s['overall'].status == rcStatus.UP:
            self.write_mksf()
            self.write_share()

    def sharefile_name(self):
        return os.path.join(rcEnv.pathvar, 'vg_' + self.svc.svcname + '_' + self.name + '.share')

    def get_devs(self):
        cmd = ['/opt/hpvm/bin/hpvmdevmgmt', '-l', 'all']
        (ret, buff) = self.call(cmd)
        if ret != 0:
            raise ex.excError
        if len(buff) == 0:
            return []
        a = []
        for line in buff.split('\n'):
            if "DEVTYPE=FILE" not in line and "DEVTYPE=DISK" not in line:
                continue
            a.append(line)
        return a

    def write_share(self):
        devs = self.get_devs()
        disklist = self.disklist()
        with open(self.sharefile_name(), 'w') as f:
            for line in devs:
                dev = line.split(':')[0]
                if len(dev) == 0:
                    continue
                if dev not in disklist:
                    continue
                if 'SHARE=YES' in line:
                    f.write(dev+':YES\n')
                else:
                    f.write(dev+':NO\n')

    def do_share(self):
        if not os.path.exists(self.sharefile_name()):
            return
        _devs = self.get_devs()
        devs = set([])
        for line in _devs:
            l = line.split(':')
            if len(l) == 0:
                continue
            if len(l[0]) == 0:
                continue
            if ',' in l[0]:
                devs |= set(l[0].split(','))
            else:
                devs |= set([l[0]])
        with open(self.sharefile_name(), 'r') as f:
            err = 0
            for line in f.readlines():
                l = line.split(':')
                if len(l) != 2:
                    continue
                dev = l[0]
                if len(dev) == 0:
                    continue
                if not os.path.exists(dev):
                    continue
                if dev not in devs:
                    cmd = ['/opt/hpvm/bin/hpvmdevmgmt', '-a', 'gdev:'+dev]
                    (ret, out) = self.vcall(cmd)
                    if ret != 0:
                        raise ex.excError
                if 'YES' in l[1]:
                    cmd = ['/opt/hpvm/bin/hpvmdevmgmt', '-m', 'gdev:'+dev+':attr:SHARE=YES']
                else:
                    cmd = ['/opt/hpvm/bin/hpvmdevmgmt', '-m', 'gdev:'+dev+':attr:SHARE=NO']
                (ret, buff) = self.vcall(cmd)
                if ret != 0:
                    err += 1
                    continue
        if err > 0:
            raise ex.excError

    def disklist(self):
        cmd = ['/opt/hpvm/bin/hpvmstatus', '-d', '-P', self.svc.vmname]
        p = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
        buff = p.communicate()
        if p.returncode != 0:
            raise ex.excError

        for line in buff[0].split('\n'):
            l = line.split(':')
            if len(l) < 5:
                continue
            if l[3] != 'disk':
                continue
            self.disks |= set([l[4]])
        return self.disks
 07070100067229000081a40000000000000000000000014d9d7e6e0000143b000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/resHbOpenHA.py   #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import resources as Res
from rcGlobalEnv import rcEnv
import os
import rcStatus
import rcExceptions as ex
from rcUtilities import justcall

class Hb(Res.Resource):
    """ HeartBeat ressource
    """
    def __init__(self, rid=None, name=None, always_on=set([]),
                 optional=False, disabled=False, tags=set([])):
        Res.Resource.__init__(self, rid, "hb.openha",
                              optional=optional, disabled=disabled, tags=tags)
        self.basedir = os.path.join(os.sep, 'usr', 'local', 'cluster')
        self.bindir = os.path.join(self.basedir, 'bin')
        self.logdir = os.path.join(self.basedir, 'log')
        self.svcdir = os.path.join(self.basedir, 'services')
        self.cfsvcdir = os.path.join(self.basedir, 'conf', 'services')
        self.cfnoddir = os.path.join(self.basedir, 'conf', 'nodes')
        self.cfmondir = os.path.join(self.basedir, 'conf', 'monitor')
        os.environ['EZ_BIN'] = self.bindir
        os.environ['EZ_SERVICES'] = self.cfsvcdir
        os.environ['EZ_NODES'] = self.cfnoddir
        os.environ['EZ_MONITOR'] = self.cfmondir
        os.environ['EZ_LOG'] = self.logdir
        self.service_cmd = os.path.join(self.bindir, 'service')
        self.heartc = os.path.join(self.bindir, 'heartc')
        self.heartd = os.path.join(self.bindir, 'heartd')
        self.nmond = os.path.join(self.bindir, 'nmond')
        self.name = name

    def cluster_name(self):
        if self.name is None:
            return self.svc.svcname
        else:
            return self.name

    def service_status(self):
        service_state = os.path.join(self.svcdir, self.cluster_name(), 'STATE.'+rcEnv.nodename)
        try:
            f = open(service_state, 'r')
            buff = f.read().strip(' \n')
            f.close()
        except:
            import traceback
            traceback.print_exc()
            return 'unknown'
        if buff == '9':
            return 'force_stop'
        elif buff == '8':
            return 'unknown'
        elif buff == '7':
            return 'start_ready'
        elif buff == '6':
            return 'frozen_stop'
        elif buff == '5':
            return 'stop_failed'
        elif buff == '4':
            return 'start_failed'
        elif buff == '3':
            return 'starting'
        elif buff == '2':
            return 'started'
        elif buff == '1':
            return 'stopping'
        elif buff == '0':
            return 'stopped'
        else:
            return 'unknown'

    def service_action(self, command):
        cmd = [service_cmd, '-A', self.cluster_name(), command]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def process_running(self):
        daemons = [self.heartc, self.heartd, self.nmond]
        (out, err, ret) = justcall(['ps', '-ef'])
        if ret != 0:
            return False
        h = {}
        for d in daemons:
            h[d] = 1
        for line in out.split('\n'):
            for d in daemons:
                if d in line:
                    h[d] = 0
        total = 0
        for d in daemons:
            total += h[d]
        if total > 0:
            return False
        return True

    def __str__(self):
        return "%s" % (Res.Resource.__str__(self))

    def stop(self):
        pass

    def start(self):
        pass

    def _status(self, verbose=False):
        if not os.path.exists(self.service_cmd):
            self.status_log("open-ha is not installed")
            return rcStatus.WARN
        if not self.process_running():
            self.status_log("open-ha daemons are not running")
            return rcStatus.WARN
        status = self.service_status()
        if status == 'unknown':
            self.status_log("unable to determine cluster service state")
            return rcStatus.WARN
        elif status in ['frozen_stop', 'start_failed', 'stop_failed']:
            self.status_log("cluster service status is %s"%status)
            return rcStatus.WARN
        elif status in ['stopped', 'stopping', 'force_stop']:
            return rcStatus.DOWN
        elif status in ['started', 'starting', 'start_ready']:
            return rcStatus.UP
        else:
            self.status_log("unknown cluster service status: %s"%status)
            return rcStatus.WARN
 07070100067222000081a40000000000000000000000014d9d7e6e00001125000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/lib/resContainerVbox.py  #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import resources as Res
import rcExceptions as ex
from rcUtilities import qcall
import resContainer
from rcGlobalEnv import rcEnv
import os

utilities = __import__('rcUtilities'+rcEnv.sysname)

class Vbox(resContainer.Container):
    def __init__(self, name, optional=False, disabled=False, tags=set([])):
        resContainer.Container.__init__(self, rid="vbox", name=name,
                                        type="container.vbox",
                                        optional=optional, disabled=disabled,
                                        tags=tags)
        self.shutdown_timeout = 240
        #self.sshbin = '/usr/local/bin/ssh'
        self.vminfo = None

    def __str__(self):
        return "%s name=%s" % (Res.Resource.__str__(self), self.name)

    def get_vminfo(self):
        if self.vminfo is not None:
            return self.vminfo
        cmd = ['VBoxManage', 'showvminfo', '--machinereadable', self.name]
        (ret, out) = self.call(cmd)
        if ret != 0:
            return None
        h = {}
        for line in out.split('\n'):
            l = line.split('=')
            if len(l) != 2:
                continue
            key = l[0].strip('"')
            val = l[1].strip('"')
            h[key] = val
        self.vminfo = h
        return self.vminfo

    def files_to_sync(self):
        a = []
        vminfo = self.get_vminfo()
        if vminfo is None:
            return []
        a.append(vminfo['CfgFile'])
        a.append(vminfo['SnapFldr'])
        a.append(vminfo['LogFldr'])
        return a

    def check_capabilities(self):
        cmd = ['VBoxManage', '-v']
        (ret, out) = self.call(cmd)
        if ret != 0:
            return False
        return True

    def state(self):
        cmd = ['VBoxManage', 'list', 'runningvms']
        (ret, out) = self.call(cmd)
        if ret != 0:
            return None
        for line in out.split('\n'):
            l = line.split('"')
            if len(l) < 2:
                continue
            if l[1] == self.name:
                return 'on'
        return 'off'

    def ping(self):
        return utilities.check_ping(self.addr)

    def container_action(self, action, add=[]):
        cmd = ['VBoxManage', action, self.name] + add
        (ret, buff) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def container_start(self):
        state = self.state()
        if state == 'None':
            raise ex.excError
        elif state == 'off':
            self.container_action('startvm')
        elif state == 'on':
            self.log.info("container is already up")

    def container_forcestop(self):
        self.container_action('controlvm', ['poweroff'])

    def container_stop(self):
        state = self.state()
        if state == 'None':
            raise ex.excError
        elif state == 'off':
            self.log.info("container is already down")
        if state == 'on' :
            self.container_action('controlvm', ['acpipowerbutton'])
            try:
                self.log.info("wait for container shutdown")
                self.wait_for_fn(self.is_shutdown, self.shutdown_timeout, 2)
            except ex.excError:
                self.container_forcestop()

    def check_manual_boot(self):
        return True

    def is_shutdown(self):
        state = self.state()
        if state == 'off':
            return True
        return False

    def is_down(self):
        if self.state() == 'off':
            return True
        return False

    def is_up(self):
        if self.state() == 'on':
            return True
        return False

   070701000671db000081a40000000000000000000000014d9d7e6e00000bc8000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/rcAssetDarwin.py #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import datetime
from rcUtilities import call, which
from rcGlobalEnv import rcEnv
import rcAsset

class Asset(rcAsset.Asset):
    def __init__(self, node):
        rcAsset.Asset.__init__(self, node)
        self.sphw = {}
        (ret, out) = call(['system_profiler', 'SPHardwareDataType'])
        if ret == 0:
            for line in out.split('\n'):
                l = line.split(':')
                if len(l) != 2: continue
                self.sphw[l[0].strip()] = l[1].strip()

    def get_mem_bytes(self):
        if 'Memory' not in self.sphw:
            return '0'
        m = self.sphw['Memory'].split()
        size = int(m[0])
        unit = m[1]
        if unit == 'GB':
            size = size * 1024
        elif unit == 'MB':
            pass
        else:
            raise
        return str(size)

    def get_mem_banks(self):
        return '0'

    def get_mem_slots(self):
        return '0'

    def get_os_vendor(self):
        return 'Apple'

    def get_os_release(self):
        (ret, out) = call(['uname', '-r'])
        if ret != 0:
            return 'Unknown'
        return out.split()[0]

    def get_os_kernel(self):
        return self.get_os_release()

    def get_os_arch(self):
        cmd = ['uname', '-m']
        (ret, out) = call(cmd)
        if ret != 0:
            return 'Unknown'
        return out.split('\n')[0]

    def get_cpu_freq(self):
        if 'Processor Speed' not in self.sphw:
            return '0'
        return self.sphw['Processor Speed']

    def get_cpu_cores(self):
        if 'Total Number of Cores' not in self.sphw:
            return '0'
        return self.sphw['Total Number of Cores']

    def get_cpu_dies(self):
        if 'Number of Processors' not in self.sphw:
            return '0'
        return self.sphw['Number of Processors']

    def get_cpu_model(self):
        if 'Processor Name' not in self.sphw:
            return '0'
        return self.sphw['Processor Name']

    def get_serial(self):
        if 'Hardware UUID' not in self.sphw:
            return '0'
        return self.sphw['Hardware UUID']

    def get_model(self):
        if 'Model Name' not in self.sphw:
            return '0'
        return self.sphw['Model Name']

070701000671cc000081a40000000000000000000000014d9d7e6e00000a46000000b600010002ffffffffffffffff0000002a00000000root/opt/opensvc/lib/checkVgUsageHP-UX.py #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import checks
from rcUtilities import call

class check(checks.check):
    chk_type = "vg_u"

    def find_svc(self, vgname):
        for svc in self.svcs:
            for rs in svc.get_res_sets('disk.vg'):
                for r in rs.resources:
                    if r.name == vgname:
                        return svc.svcname
        return ''

    def do_check(self):
        """
        # vgdisplay -F
vg_name=/dev/vg00:vg_write_access=read,write:vg_status=available:max_lv=255:cur_lv=9:open_lv=9:max_pv=16:cur_pv=1:act_pv=1:max_pe_per_pv=4384:vgda=2:pe_size=32:total_pe=4347:alloc_pe=2712:free_pe=1635:total_pvg=0:total_spare_pvs=0:total_spare_pvs_in_use=0:vg_version=1.0:vg_max_size=2192g:vg_max_extents=70144
        """
        cmd = ['vgdisplay', '-F']
        (ret, out) = call(cmd, errlog=False)
        if ret != 0:
            return self.undef
        lines = out.split('\n')
        if len(lines) < 1:
            return self.undef
        r = []
        for line in lines:
            l = line.split(':')
            if len(l) < 10:
                continue
            instance = None
            free = None
            size = None
            for w in l:
                if 'vg_name' in w:
                    instance = w.split('=')[1].replace('/dev/','')
                elif 'total_pe' in w:
                    size = int(w.split('=')[1])
                elif 'free_pe' in w:
                    free = int(w.split('=')[1])
            if instance is None or free is None or size is None:
                continue
            val = int(100*(size-free)/size)
            r.append({'chk_instance': instance,
                      'chk_value': str(val),
                      'chk_svcname': self.find_svc(instance),
                     }
                    )
        return r
  07070100067215000081a40000000000000000000000014d9d7e6e00000145000000b600010002ffffffffffffffff0000002b00000000root/opt/opensvc/lib/rcUtilitiesFreeBSD.py    from rcUtilities import call

def check_ping(addr, timeout=5, count=1):
    if ':' in addr:
        ping = 'ping6'
    else:
        ping = 'ping'
    cmd = [ping, '-c', repr(count),
                 '-W', repr(timeout),
                 addr]
    (ret, out) = call(cmd)
    if ret == 0:
        return True
    return False
   07070100067231000081a40000000000000000000000014d9d7e6e000005e9000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/lib/resIpLdom.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

resIpHv = __import__("resIpSunOS")
import resIpVm

class Ip(resIpVm.Ip, resIpHv.Ip):
    def __init__(self, rid=None, ipDev=None, ipName=None,
                 mask=None, always_on=set([]),
                 disabled=False, tags=set([]), optional=False):
        resIpVm.Ip.__init__(self, rid=rid, ipDev=ipDev, ipName=ipName,
                            mask=mask, always_on=always_on,
                            disabled=disabled, tags=tags, optional=optional)

    def check_ping(self):
        return resIpHv.Ip.check_ping(self)


if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

   07070100067245000081a40000000000000000000000014d9d7e6e0000128e000000b600010002ffffffffffffffff0000002b00000000root/opt/opensvc/lib/resScsiReservLinux.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import resources as Res
import uuid
import re
import time
import rcStatus
import rcExceptions as ex
from rcUtilities import which
from subprocess import *
import resScsiReserv


class ScsiReserv(resScsiReserv.ScsiReserv):
    def scsireserv_supported(self):
        if which('sg_persist') is None:
            self.log.debug("sg_persist must be installed to use scsi-3 reservations" )
            return False
        return True

    def ack_unit_attention(self, d):
        i = self.preempt_timeout
        while i>0:
            i -= 1
            cmd = [ 'sg_persist', '-n', '-r', d ]
            p = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
            out = p.communicate()
            ret = p.returncode
            if "unsupported service action" in out[1]:
                self.log.error("disk %s does not support persistent reservation" % d)
                raise ex.excScsiPrNotsupported
            if "Unit Attention" in out[0] or ret != 0:
                self.log.debug("disk %s reports 'Unit Attention' ... waiting" % d)
                time.sleep(1)
                continue
            break
        if i == 0:
            self.log.error("timed out waiting for 'Unit Attention' to go away on disk %s" % d)
            return 1
        return 0

    def disk_registered(self, disk):
        cmd = [ 'sg_persist', '-n', '-k', disk ]
        (ret, out) = self.call(cmd)
        if ret != 0:
            self.log.error("failed to read registrations for disk %s" % disk)
        if self.hostid in out:
            return True
        return False

    def disk_register(self, disk):
        cmd = [ 'sg_persist', '-n', '--out', '--register-ignore', '--param-sark='+self.hostid, disk ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            self.log.error("failed to register key %s with disk %s" % (self.hostid, disk))
        return ret

    def disk_unregister(self, disk):
        cmd = [ 'sg_persist', '-n', '--out', '--register-ignore', '--param-rk='+self.hostid, disk ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            self.log.error("failed to unregister key %s with disk %s" % (self.hostid, disk))
        return ret

    def get_reservation_key(self, disk):
        cmd = [ 'sg_persist', '-n', '-r', disk ]
        (ret, out) = self.call(cmd)
        if ret != 0:
            self.log.error("failed to list reservation for disk %s" % disk)
        if 'Key=' not in out:
            return None
        for w in out.split():
            if 'Key=' in w:
                return w.split('=')[1]
        raise Exception()

    def disk_reserved(self, disk):
        cmd = [ 'sg_persist', '-n', '-r', disk ]
        (ret, out) = self.call(cmd)
        if ret != 0:
            self.log.error("failed to read reservation for disk %s" % disk)
        if self.hostid in out:
            return True
        return False

    def disk_release(self, disk):
        cmd = [ 'sg_persist', '-n', '--out', '--release', '--param-rk='+self.hostid, '--prout-type='+self.prtype, disk ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            self.log.error("failed to release disk %s" % disk)
        return ret

    def disk_reserve(self, disk):
        cmd = [ 'sg_persist', '-n', '--out', '--reserve', '--param-rk='+self.hostid, '--prout-type='+self.prtype, disk ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            self.log.error("failed to reserve disk %s" % disk)
        return ret

    def disk_preempt_reservation(self, disk, oldkey):
        cmd = [ 'sg_persist', '-n', '--out', '--preempt-abort', '--param-sark='+oldkey, '--param-rk='+self.hostid, '--prout-type='+self.prtype, disk ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            self.log.error("failed to preempt reservation for disk %s" % disk)
        return ret

  070701000671fe000081a40000000000000000000000014d9d7e6e000008c5000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/rcMountsHP-UX.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcMounts
from rcUtilities import *
from subprocess import Popen

def get_src_dir_dev(dev):
    """Given a directory path, return its hosting device
    """
    process = Popen(['df', '-l', dev], stdout=PIPE, stderr=STDOUT, close_fds=True)
    buff = process.communicate()
    out = buff[0]
    i = out.index('/')
    return out[i:].split()[0]

class Mounts(rcMounts.Mounts):

    def match_mount(self, i, dev, mnt):
        """Given a line of 'mount' output, returns True if (dev, mnt) matches
        this line. Returns False otherwize. Also care about weirdos like loops
        and binds, ...
        """
        if os.path.isdir(dev):
            is_bind = True
            src_dir_dev = get_src_dir_dev(dev)
        else:
            is_bind = False

        if i.mnt != mnt:
            return False
        if i.dev == dev:
            return True
        if is_bind and i.dev == src_dir_dev:
            return True
        return False

    def __init__(self):
        self.mounts = []
        (ret, out) = call(['mount', '-v'])
        for l in out.split('\n'):
            if len(l.split()) != 12:
                return
            dev, null, mnt, null, type, mnt_opt, null, null, null, null, null, null = l.split()
            m = rcMounts.Mount(dev, mnt, type, mnt_opt.strip('()'))
            self.mounts.append(m)

if __name__ == "__main__" :
    help(Mounts)
    for m in Mounts():
        print m
   070701000671d4000081a40000000000000000000000014d9d7e6e00000378000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/hostidLinux.py   #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from uuid import getnode

def hostid():
    return str(getnode())
0707010006721f000081a40000000000000000000000014d9d7e6e000013da000000b600010002ffffffffffffffff0000002800000000root/opt/opensvc/lib/resContainerKvm.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import rcStatus
import resources as Res
import time
import os
import rcExceptions as ex
from rcGlobalEnv import rcEnv
from rcUtilities import qcall
from rcUtilitiesLinux import check_ping
import resContainer

class Kvm(resContainer.Container):
    startup_timeout = 180
    shutdown_timeout = 120

    def __init__(self, name, optional=False, disabled=False, tags=set([])):
        resContainer.Container.__init__(self, rid="kvm", name=name, type="container.kvm",
                                        optional=optional, disabled=disabled, tags=tags)
        self.cf = os.path.join(os.sep, 'etc', 'libvirt', 'qemu', name+'.xml')

    def __str__(self):
        return "%s name=%s" % (Res.Resource.__str__(self), self.name)

    def list_kvmconffiles(self):
        if os.path.exists(self.cf):
            return [self.cf]
        return []

    def files_to_sync(self):
        return self.list_kvmconffiles()

    def check_capabilities(self):
        cmd = ['virsh', 'capabilities']
        (ret, out) = self.call(cmd, errlog=False)
        if ret != 0:
            self.status_log("can not fetch capabilities")
            return False
        if 'hvm' not in out:
            self.status_log("hvm not supported by host")
            return False
        return True

    def ping(self):
        return check_ping(self.addr, timeout=1, count=1)

    def container_start(self):
        if not os.path.exists(self.cf):
            self.log.error("%s not found"%self.cf)
            raise ex.excError
        cmd = ['virsh', 'define', self.cf]
        (ret, buff) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError
        cmd = ['virsh', 'start', self.name]
        (ret, buff) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def container_stop(self):
        cmd = ['virsh', 'shutdown', self.name]
        (ret, buff) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def container_forcestop(self):
        cmd = ['virsh', 'destroy', self.name]
        (ret, buff) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def is_up(self):
        cmd = ['virsh', 'dominfo', self.name]
        (ret, out) = self.call(cmd, errlog=False)
        if ret != 0:
            return False
        if "running" in out.split():
            return True
        return False

    def get_container_info(self):
        cmd = ['virsh', 'dominfo', self.name]
        (ret, out) = self.call(cmd, errlog=False, cache=True)
        self.info = {'vcpus': '0', 'vmem': '0'}
        if ret != 0:
            return self.info
        for line in out.split('\n'):
            if "CPU(s):" in line: self.info['vcpus'] = line.split(':')[1].strip()
            if "Used memory:" in line: self.info['vmem'] = line.split(':')[1].strip()
        return self.info

    def check_manual_boot(self):
        cf = os.path.join(os.sep, 'etc', 'libvirt', 'qemu', 'autostart', self.name+'.xml')
        if os.path.exists(cf):
            return False
        return True

    def install_drp_flag(self):
        flag_disk_path = os.path.join(rcEnv.pathvar, 'drp_flag.vdisk')

        from xml.etree.ElementTree import ElementTree, SubElement
        tree = ElementTree()
        tree.parse(self.cf)

        """ create the vdisk if it does not exist yet
        """
        if not os.path.exists(flag_disk_path):
            with open(flag_disk_path, 'w') as f:
                f.write('')
                f.close()

        """ check if drp flag is already set up
        """
        for disk in tree.getiterator("disk"):
            e = disk.find('source')
            if e is None:
                continue
            (dev, path) = e.items()[0]
            if path == flag_disk_path:
                self.log.info("flag virtual disk already exists")
                return

        """ add vdisk to the vm xml config
        """
        self.log.info("install drp flag virtual disk")
        devices = tree.find("devices")
        e = SubElement(devices, "disk", {'device': 'disk', 'type': 'file'})
        SubElement(e, "driver", {'name': 'qemu'})
        SubElement(e, "source", {'file': flag_disk_path})
        SubElement(e, "target", {'bus': 'virtio', 'dev': 'vdosvc'})
        tree.write(self.cf)
  070701000671e7000081a40000000000000000000000014d9d7e6e00000378000000b600010002ffffffffffffffff0000002800000000root/opt/opensvc/lib/rcDiskInfoSunOS.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcDiskInfo

class diskInfo(rcDiskInfo.diskInfo):
    pass
070701000671f6000081a40000000000000000000000014d9d7e6e00000b27000000b600010002ffffffffffffffff0000002800000000root/opt/opensvc/lib/rcIfconfigSunOS.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

from subprocess import *

import rcIfconfig

class ifconfig(rcIfconfig.ifconfig):

    def __init__(self):
        self.intf = []
        out = Popen(['ifconfig', '-a'], stdin=None, stdout=PIPE,stderr=PIPE,close_fds=True).communicate()[0]
        self.parse(out)

    def parse(self, out):
        for l in out.split("\n"):
            if l == '' : break
            if l[0]!='\t' :
                (ifname,ifstatus)=l.split(': ')

                i=rcIfconfig.interface(ifname)
                self.intf.append(i)

                # defaults
                i.link_encap = ''
                i.scope = ''
                i.bcast = ''
                i.mask = ''
                i.mtu = ''
                i.ipaddr = ''
                i.ip6addr = []
                i.ip6mask = []
                i.hwaddr = ''
                i.flag_up = False
                i.flag_broadcast = False
                i.flag_running = False
                i.flag_multicast = False
                i.flag_ipv4 = False
                i.flag_ipv6 = False
                i.flag_loopback = False

                if 'UP' in ifstatus : i.flag_up = True
                elif 'BROADCAST' in ifstatus : i.flag_broadcast = True
                elif 'RUNNING' in ifstatus   : i.flag_running = True
                elif 'MULTICAST' in ifstatus : i.flag_multicast = True
                elif 'IPv4' in ifstatus      : i.flag_ipv4 = True
                elif 'IPv6' in ifstatus      : i.flag_ipv6 = True
            else:
                n=0
                w=l.split()
                while n < len(w) :
                    [p,v]=w[n:n+2]
                    if p == 'inet' : i.ipaddr=v
                    elif p == 'netmask' : i.mask=v
                    elif p == 'broadcast' : i.bcast=v
                    elif p == 'inet6' :
                        (a, m) = v.split('/')
                        i.ip6addr += [a]
                        i.ip6mask += [m]
                    n+=2


if __name__ == "__main__":
    for c in (ifconfig,) :
        help(c)
 07070100067206000081a40000000000000000000000014d9d7e6e00000507000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/rcPkgHP-UX.py    #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from rcUtilities import call, which
from rcGlobalEnv import rcEnv

def listpkg():
    if which('swlist') is None:
        return []
    cmd = ['swlist', '-l', 'product']
    (ret, out) = call(cmd, errlog=False, cache=True)
    lines = []
    for line in out.split('\n'):
        l = line.split()
        if len(l) < 2:
            continue
        if line[0] == '#':
            continue
        x = [rcEnv.nodename, l[0], l[1], '']
        lines.append(x)
    return lines

def listpatch():
    return []
 0707010006721d000081a40000000000000000000000014d9d7e6e00000ec8000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/lib/resContainerHpVm.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import rcStatus
import resources as Res
import time
import os
import rcExceptions as ex
from rcUtilities import qcall
from rcGlobalEnv import rcEnv
import resContainer
u = __import__('rcUtilitiesHP-UX')

class HpVm(resContainer.Container):
    def __init__(self, name, optional=False, disabled=False, tags=set([])):
        resContainer.Container.__init__(self, rid="hpvm", name=name, type="container.hpvm",
                                        optional=optional, disabled=disabled, tags=tags)

    def __str__(self):
        return "%s name=%s" % (Res.Resource.__str__(self), self.name)

    def files_to_sync(self):
        import glob
        a = []
        guest = os.path.join(os.sep, 'var', 'opt', 'hpvm', 'guests', self.name)
        uuid = os.path.realpath(guest)
        share = os.path.join(rcEnv.pathvar, 'vg_'+self.svc.svcname+'_*.share')
        if os.path.exists(guest):
            a.append(guest)
        if os.path.exists(uuid):
            a.append(uuid)
        files = glob.glob(share)
        if len(files) > 0:
            a += files
        return a

    def ping(self):
        return u.check_ping(self.addr, timeout=1, count=1)

    def container_start(self):
        cmd = ['/opt/hpvm/bin/hpvmstart', '-P', self.name]
        (ret, buff) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def container_stop(self):
        cmd = ['/opt/hpvm/bin/hpvmstop', '-g', '-F', '-P', self.name]
        (ret, buff) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def container_forcestop(self):
        cmd = ['/opt/hpvm/bin/hpvmstop', '-F', '-P', self.name]
        (ret, buff) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def check_manual_boot(self):
        cmd = ['/opt/hpvm/bin/hpvmstatus', '-M', '-P', self.name]
        (ret, out) = self.call(cmd, cache=True)
        if ret != 0:
            return False
        if out.split(":")[11] == "Manual":
            return True
        self.log.info("Auto boot should be turned off")
        return False

    def get_container_info(self):
        cmd = ['/opt/hpvm/bin/hpvmstatus', '-M', '-P', self.name]
        (ret, out) = self.call(cmd, cache=True)
        self.info = {'vcpus': '0', 'vmem': '0'}
        if ret != 0:
            return self.info
        self.info['vcpus'] = out.split(':')[19].split(';')[0]
        self.info['vmem'] = out.split(':')[20].split(';')[0]
        if 'GB' in self.info['vmem']:
            self.info['vmem'] = str(1024*1024*int(self.info['vmem'].replace('GB','')))
        return self.info

    def is_up(self):
        cmd = ['/opt/hpvm/bin/hpvmstatus', '-M', '-P', self.name]
        (ret, out) = self.call(cmd)
        if ret != 0:
            return False
        if out.split(":")[10] == "On":
            return True
        return False

    def check_capabilities(self):
        if os.path.exists('/opt/hpvm/bin/hpvmstatus'):
            return True
        return False
07070100067249000081a40000000000000000000000014d9d7e6e00002a7d000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/resSyncNetapp.py #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import logging

from rcGlobalEnv import rcEnv
from rcUtilities import which
import rcExceptions as ex
import rcStatus
import time
import resSync
import datetime

class syncNetapp(resSync.Sync):
    def master(self):
        s = self.local_snapmirror_status()
        return s['master']

    def slave(self):
        s = self.local_snapmirror_status()
        return s['slave']

    def local(self):
        if rcEnv.nodename in self.filers:
            return self.filers[rcEnv.nodename]
        return None

    def _cmd(self, cmd, target, info=False):
        if target == "local":
            filer = self.local()
        elif target == "master":
            filer = self.master()
        elif target == "slave":
            filer = self.slave()
        elif target in self.filers.values():
            filer = target
        else:
            self.log.error("unable to find the %s filer"%target)
            raise ex.excError

        return self.call(rcEnv.rsh.split() + [self.user+'@'+filer] + cmd, info=info)

    def cmd_master(self, cmd, info=False):
        return self._cmd(cmd, "master", info=info)

    def cmd_slave(self, cmd, info=False):
        return self._cmd(cmd, "slave", info=info)

    def cmd_local(self, cmd, info=False):
        return self._cmd(cmd, "local", info=info)

    def lag_to_ts(self, lag):
        now = datetime.datetime.now()
        l = lag.split(":")
        if len(l) != 3:
            self.log.error("unexpected lag format")
            raise ex.excError
        delta = datetime.timedelta(hours=int(l[0]),
                                   minutes=int(l[1]),
                                   seconds=int(l[2]))
        return now - delta

    def can_sync(self, target=None, s=None):
        if s is None:
            s = self.snapmirror_status(self.slave())
        ts = self.lag_to_ts(s['lag'])
        if self.skip_sync(ts):
            return False
        return True

    def lagged(self, lag, max=None):
        if max is None:
            max = self.sync_max_delay
        l = lag.split(":")
        if len(l) != 3:
            self.log.error("unexpected lag format")
            raise ex.excError
        if int(l[0]) * 60 + int(l[1]) > max:
            return True
        return False

    def syncresync(self):
        (ret, buff) = self.cmd_slave(['snapmirror', 'resync', '-f', self.slave()+':'+self.path_short], info=True)
        if ret != 0:
            raise ex.excError

    def syncswap(self):
        master = self.master()
        slave = self.slave()
        s = self.snapmirror_status(self.local())
        if s['state'] != "Broken-off":
            self.log.error("can not swap: snapmirror is not in state Broken-off")
            raise ex.excError
        src = slave+':'+self.path_short
        dst = master+':'+self.path_short

        (ret, buff) = self._cmd(['snapmirror', 'resync', '-f', '-S', src, dst], master, info=True)
        if ret != 0:
            raise ex.excError
        (ret, buff) = self._cmd(['snapmirror', 'release', self.path_short, src], master, info=True)
        if ret != 0:
            raise ex.excError
        (ret, buff) = self._cmd(['snapmirror', 'status', '-l', dst], slave, info=False)
        if ret != 0:
            raise ex.excError
        snap = ""
        state = ""
        for line in buff.split('\n'):
            l = line.split()
            if len(l) < 2:
                continue
            if l[0] == "State:":
                state = l[1]
            if state != "Broken-off":
                continue
            if l[0] == "Base" and l[1] == "Snapshot:":
                snap = l[-1]
                break
        if len(snap) == 0:
            self.log.error("can not determine base snapshot name to remove on %s"%slave)
            raise ex.excError
        import time
        time.sleep(5)
        (ret, buff) = self._cmd(['snap', 'delete', self.path_short, snap], slave, info=True)
        if ret != 0:
            raise ex.excError

    def syncupdate(self):
        s = self.snapmirror_status(self.slave())
        if not self.can_sync(s=s):
            return
        if s['state'] == "Quiesced":
            self.log.error("update not applicable: quiesced")
            return
        if s['state'] == "Snapmirrored" and s['status'] == "Transferring":
            self.log.info("update not applicable: transfer in progress")
            return
        if s['state'] != "Snapmirrored" or s['status'] != "Idle":
            self.log.error("update not applicable: not in snapmirror idle status")
            return
        (ret, buff) = self.cmd_slave(['snapmirror', 'update', self.slave()+':'+self.path_short], info=True)
        if ret != 0:
            raise ex.excError

    def syncresume(self):
        s = self.snapmirror_status(self.slave())
        if s['state'] != "Quiesced":
            self.log.info("resume not applicable: not quiesced")
            return
        (ret, buff) = self.cmd_slave(['snapmirror', 'resume', self.slave()+':'+self.path_short], info=True)
        if ret != 0:
            raise ex.excError

    def syncquiesce(self):
        s = self.snapmirror_status(self.slave())
        if s['state'] == "Quiesced":
            self.log.info("already quiesced")
            return
        elif s['state'] != "Snapmirrored":
            self.log.error("Can not quiesce: volume not in Snapmirrored state")
            raise ex.excError
        if s['status'] == "Pending":
            self.log.error("Can not quiesce: volume in snapmirror Pending status")
            raise ex.excError
        (ret, buff) = self.cmd_slave(['snapmirror', 'quiesce', self.slave()+':'+self.path_short], info=True)
        if ret != 0:
            raise ex.excError
        self.wait_quiesce()

    def syncbreak(self):
        (ret, buff) = self.cmd_slave(['snapmirror', 'break', self.slave()+':'+self.path_short], info=True)
        if ret != 0:
            raise ex.excError
        self.wait_break()

    def wait_quiesce(self):
        timeout = 60
        self.log.info("start waiting quiesce to finish (max %s seconds)"%(timeout*5))
        for i in range(timeout):
            s = self.snapmirror_status(self.slave())
            if s['state'] == "Quiesced" and s['status'] == "Idle":
                return
            time.sleep(5)
        self.log.error("timed out waiting for quiesce to finish")
        raise ex.excError

    def wait_break(self):
        timeout = 20
        for i in range(timeout):
            s = self.snapmirror_status(self.slave())
            if s['state'] == "Broken-off" and s['status'] == "Idle":
                return
            time.sleep(5)
        self.log.error("timed out waiting for break to finish")
        raise ex.excError

    def snapmirror_status(self, filer):
        (ret, buff) = self._cmd(['snapmirror', 'status'], filer)
        if ret != 0:
	    self.log.error("can get snapmirror status from %s"%filer)
            raise ex.excError
        key = ':'.join([filer, self.path_short])
        list = []
        for line in buff.split('\n'):
            l = line.split()
            if len(l) < 5:
                continue
            if l[2] == "Uninitialized":
                continue
            if l[0] == key or l[1] == key:
                list.append(l)
        if len(list) == 0:
	    self.log.error("%s not found in snapmirror status"%self.path_short)
            raise ex.excError
        elif len(list) == 1:
            l = list[0]
            master = l[0].split(':')[0]
            slave = l[1].split(':')[0]
            return dict(master=master, slave=slave, state=l[2], lag=l[3], status=l[4])
        else:
            self.log.error("%s is in an unsupported state. Please repair manually."%filer)
            raise ex.excError

    def local_snapmirror_status(self):
        return self.snapmirror_status(self.local())

    def start(self):
        if self.local() == self.master():
            self.log.info("%s is already replication master"%self.local())
            return
        s = self.snapmirror_status(self.slave())
        if s['state'] != "Broken-off":
            try:
                self.syncquiesce()
            except:
                if self.svc.force:
                    self.log.warning("force mode is on. bypass failed quiesce.")
                    pass
                else:
                    self.log.error("set force mode to bypass")
                    raise ex.excError
            self.syncbreak()
        if rcEnv.host_mode == "PRD":
            self.syncswap()

    def stop(self):
        pass

    def _status(self, verbose=False):
        try:
            s = self.snapmirror_status(self.slave())
        except:
            return rcStatus.UNDEF
        if s['state'] == "Snapmirrored":
            if "Transferring" in s['status']:
                self.log.debug("snapmirror transfer in progress")
                return rcStatus.WARN
            elif self.lagged(s['lag']):
                self.log.debug("snapmirror lag beyond sync_max_delay")
                return rcStatus.WARN
            else:
                return rcStatus.UP
        return rcStatus.DOWN

    def __init__(self, rid=None, filers={}, path=None, user=None,
                 sync_max_delay=None, sync_interval=None, sync_days=None,
                 sync_period=None,
                 optional=False, disabled=False, tags=set([]), internal=False):
        resSync.Sync.__init__(self, rid=rid, type="sync.netapp",
                              sync_max_delay=sync_max_delay,
                              sync_interval=sync_interval,
                              sync_days=sync_days,
                              sync_period=sync_period,
                              optional=optional, disabled=disabled, tags=tags)
        self.label = "netapp %s on %s"%(path, ', '.join(filers.values()))
        self.filers = filers
        self.path = path
        self.user = user
        self.path_short = self.path.replace('/vol/','')

    def __str__(self):
        return "%s filers=%s user=%s path=%s" % (resSync.Sync.__str__(self),\
                self.filers, self.user, self.path)

   070701000671d1000081a40000000000000000000000014d9d7e6e00000453000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/lib/hostidAIX.py #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from subprocess import *

def hostid():
    cmd = ['uname', '-u']
    p = Popen(cmd, stderr=None, stdout=PIPE, close_fds=True)
    buff = p.communicate()
    if p.returncode != 0:
        return '1'
    sn = buff[0].split()[0]
    return str(hex(abs(sn.__hash__()))).replace('0x', '')
 070701000671ef000081a40000000000000000000000014d9d7e6e000004f2000000b600010002ffffffffffffffff0000002d00000000root/opt/opensvc/lib/rcIfconfigFreeBSDkvm.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcExceptions as ex
from subprocess import *

rcIfconfig = __import__("rcIfconfigFreeBSD")
from rcGlobalEnv import rcEnv

class ifconfig(rcIfconfig.ifconfig):
    def __init__(self, hostname):
        self.intf = []
        cmd = rcEnv.rsh.split(' ') + [hostname, 'ifconfig', '-a']
        p = Popen(cmd, stdout=PIPE)
        buff = p.communicate()[0]
        if p.returncode != 0:
            raise ex.excError
        self.parse(buff)
  07070100067223000081a40000000000000000000000014d9d7e6e000010d2000000b600010002ffffffffffffffff0000002700000000root/opt/opensvc/lib/resContainerVz.py    #
# Copyright (c) 2011 Christophe Varoqui <christophe.varoqui@opensvc.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os

import rcStatus
import resources as Res
from rcUtilities import which, qcall
import resContainer
import rcExceptions as ex

class Vz(resContainer.Container):
    def files_to_sync(self):
        return [self._cf]

    def get_cf_value(self, param):
        value = None
        try:
            cf = self.cf()
        except:
            return value
        with open(cf, 'r') as f:
            for line in f.readlines():
                if param not in line:
                    continue
                if line.strip()[0] == '#':
                    continue
                l = line.replace('\n', '').split('=')
                if len(l) < 2:
                    continue
                if l[0].strip() != param:
                    continue
                value = ' '.join(l[1:]).strip()
                break
        return value

    def get_rootfs(self):
        with open(self.cf(), 'r') as f:
            for line in f:
                if 'VE_PRIVATE' in line:
                    return line.strip('\n').split('=')[1].strip('"').replace('$VEID', self.name)
        self.log.error("could not determine lxc container rootfs")
        return ex.excError

    def install_drp_flag(self):
        rootfs = self.get_rootfs()
        flag = os.path.join(rootfs, ".drp_flag")
        self.log.info("install drp flag in container : %s"%flag)
        with open(flag, 'w') as f:
            f.write(' ')
            f.close()

    def vzctl(self, action, options=[]):
        cmd = ['vzctl', action, self.name] + options
        ret, out = self.vcall(cmd)
        if ret != 0:
            raise ex.excError
        return out

    def container_start(self):
        self.vzctl('start')

    def container_stop(self):
        self.vzctl('stop')

    def container_forcestop(self):
        raise ex.excError

    def operational(self):
        cmd = self.svc.runmethod + ['/sbin/ifconfig', '-a']
        ret = qcall(cmd)
        if ret == 0:
            return True
        return False

    def is_up(self):
        """ CTID 101 exist mounted running
        """
        cmd = ['vzctl', 'status', self.name]
        ret, out = self.call(cmd)
        if ret != 0:
            raise ex.excError
        l = out.split()
        if len(l) != 5:
            return False
        if l[2] != 'exist' or \
           l[3] != 'mounted' or \
           l[4] != 'running':
            return False
        return True

    def get_container_info(self):
        return {'vcpus': '0', 'vmem': '0'}

    def check_manual_boot(self):
        try:
            cf = self.cf()
        except:
            return True
        with open(self.cf(), 'r') as f:
            for line in f:
                if 'ONBOOT' in line and 'yes' in line:
                    return False
        return True

    def check_capabilities(self):
        if not which('vzctl'):
            self.log.debug("vzctl is not in PATH")
            return False
        return True

    def cf(self):
        if not os.path.exists(self._cf):
            self.log.error("%s does not exist"%self._cf)
            raise ex.excError
        return self._cf

    def __init__(self, name, optional=False, disabled=False, tags=set([])):
        resContainer.Container.__init__(self, rid="vz", name=name, type="container.vz",
                                        optional=optional, disabled=disabled, tags=tags)
        self._cf = os.path.join(os.sep, 'etc', 'vz', 'conf', name+'.conf')

    def __str__(self):
        return "%s name=%s" % (Res.Resource.__str__(self), self.name)

  07070100067232000081a40000000000000000000000014d9d7e6e00000743000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/resIpLinux.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.
"Module implement Linux specific ip management"

import resIp as Res
import rcExceptions as ex
from rcUtilitiesLinux import check_ping

class Ip(Res.Ip):
    def check_ping(self):
        return check_ping(self.addr)

    def startip_cmd(self):
        if ':' in self.addr:
            if '.' in self.mask:
                self.log.error("netmask parameter is mandatory for ipv6 adresses")
                raise ex.excError
            cmd = ['ifconfig', self.ipDev, 'inet6', 'add', '/'.join([self.addr, self.mask])]
        else:
            cmd = ['ifconfig', self.stacked_dev, self.addr, 'netmask', self.mask, 'up']
        return self.vcall(cmd)

    def stopip_cmd(self):
        if ':' in self.addr:
            cmd = ['ifconfig', self.ipDev, 'inet6', 'del', self.addr]
        else:
            cmd = ['ifconfig', self.stacked_dev, 'down']
        return self.vcall(cmd)



if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

 0707010006725f000081a40000000000000000000000014d9d7e6e0000a879000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/svcDict.py   #!/opt/opensvc/bin/python

import sys

class MissKeyNoDefault(Exception):
     pass

class KeyInvalidValue(Exception):
     pass

class Keyword(object):
    def __init__(self, section, keyword,
                 rtype=None,
                 order=100,
                 required=False,
                 at=False,
                 default=None,
                 validator=None,
                 candidates=None,
                 depends=[],
                 text=""):
        self.section = section
        self.keyword = keyword
        self.rtype = rtype
        self.order = order
        self.at = at
        self.required = required
        self.default = default
        self.validator = validator
        self.candidates = candidates
        self.depends = depends
        self.text = text

    def __cmp__(self, o):
        if o.order > self.order:
            return -1
        elif o.order == self.order:
            return 0
        return 1

    def __str__(self):
        from textwrap import TextWrapper
        wrapper = TextWrapper(subsequent_indent="%15s"%"", width=78)

        if self.validator is None:
            validator = False
        else:
            validator = True
        depends = ""
        for d in self.depends:
            depends += "%s in %s\n"%(d[0], d[1])
        if depends == "":
            depends = None

        s = ''
        s += "------------------------------------------------------------------------------\n"
        s += "section:       %s\n"%self.section
        s += "keyword:       %s\n"%self.keyword
        s += "------------------------------------------------------------------------------\n"
        s += "  required:    %s\n"%str(self.required)
        s += "  default:     %s\n"%str(self.default)
        s += "  candidates:  %s\n"%str(self.candidates)
        s += "  validator:   %s\n"%str(validator)
        s += "  depends:     %s\n"%depends
        s += "  @node:       %s\n"%str(self.at)
        if self.text:
            s += wrapper.fill("  help:        "+self.text)
        if self.at:
            s += "\n\nPrefix the value with '@node ' to specify a node-specific value.\n"
            s += "You will be prompted for new values until you submit an empty value.\n"
        return s

    def form(self, d):
        for d_keyword, d_value in self.depends:
            if d_keyword not in d:
                return d
            if d[d_keyword] not in d_value:
                return d
        print self
        if self.keyword in d:
            default = d[self.keyword]
        elif self.default is not None:
            default = self.default
        else:
            default = None

        if default is not None:
            default_prompt = " [%s] "%str(default)
        else:
            default_prompt = ""

        req_satisfied = False
        while True:
            val = raw_input(self.keyword+default_prompt+"> ")
            if len(val) == 0:
                if req_satisfied:
                    return d
                if default is None:
                    if self.required:
                        print "value required"
                        continue
                    # keyword is optional, leave dictionaty untouched
                    return d
                else:
                    val = default
                if self.candidates is not None and \
                   val not in self.candidates:
                    print "invalid value"
                    continue
            if self.at and val[0] == '@':
                l = val.split()
                if len(l) < 2:
                    print "invalid value"
                    continue
                val = ' '.join(l[1:])
                d[self.keyword+l[0]] = val
                req_satisfied = True
            else:
                d[self.keyword] = val
                req_satisfied = True
            if self.at:
                # loop for more key@node = values
                print "More '%s' ? <enter> to step to the next parameter."%self.keyword
                continue
            else:
                return d

class Section(object):
    def __init__(self, section):
        self.section = section
        self.keywords = []

    def __iadd__(self, o):
        if not isinstance(o, Keyword):
            return self
        self.keywords.append(o)
        return self

    def __str__(self):
        s = ''
        for keyword in sorted(self.keywords):
            s += str(keyword)
        return s

    def getkeys(self, rtype=None):
        if rtype is None:
            return [k for k in self.keywords if k.rtype is None]
        else:
            return [k for k in self.keywords if k.rtype == rtype]

    def getkey(self, keyword, rtype=None):
        if '@' in keyword:
            l = keyword.split('@')
            if len(l) != 2:
                return None
            keyword, node = l
        for k in self.keywords:
            if k.keyword == keyword and k.rtype == rtype:
                return k
        return None

class KeywordStore(dict):
    def __init__(self):
        self.sections = {}

    def __iadd__(self, o):
        if not isinstance(o, Keyword):
            return self
        if o.section not in self.sections:
             self.sections[o.section] = Section(o.section)
        self.sections[o.section] += o
        return self

    def __getattr__(self, key):
        return self.sections[str(key)]

    def __getitem__(self, key):
        return self.sections[str(key)]

    def __str__(self):
        s = ''
        for section in self.sections:
            s += str(self.sections[section])
        return s

    def required_keys(self, section, rtype=None):
        if section not in self.sections:
            return []
        return [k for k in sorted(self.sections[section].getkeys(rtype)) if k.required is True]

    def update(self, rid, d):
        """ Given a resource dictionary, spot missing required keys
            and provide a new dictionary to merge populated by default
            values
        """
        completion = {}

        # decompose rid into section and rtype
        if rid == 'DEFAULT':
            section = rid
            rtype = None
        else:
            if '#' not in rid:
                return {}
            l = rid.split('#')
            if len(l) != 2:
                return {}
            section = l[0]
            if 'type' in d:
                 rtype = d['type']
            elif self[section].getkey('type') is not None and \
                  self[section].getkey('type').default is not None:
                rtype = self[section].getkey('type').default
            else:
                rtype = None

        # validate command line dictionary
        for keyword, value in d.items():
            key = self.sections[section].getkey(keyword)
            if key is None and rtype is not None:
                key = self.sections[section].getkey(keyword, rtype)
            if key is None:
                if keyword != "rtype":
                    print "Remove unknown keyword '%s' from section '%s'"%(keyword, rid)
                    del d[keyword]
                continue
            if key.candidates is None:
                continue
            if value not in key.candidates:
                print "'%s' keyword has invalid value '%s' in section '%s'"%(keyword, str(value), rid)
                raise KeyInvalidValue()

        # add missing required keys if they have a known default value
        for key in self.required_keys(section, rtype):
            if key.keyword in d:
                continue
            if key.keyword in map(lambda x: x.split('@')[0], d.keys()):
                continue
            if key.default is None:
                sys.stderr.write("No default value for required key '%s' in section '%s'\n"%(key.keyword, rid))
                raise MissKeyNoDefault()
            print "Implicitely add [%s]"%rid, key.keyword, "=", key.default
            completion[key.keyword] = key.default
        return completion

    def form_sections(self, sections):
        from textwrap import TextWrapper
        wrapper = TextWrapper(subsequent_indent="%18s"%"", width=78)
        candidates = set(self.sections.keys()) - set(['DEFAULT'])

        print "------------------------------------------------------------------------------"
        print "Choose a resource type to add or a resource to edit."
        print "Enter 'quit' to finish the creation."
        print "------------------------------------------------------------------------------"
        print wrapper.fill("resource types: "+', '.join(candidates))
        print wrapper.fill("resource ids:   "+', '.join(sections.keys()))
        print
        return raw_input("resource type or id> ")

    def free_resource_index(self, section, sections):
        indices = []
        for s in sections:
            l = s.split('#')
            if len(l) != 2:
                continue
            sname, sindex = l
            if section != sname:
                continue
            try:
                indices.append(int(sindex))
            except:
                continue
        i = 0
        while True:
            if i not in indices:
                return i
            i += 1

    def form(self, defaults, sections):
        for key in sorted(self.DEFAULT.getkeys()):
            defaults = key.form(defaults)
        while True:
            section = self.form_sections(sections)
            if section == "quit":
                 break
            if '#' in section:
                rid = section
                section = section.split('#')[0]
            else:
                index = self.free_resource_index(section, sections)
                rid = '#'.join((section, str(index)))
            if section not in self.sections:
                 print "unsupported resource type"
                 continue
            for key in sorted(self.sections[section].getkeys()):
                if rid not in sections:
                    sections[rid] = {}
                sections[rid] = key.form(sections[rid])
            if 'type' not in sections[rid]:
                continue
            specific_keys = self.sections[section].getkeys(rtype=sections[rid]['type'])
            if len(specific_keys) > 0:
                print "\nKeywords specific to the '%s' driver\n"%sections[rid]['type']
            for key in sorted(specific_keys):
                if rid not in sections:
                    sections[rid] = {}
                sections[rid] = key.form(sections[rid])
        return defaults, sections

class KeyDict(KeywordStore):
    def __init__(self):
        KeywordStore.__init__(self)

        import os
        from rcNode import node_get_hostmode
        from rcGlobalEnv import rcEnv
        sysname, nodename, x, x, machine = os.uname()

        def is_integer(val):
            try:
                 val = int(val)
            except:
                 return False
            return True

        def kw_disable(resource):
            return Keyword(
                  section=resource,
                  keyword="disable",
                  candidates=(True, False),
                  default=False,
                  text="A disabled resource will be ignored on service startup and shutdown."
                )
        def kw_disable_on(resource):
            return Keyword(
                  section=resource,
                  keyword="disable_on",
                  text="A list of nodenames where to consider the 'disable' value is True."
                )
        def kw_optional(resource):
            return Keyword(
                  section=resource,
                  keyword="optional",
                  candidates=(True, False),
                  default=False,
                  text="Possible values are 'true' or 'false'. Actions on resource will be tried upon service startup and shutdown, but action failures will be logged and passed over. Useful for resources like dump filesystems for example."
                )
        def kw_always_on(resource):
            return Keyword(
                  section=resource,
                  keyword="always_on",
                  candidates=['nodes', 'drpnodes', 'nodes drpnodes'],
                  text="Possible values are 'nodes', 'drpnodes' or 'nodes drpnodes', or a list of nodes. Sets the nodes on which the resource is always kept up. Primary usage is file synchronization receiving on non-shared disks. Don't set this on shared disk !! danger !!"
                )

        for r in ["sync", "ip", "fs", "vg", "hb", "pool", "vmdg", "drbd",
                  "loop", "vdisk"]:
            self += kw_disable(r)
            self += kw_disable_on(r)
            self += kw_optional(r)
            self += kw_always_on(r)

        self += Keyword(
                  section="DEFAULT",
                  keyword="mode",
                  order=10,
                  default="hosted",
                  candidates=["hosted"] + rcEnv.vt_supported,
                  text="The mode decides upon disposition OpenSVC takes to bring a service up or down : virtualized services need special actions to prepare and boot the container for example, which is not needed for 'hosted' services."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="vm_name",
                  order=11,
                  depends=[('mode', rcEnv.vt_supported)],
                  text="This need to be set if the virtual machine name is different from the service name."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="cluster_type",
                  order=15,
                  required=False,
                  default="failover",
                  candidates=["failover", "allactive", "flex", "autoflex"],
                  text="failover: the service is allowed to be up on one node at a time. allactive: the service must be up on all nodes. flex: the service can be up on n out of m nodes (n <= m), n/m must be in the [flex_min_nodes, flex_max_nodes] range. autoflex: same as flex, but charge the collector to start the service on passive nodes when the average %cpu usage on active nodes > flex_cpu_high_threshold and stop the service on active nodes when the average %cpu usage on active nodes < flex_cpu_low_threshold."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="flex_min_nodes",
                  order=16,
                  required=False,
                  default=1,
                  depends=[('cluster_type', ['flex', 'autoflex'])],
                  text="Minimum number of active nodes in the cluster. Below this number alerts are raised by the collector, and the collector won't stop any more service instances."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="flex_max_nodes",
                  order=16,
                  required=False,
                  default=0,
                  depends=[('cluster_type', ['flex', 'autoflex'])],
                  text="Maximum number of active nodes in the cluster. Above this number alerts are raised by the collector, and the collector won't start any more service instances. 0 means unlimited."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="flex_cpu_min_threshold",
                  order=16,
                  required=False,
                  default=10,
                  depends=[('cluster_type', ['flex', 'autoflex'])],
                  text="Average CPU usage across the active cluster nodes below which the collector raises alerts and decides to stop service instances with autoflex cluster type."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="flex_cpu_max_threshold",
                  order=16,
                  required=False,
                  default=70,
                  depends=[('cluster_type', ['flex', 'autoflex'])],
                  text="Average CPU usage across the active cluster nodes above which the collector raises alerts and decides to start new service instances with autoflex cluster type."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="service_type",
                  order=15,
                  required=True,
                  default=node_get_hostmode(),
                  candidates=rcEnv.allowed_svctype,
                  text="A non-PRD service can not be brought up on a PRD node, but a PRD service can be startup on a non-PRD node (in a DRP situation)."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="nodes",
                  order=20,
                  required=True,
                  default=nodename,
                  text="List of cluster local nodes able to start the service.  Whitespace separated."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="autostart_node",
                  order=20,
                  required=True,
                  default=nodename,
                  text="A whitespace-separated list subset of 'nodes'. Defines the nodes where the service will try to start on upon node reboot. On a failover cluster there should only be one autostart node and the start-up will fail if the service is already up on another node though. If not specified, the service will never be started at node boot-time, which is rarely the expected behaviour."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="drpnode",
                  order=21,
                  text="The backup node where the service is activated in a DRP situation. This node is also a data synchronization target for 'sync' resources."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="drpnodes",
                  order=21,
                  text="Alternate backup nodes, where the service could be activated in a DRP situation if the 'drpnode' is not available. These nodes are also data synchronization targets for 'sync' resources."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="app",
                  order=24,
                  default="DEFAULT",
                  text="Used to identify who is responsible for is service, who is billable and provides a most useful filtering key. Better keep it a short code."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="comment",
                  order=25,
                  text="Helps users understand the role of the service, which is nice to on-call support people having to operate on a service they are not usualy responsible for."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="scsireserv",
                  order=25,
                  default=False,
                  candidates=(True, False),
                  text="If set to 'true', OpenSVC will try to acquire a type-5 (write exclusive, registrant only) scsi3 persistent reservation on every path to disks of every disk group attached to this service. Existing reservations are preempted to not block service start-up. If the start-up was not legitimate the data are still protected from being written over from both nodes. If set to 'false' or not set, 'scsireserv' can be activated on a per-resource basis."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="bwlimit",
                  order=25,
                  validator=is_integer,
                  text="Bandwidth limit in KB applied to all rsync transfers."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="sync_min_delay",
                  order=26,
                  validator=is_integer,
                  default=30,
                  text="Set the minimum delay between syncs in minutes. If a sync is triggered through crond or manually, it is skipped if last sync occured less than 'sync_min_delay' ago. The mecanism is enforced by a timestamp created upon each sync completion in /opt/opensvc/var/sync/[service]![dst]"
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="sync_max_delay",
                  order=27,
                  validator=is_integer,
                  default=1440,
                  text="Unit is minutes. This sets to delay above which the sync status of the resource is to be considered down. Should be set according to your application service level agreement. The cron job frequency should be set between 'sync_min_delay' and 'sync_max_delay'"
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="presnap_trigger",
                  order=28,
                  text="Define a command to run before creating snapshots. This is most likely what you need to use plug a script to put you data in a coherent state (alter begin backup and the like)."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="postsnap_trigger",
                  order=29,
                  text="Define a command to run after snapshots are created. This is most likely what you need to use plug a script to undo the actions of 'presnap_trigger'."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="containerize",
                  order=30,
                  default=True,
                  candidates=(True, False),
                  text="Use process containers when possible. Containers allow capping memory, swap and cpu usage per service. Lxc containers are naturally containerized, so skip containerization of their startapp."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="container_cpus",
                  order=31,
                  validator=is_integer,
                  depends=[('containerize', [True])],
                  text="Allow service process to bind only the specified cpus. Cpus are specified as list or range : 0,1,2 or 0-2"
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="container_mems",
                  order=31,
                  validator=is_integer,
                  depends=[('containerize', [True])],
                  text="Allow service process to bind only the specified memory nodes. Memory nodes are specified as list or range : 0,1,2 or 0-2"
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="container_cpu_share",
                  order=31,
                  validator=is_integer,
                  depends=[('containerize', [True])],
                  text="Kernel default value is used, which usually is 1024 shares. In a cpu-bound situation, ensure the service does not use more than its share of cpu ressource. The actual percentile depends on shares allowed to other services."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="container_mem_limit",
                  order=31,
                  validator=is_integer,
                  depends=[('containerize', [True])],
                  text="Ensures the service does not use more than specified memory (in bytes). The Out-Of-Memory killer get triggered in case of tresspassing."
                )
        self += Keyword(
                  section="DEFAULT",
                  keyword="container_vmem_limit",
                  order=31,
                  validator=is_integer,
                  depends=[('containerize', [True])],
                  text="Ensures the service does not use more than specified memory+swap (in bytes). The Out-Of-Memory killer get triggered in case of tresspassing. The specified value must be greater than container_mem_limit."
                )
        self += Keyword(
                  section="sync",
                  keyword="type",
                  order=10,
                  required=True,
                  candidates=("rsync", "dds", "netapp", "zfs", "symclone"),
                  default="rsync",
                  text="Point a sync driver to use."
                )
        self += Keyword(
                  section="sync",
                  keyword="src",
                  rtype="zfs",
                  order=10,
                  at=True,
                  required=True,
                  text="Source dataset of the sync."
                )
        self += Keyword(
                  section="sync",
                  keyword="dst",
                  rtype="zfs",
                  order=11,
                  at=True,
                  required=True,
                  text="Destination dataset of the sync."
                )
        self += Keyword(
                  section="sync",
                  keyword="target",
                  rtype="zfs",
                  order=12,
                  required=True,
                  candidates=['nodes', 'drpnodes', 'nodes drpnodes'],
                  text="Describes which nodes should receive this data sync from the PRD node where the service is up and running. SAN storage shared 'nodes' must not be sync to 'nodes'. SRDF-like paired storage must not be sync to 'drpnodes'."
                )
        self += Keyword(
                  section="sync",
                  keyword="recursive",
                  rtype="zfs",
                  order=13,
                  default=True,
                  candidates=(True, False),
                  text="Describes which nodes should receive this data sync from the PRD node where the service is up and running. SAN storage shared 'nodes' must not be sync to 'nodes'. SRDF-like paired storage must not be sync to 'drpnodes'."
                )
        self += Keyword(
                  section="sync",
                  keyword="tags",
                  rtype="zfs",
                  text="The zfs sync resource supports the 'delay_snap' tag. This tag is used to delay the snapshot creation just before the sync, thus after 'postsnap_trigger' execution. The default behaviour (no tags) is to group all snapshots creation before copying data to remote nodes, thus between 'presnap_trigger' and 'postsnap_trigger'."
                )
        self += Keyword(
                  section="sync",
                  keyword="src",
                  rtype="rsync",
                  order=10,
                  at=True,
                  required=True,
                  text="Source of the sync. Can be a whitespace-separated list of files or dirs passed as-is to rsync. Beware of the meaningful ending '/'. Refer to the rsync man page for details."
                )
        self += Keyword(
                  section="sync",
                  keyword="dst",
                  rtype="rsync",
                  order=11,
                  required=True,
                  text="Destination of the sync. Beware of the meaningful ending '/'. Refer to the rsync man page for details."
                )
        self += Keyword(
                  section="sync",
                  keyword="tags",
                  rtype="rsync",
                  text="The sync resource supports the 'delay_snap' tag. This tag is used to delay the snapshot creation just before the rsync, thus after 'postsnap_trigger' execution. The default behaviour (no tags) is to group all snapshots creation before copying data to remote nodes, thus between 'presnap_trigger' and 'postsnap_trigger'."
                )
        self += Keyword(
                  section="sync",
                  keyword="exclude",
                  rtype="rsync",
                  text="!deprecated!. A whitespace-separated list of --exclude params passed unchanged to rsync. The 'options' keyword is preferred now."
                )
        self += Keyword(
                  section="sync",
                  keyword="options",
                  rtype="rsync",
                  text="A whitespace-separated list of params passed unchanged to rsync. Typical usage is ACL preservation activation."
                )
        self += Keyword(
                  section="sync",
                  keyword="target",
                  rtype="rsync",
                  order=12,
                  required=True,
                  candidates=['nodes', 'drpnodes', 'nodes drpnodes'],
                  text="Describes which nodes should receive this data sync from the PRD node where the service is up and running. SAN storage shared 'nodes' must not be sync to 'nodes'. SRDF-like paired storage must not be sync to 'drpnodes'."
                )
        self += Keyword(
                  section="sync",
                  keyword="snap",
                  rtype="rsync",
                  order=14,
                  candidates=(True, False),
                  default=False,
                  text="If set to true, OpenSVC will try to snapshot the first snapshottable parent of the source of the sync and try to sync from the snap."
                )
        self += Keyword(
                  section="sync",
                  keyword="dstfs",
                  rtype="rsync",
                  order=13,
                  text="If set to a remote mount point, OpenSVC will verify that the specified mount point is really hosting a mounted FS. This can be used as a safety net to not overflow the parent FS (may be root)."
                )
        self += Keyword(
                  section="sync",
                  keyword="bwlimit",
                  rtype="rsync",
                  validator=is_integer,
                  text="Bandwidth limit in KB applied to this rsync transfer. Takes precedence over 'bwlimit' set in [DEFAULT]."
                )
        self += Keyword(
                  section="sync",
                  keyword="sync_min_delay",
                  validator=is_integer,
                  default=30,
                  text="Set the minimum delay between syncs in minutes. If a sync is triggered through crond or manually, it is skipped if last sync occured less than 'sync_min_delay' ago. If no set in a resource section, fallback to the value set in the 'default' section. The mecanism is enforced by a timestamp created upon each sync completion in /opt/opensvc/var/sync/[service]![dst]"
                )
        self += Keyword(
                  section="sync",
                  keyword="sync_max_delay",
                  validator=is_integer,
                  default=1440,
                  text="Unit is minutes. This sets to delay above which the sync status of the resource is to be considered down. Should be set according to your application service level agreement. The cron job frequency should be set between 'sync_min_delay' and 'sync_max_delay'."
                )
        self += Keyword(
                  section="ip",
                  keyword="ipname",
                  order=12,
                  at=True,
                  required=True,
                  text="The DNS name of the ip resource. Can be different from one node to the other, in which case '@nodename' can be specified. This is most useful to specify a different ip when the service starts in DRP mode, where subnets are likely to be different than those of the production datacenter."
                )
        self += Keyword(
                  section="ip",
                  keyword="ipdev",
                  order=11,
                  at=True,
                  required=True,
                  text="The interface name over which OpenSVC will try to stack the service ip. Can be different from one node to the other, in which case the '@nodename' can be specified."
                )
        self += Keyword(
                  section="ip",
                  keyword="netmask",
                  order=13,
                  text="If an ip is already plumbed on the root interface (if which case the netmask is deduced from this ip). Mandatory if the interface is dedicated to the service (dummy interface are likely to be in this case). The format is decimal for IPv4, ex: 255.255.252.0, and octal for IPv6, ex: 64."
                )
        self += Keyword(
                  section="vg",
                  keyword="type",
                  order=9,
                  required=False,
                  candidates=['veritas'],
                  text="The volume group driver to use. Leave empty to activate the native volume group manager."
                )
        self += Keyword(
                  section="vg",
                  keyword="vgname",
                  order=10,
                  required=True,
                  text="The name of the volume group"
                )
        self += Keyword(
                  section="vg",
                  keyword="dsf",
                  candidates=(True, False),
                  default=True,
                  text="HP-UX only. 'dsf' must be set to false for LVM to use never-multipathed /dev/dsk/... devices. Otherwize, ad-hoc multipathed /dev/disk/... devices."
                )
        self += Keyword(
                  section="vg",
                  keyword="scsireserv",
                  default=False,
                  candidates=(True, False),
                  text="If set to 'true', OpenSVC will try to acquire a type-5 (write exclusive, registrant only) scsi3 persistent reservation on every path to disks of every disk group attached to this service. Existing reservations are preempted to not block service start-up. If the start-up was not legitimate the data are still protected from being written over from both nodes. If set to 'false' or not set, 'scsireserv' can be activated on a per-resource basis."
                )
        self += Keyword(
                  section="pool",
                  keyword="poolname",
                  order=10,
                  at=True,
                  text="The name of the zfs pool"
                )
        self += Keyword(
                  section="pool",
                  keyword="tags",
                  text="tags  = preboot may be used when zfs pool is required before container boot else postboot is presumed"
                )
        self += Keyword(
                  section="vmdg",
                  keyword="scsireserv",
                  default=False,
                  candidates=(True, False),
                  text="If set to 'true', OpenSVC will try to acquire a type-5 (write exclusive, registrant only) scsi3 persistent reservation on every path to disks of every disk group attached to this service. Existing reservations are preempted to not block service start-up. If the start-up was not legitimate the data are still protected from being written over from both nodes. If set to 'false' or not set, 'scsireserv' can be activated on a per-resource basis."
                )
        self += Keyword(
                  section="drbd",
                  keyword="scsireserv",
                  default=False,
                  candidates=(True, False),
                  text="If set to 'true', OpenSVC will try to acquire a type-5 (write exclusive, registrant only) scsi3 persistent reservation on every path to disks of every disk group attached to this service. Existing reservations are preempted to not block service start-up. If the start-up was not legitimate the data are still protected from being written over from both nodes. If set to 'false' or not set, 'scsireserv' can be activated on a per-resource basis."
                )
        self += Keyword(
                  section="drbd",
                  keyword="res",
                  order=11,
                  text="The name of the drbd resource associated with this service resource. OpenSVC expect the resource configuration file to reside in '/etc/drbd.d/resname.res'. The 'sync#i0' resource will take care of replicating this file to remote nodes."
                )
        self += Keyword(
                  section="fs",
                  keyword="dev",
                  order=11,
                  at=True,
                  required=True,
                  text="The block device file or filesystem image file hosting the filesystem to mount. Different device can be set up on different nodes using the dev@nodename syntax"
                )
        self += Keyword(
                  section="fs",
                  keyword="mnt",
                  order=12,
                  required=True,
                  text="The mount point where to mount the filesystem."
                )
        self += Keyword(
                  section="fs",
                  keyword="mnt_opt",
                  order=13,
                  text="The mount options."
                )
        self += Keyword(
                  section="fs",
                  keyword="type",
                  order=14,
                  required=True,
                  text="The filesystem type. Used to determine the fsck command to use."
                )
        self += Keyword(
                  section="fs",
                  keyword="snap_size",
                  order=14,
                  text="If this filesystem is build on a snapable logical volume or is natively snapable (jfs, vxfs, ...) this setting overrides the default 10% of the filesystem size to compute the snapshot size. The snapshot is created by snap-enabled rsync-type sync resources. The unit is Megabytes."
                )
        self += Keyword(
                  section="loop",
                  keyword="file",
                  required=True,
                  text="The file hosting the disk image to map."
                )
        self += Keyword(
                  section="sync",
                  keyword="filer",
                  rtype="netapp",
                  required=True,
                  at=True,
                  text="The Netapp filer resolvable host name used by the node.  Different filers can be set up for each node using the filer@nodename syntax."
                )
        self += Keyword(
                  section="sync",
                  keyword="path",
                  rtype="netapp",
                  required=True,
                  text="Specifies the volume or qtree to drive snapmirror on."
                )
        self += Keyword(
                  section="sync",
                  keyword="user",
                  rtype="netapp",
                  required=True,
                  default="nasadm",
                  text="Specifies the user used to ssh connect the filers. Nodes should be trusted by keys to access the filer with this user."
                )
        self += Keyword(
                  section="sync",
                  keyword="symdg",
                  rtype="symclone",
                  required=True,
                  text="Name of the symmetrix device group where the source and target devices are grouped."
                )
        self += Keyword(
                  section="sync",
                  keyword="precopy_timeout",
                  rtype="symclone",
                  required=True,
                  default=300,
                  text="Seconds to wait for a precopy (syncresync) to finish before returning with an error. In this case, the precopy proceeds normally, but the opensvc leftover actions must be retried. The precopy time depends on the amount of changes logged at the source, which is context-dependent. Tune to your needs."
                )
        self += Keyword(
                  section="sync",
                  keyword="symdevs",
                  rtype="symclone",
                  required=True,
                  at=True,
                  default=300,
                  text="Whitespace-separated list of devices to drive with this resource. Devices are specified as 'symmetrix identifier:symmetrix device identifier. Different symdevs can be setup on each node using the symdevs@nodename."
                )
        self += Keyword(
                  section="sync",
                  keyword="src",
                  rtype="dds",
                  required=True,
                  text="Points the origin of the snapshots to replicate from."
                )
        self += Keyword(
                  section="sync",
                  keyword="dst",
                  rtype="dds",
                  required=True,
                  text="Target file or block device. Optional. Defaults to src. Points the media to replay the binary-delta received from source node to. This media must have a size superior or equal to source."
                )
        self += Keyword(
                  section="sync",
                  keyword="target",
                  rtype="dds",
                  required=True,
                  candidates=['nodes', 'drpnodes', 'nodes drpnodes'],
                  text="Accepted values are 'drpnodes', 'nodes' or both, whitespace-separated. Points the target nodes to replay the binary-deltas on. Be warned that starting the service on a target node without a 'stop-syncupdate-start cycle, will break the synchronization, so this mode is usually restricted to drpnodes sync, and should not be used to replicate data between nodes with automated services failover."
                )
        self += Keyword(
                  section="sync",
                  keyword="snap_size",
                  rtype="dds",
                  text="Default to 10% of origin. In MB, rounded to physical extent boundaries by lvm tools. Size of the snapshots created by OpenSVC to extract binary deltas from. Opensvc creates at most 2 snapshots : one short-lived to gather changed data from, and one long-lived to gather changed chunks list from. Volume groups should have the necessary space always available."
                )
        self += Keyword(
                  section="vdisk",
                  keyword="path",
                  required=True,
                  at=True,
                  text="Path of the device or file used as a virtual machine disk. The path@nodename can be used to to set up different path on each node."
                )
        self += Keyword(
                  section="hb",
                  keyword="type",
                  required=True,
                  candidates=('OpenHA', 'LinuxHA'),
                  text="Specify the heartbeat driver to use."
                )
        self += Keyword(
                  section="hb",
                  keyword="name",
                  rtype="OpenHA",
                  text="Specify the service name used by the heartbeat. Defaults to the service name."
                )

if __name__ == "__main__":
    store = KeyDict()
    print store
    #print store.DEFAULT.app
    #print store['DEFAULT']
   07070100067200000081a40000000000000000000000014d9d7e6e0000078d000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/rcMountsSunOS.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcMounts
from rcUtilities import *


class Mounts(rcMounts.Mounts):

    def match_mount(self, i, dev, mnt):
        """Given a line of 'mount' output, returns True if (dev, mnt) matches
        this line. Returns False otherwize. Also care about weirdos like loops
        and binds, ...
        """
        if i.mnt != mnt:
            return False
        if i.dev == dev:
            return True
        return False

    def __init__(self):
        self.mounts = []
        (ret, out) = call(['mount','-p'], outdebug=False)
        for line in out.split('\n'):
            words=line.split()
            if len(words) < 6 :
                continue
            elif words[1]+words[4] != '--' :
                # ignore mount line with space in mountpoint or dev
                continue
            elif len(words) == 6 :
                words.append('-')
            dev, null, mnt, type, null, null, mnt_opt = words
            m = rcMounts.Mount(dev, mnt, type, mnt_opt.strip('()'))
            self.mounts.append(m)

if __name__ == "__main__" :
    help(Mounts)
    M=Mounts()
    print M
    
   0707010006725c000081a40000000000000000000000014d9d7e6e0000087e000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/snapZfsSunOS.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from rcUtilities import justcall
import rcExceptions as ex
import snap
from rcZfs import dataset_exists

class Snap(snap.Snap):
    """Defines a snap object with ZFS
    """

    def snapcreate(self, m):
        """ create a snapshot for m
        add self.snaps[m] with
            dict(snapinfo key val)
        """
        dataset = m.device
        if not dataset_exists(dataset, 'filesystem'):
            raise ex.syncNotSnapable
        snapdev = dataset +'@osvc_sync'
        mountPoint = m.mountPoint
        snapMountPoint= mountPoint + '/.zfs/snapshot/osvc_sync/'
        if dataset_exists(snapdev, 'snapshot'):
            (ret, buff) = self.vcall(['zfs', 'destroy', snapdev ])
            if ret != 0:
                raise ex.syncSnapDestroyError
        (ret, buff) = self.vcall(['zfs', 'snapshot', snapdev ])
        if ret != 0:
            raise ex.syncSnapCreateError
        self.snaps[mountPoint]={'snap_mnt' : snapMountPoint, \
                                'snapdev' : snapdev }

    def snapdestroykey(self, snap_key):
        """ destroy a snapshot for a mountPoint
        """
        snapdev = self.snaps[snap_key]['snapdev']
        if not dataset_exists(snapdev, 'snapshot'):
            return
        (ret, buff) = self.vcall(['zfs', 'destroy', snapdev ])
        if ret != 0:
            raise ex.syncSnapDestroyError
  07070100067237000081a40000000000000000000000014d9d7e6e00000610000000b600010002ffffffffffffffff0000002100000000root/opt/opensvc/lib/resIpXen.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

from rcGlobalEnv import rcEnv
resIpHv = __import__("resIp"+rcEnv.sysname)
import resIpVm

class Ip(resIpVm.Ip, resIpHv.Ip):
    def __init__(self, rid=None, ipDev=None, ipName=None,
                 mask=None, always_on=set([]),
                 disabled=False, tags=set([]), optional=False):
        resIpVm.Ip.__init__(self, rid=rid, ipDev=ipDev, ipName=ipName,
                            mask=mask, always_on=always_on,
                            disabled=disabled, tags=tags, optional=optional)

    def check_ping(self):
        return resIpHv.Ip.check_ping(self)


if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

07070100067208000081a40000000000000000000000014d9d7e6e00000922000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/rcPkgSunOS.py    #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
from rcUtilities import call, which
from rcGlobalEnv import rcEnv

"""
format:

   PKGINST:  SUNWzoneu
      NAME:  Solaris Zones (Usr)
  CATEGORY:  system
      ARCH:  i386
   VERSION:  11.11,REV=2009.04.08.17.26
    VENDOR:  Sun Microsystems, Inc.
      DESC:  Solaris Zones Configuration and Administration
   HOTLINE:  Please contact your local service provider
    STATUS:  completely installed

"""

def listpkg():
    if which('pkginfo') is None:
        return []
    cmd = ['pkginfo', '-l']
    (ret, out) = call(cmd, errlog=False, cache=True)
    lines = []
    for line in out.split('\n'):
        l = line.split(':')
        if len(l) != 2:
            continue
        f = l[0].strip()
        if f == "PKGINST":
            x = [rcEnv.nodename, l[1], "", ""]
        elif f == "VERSION":
            x[2] = l[1]
        elif f == "ARCH":
            x[3] = l[1]
        lines.append(x)
    return lines

def listpatch():
    """
    Patch: patchnum-rev Obsoletes: num-rev[,patch-rev]... Requires: .... Incompatibles: ... Packages: ...
    """
    if which('showrev') is None:
        return []
    cmd = ['showrev', '-p']
    (ret, out) = call(cmd, errlog=False, cache=True)
    lines = []
    nodename = rcEnv.nodename
    for line in out.split('\n'):
        l = line.split(' ')
        if len(l) > 3:
            p = l[1].split('-')
            if len(p) != 2:
                continue
            else:
                lines.append( [ nodename , p[0], p[1] ] )
    return lines

if __name__ == "__main__" :
    print listpatch()
  070701000671f0000081a40000000000000000000000014d9d7e6e00000c36000000b600010002ffffffffffffffff0000002800000000root/opt/opensvc/lib/rcIfconfigHP-UX.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

from subprocess import *

import rcIfconfig
import rcExceptions as ex

class ifconfig(rcIfconfig.ifconfig):
    def parse(self, out):
        if len(out) == 0:
            return
        intf = out.split()[0]
        if intf[len(intf)-1] == ':':
            intf = intf[0:len(intf)-1]

        i = rcIfconfig.interface(intf)
        self.intf.append(i)

        # defaults
        i.link_encap = ''
        i.scope = ''
        i.bcast = ''
        i.mask = ''
        i.mtu = ''
        i.ipaddr = ''
        i.ip6addr = []
        i.ip6mask = []
        i.hwaddr = ''
        i.flag_up = False
        i.flag_broadcast = False
        i.flag_running = False
        i.flag_multicast = False
        i.flag_loopback = False

        prev = ''
        for w in out.split():
            if 'broadcast' in prev:
                i.bcast = w
            elif 'netmask' in prev:
                i.mask = "%d.%d.%d.%d"%(
                    int(w[0:2], 16),
                    int(w[2:4], 16),
                    int(w[4:6], 16),
                    int(w[6:8], 16)
                )
            elif 'inet' == prev:
                i.ipaddr = w
            elif 'inet6' == prev:
                i.ip6addr += [w]
            elif 'prefix' == prev:
                i.ip6mask += [w]

            if 'UP' in w:
                i.flag_up = True
            if 'BROADCAST' in w:
                i.flag_broadcast = True
            if 'RUNNING' in w:
                i.flag_running = True
            if 'MULTICAST' in w:
                i.flag_multicast = True
            if 'LOOPBACK' in w:
                i.flag_loopback = True

            prev = w

    def __init__(self):
        self.intf = []
        intf_list = []
        out = Popen(['netstat', '-win'], stdout=PIPE).communicate()[0]
        for line in out.split('\n'):
            if len(line) == 0:
                continue
            if 'IPv4:' in line or 'IPv6' in line:
                continue
            intf_list += [line.split()[0]]
        for intf in intf_list:
            p = Popen(['ifconfig', intf], stdout=PIPE, stderr=PIPE)
            out = p.communicate()
            if "no such interface" in out[1]:
                continue
            elif p.returncode != 0:
                raise ex.excError
            self.parse(out[0])
  070701000671ee000081a40000000000000000000000014d9d7e6e00000a47000000b600010002ffffffffffffffff0000002a00000000root/opt/opensvc/lib/rcIfconfigFreeBSD.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

from subprocess import *

import rcIfconfig

class ifconfig(rcIfconfig.ifconfig):
    def parse(self, out):
        prev = ''
        prevprev = ''
        for w in out.split():
            if 'flags=' in w:
                i = rcIfconfig.interface(prev.replace(':',''))
                self.intf.append(i)

                # defaults
                i.link_encap = ''
                i.scope = ''
                i.bcast = ''
                i.mtu = ''
                i.ipaddr = []
                i.mask = []
                i.ip6addr = []
                i.ip6mask = []
                i.hwaddr = ''
                i.flag_up = False
                i.flag_broadcast = False
                i.flag_running = False
                i.flag_multicast = False
                i.flag_loopback = False

                flags = w.split('<')[1].split('>')[0].split(',')
                if 'UP' in flags:
                    i.flag_up = True
                if 'BROADCAST' in flags:
                    i.flag_broadcast = True
                if 'RUNNING' in flags:
                    i.flag_running = True
                if 'MULTICAST' in flags:
                    i.flag_multicast = True
                if 'LOOPBACK' in flags:
                    i.flag_loopback = True
            elif 'inet' == prev:
                i.ipaddr += [w]
            elif 'inet6' == prev:
                i.ip6addr += [w.split('%')[0]]
            elif 'netmask' == prev:
                i.mask += [w]
            elif 'prefixlen' == prev:
                i.ip6mask += [w]
            elif 'ether' == prev:
                i.hwaddr = w

            prevprev = prev
            prev = w

    def __init__(self):
        self.intf = []
        out = Popen(['ifconfig', '-a'], stdout=PIPE).communicate()[0]
        self.parse(out)
 070701000671e5000081a40000000000000000000000014d9d7e6e00000b82000000b600010002ffffffffffffffff0000002800000000root/opt/opensvc/lib/rcDiskInfoHP-UX.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

from rcUtilities import call
import rcDiskInfo

class diskInfo(rcDiskInfo.diskInfo):

    def __init__(self):
        self.h = {}
        cmd = ["scsimgr", "-p", "get_attr", "all_lun", "-a", "wwid", "-a", "device_file", "-a", "vid", "-a", "pid", "-a", "capacity"]
        (ret, out) = call(cmd)
        for e in out.split('\n'):
            if len(e) == 0:
                continue
            (wwid, dev, vid, pid, size) = e.split(':')
            dev = self.devkey(dev)
            wwid = wwid.replace('0x', '')
            if len(size) != 0:
                size = int(size)/2097152
            vid = vid.strip('" ')
            pid = pid.strip('" ')
            self.h[dev] = dict(wwid=wwid, vid=vid, pid=pid, size=size)

    def devkey(self, dev):
        dev = dev.replace("/dev/rdisk/", "")
        dev = dev.replace("/dev/disk/", "")
        dev = dev.replace("/dev/dsk/", "")
        return dev

    def dev2char(self, dev):
        dev = dev.replace("/dev/disk/", "/dev/rdisk/")
        dev = dev.replace("/dev/dsk/", "/dev/rdsk/")
        return dev

    def scan(self, dev):
        cmd = ["scsimgr", "-p", "get_attr", "-D", self.dev2char(dev), "-a", "wwid", "-a", "device_file", "-a", "vid", "-a", "pid", "-a", "capacity"]
        (ret, out) = call(cmd, errlog=False)
        dev = self.devkey(dev)
        if ret != 0:
            self.h[dev] = dict(wwid="", vid="", pid="", size="")
            return
        (wwid, foo, vid, pid, size) = out.split(':')
        wwid = wwid.replace('0x', '')
        if len(size) != 0:
            size = int(size)/2097152
        vid = vid.strip('" ')
        pid = pid.strip('" ')
        self.h[dev] = dict(wwid=wwid, vid=vid, pid=pid, size=size)

    def get(self, dev, type):
        if dev not in self.h:
            self.scan(dev)
        dev = self.devkey(dev)
        return self.h[dev][type]

    def disk_id(self, dev):
        return self.get(dev, 'wwid')

    def disk_vendor(self, dev):
        return self.get(dev, 'vid')

    def disk_model(self, dev):
        return self.get(dev, 'pid')

    def disk_size(self, dev):
        return self.get(dev, 'size')

  070701000671f7000081a40000000000000000000000014d9d7e6e00000501000000b600010002ffffffffffffffff0000002c00000000root/opt/opensvc/lib/rcIfconfigSunOSldom.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcExceptions as ex
from subprocess import *

rcIfconfig = __import__("rcIfconfigSunOS")
from rcGlobalEnv import rcEnv

class ifconfig(rcIfconfig.ifconfig):
    def __init__(self, hostname):
        self.intf = []
        cmd = rcEnv.rsh.split(' ') + [hostname, 'env', 'LANG=C', 'ifconfig', '-a']
        p = Popen(cmd, stdout=PIPE)
        buff = p.communicate()[0]
        if p.returncode != 0:
            raise ex.excError
        self.parse(buff)
   07070100067250000081a40000000000000000000000014d9d7e6e000022ad000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/resVgHP-UX.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import re
import os
import rcExceptions as ex
import resDg
from subprocess import *
from rcUtilities import qcall
from rcGlobalEnv import rcEnv

class Vg(resDg.Dg):
    def __init__(self, rid=None, name=None, type=None,
                 always_on=set([]), dsf=True,
                 disabled=False, tags=set([]), optional=False):
        self.label = name
        self.dsf = dsf
        resDg.Dg.__init__(self, rid=rid, name=name,
                          type='disk.vg',
                          always_on=always_on,
                          optional=optional,
                          disabled=disabled, tags=tags)

    def files_to_sync(self):
        return [self.mapfile_name(), self.mkfsfile_name()]

    def mapfile_name(self):
        return os.path.join(rcEnv.pathvar, 'vg_' + self.svc.svcname + '_' + self.name + '.map')

    def mkfsfile_name(self):
        return os.path.join(rcEnv.pathvar, 'vg_' + self.svc.svcname + '_' + self.name + '.mksf')

    def has_it(self):
        """ returns True if the volume is present
        """
        if self.is_active():
            return True
        if not os.path.exists(self.mapfile_name()):
            return False
        if self.is_imported():
            return True
        return False

    def dev2char(self, dev):
        dev = dev.replace("/dev/disk", "/dev/rdisk")
        dev = dev.replace("/dev/dsk", "/dev/rdsk")
        return dev

    def dsf_name(self, dev):
        cmd = ['scsimgr', 'get_attr', '-D', self.dev2char(dev), '-a', 'device_file', '-p']
        (ret, out) = self.call(cmd)
        if ret != 0:
            raise ex.excError
        return out.split()[0]

    def write_mksf(self):
        cmd = ['ioscan', '-F', '-m', 'dsf']
        (ret, buff) = self.call(cmd)
        if ret != 0:
            raise ex.excError
        if len(buff) == 0:
            return
        mksf = {}
        if len(self.disks) == 0:
            self.disks = self.disklist()
        dsf_names = map(self.dsf_name, self.disks)
        with open(self.mkfsfile_name(), 'w') as f:
            for line in buff.split('\n'):
                if len(line) == 0:
                    return
                a = line.split(':')[0]
                if '/dev/pt/pt' not in a and '/dev/rdisk/disk' not in a and self.dsf_name(a) in dsf_names:
                    cmd = ['scsimgr', 'get_attr', '-D', self.dev2char(a), '-a', 'wwid', '-p']
                    (ret, out) = self.call(cmd)
                    if ret != 0:
                        raise ex.excError
                    f.write(":".join([a, out.split()[0].replace('0x', '')])+'\n')

    def do_mksf(self):
        if not os.path.exists(self.mkfsfile_name()):
            return

        instance = {}
        cmd = ['scsimgr', 'get_attr', 'all_lun', '-a', 'wwid', '-a', 'instance', '-p']
        (ret, buff) = self.call(cmd)
        for line in buff.split('\n'):
            l = line.split(':')
            if len(l) != 2:
                continue
            instance[l[0].replace('0x', '')] = l[1]

        with open(self.mkfsfile_name(), 'r') as f:
            err = 0
            for line in f.readlines():
                a = line.replace('\n', '').split(':')
                if len(a) == 0:
                    continue
                if os.path.exists(a[0]):
                    continue
                if a[1] not in instance.keys():
                    self.log.error("expected lun %s not present on node %s"%(a[1], rcEnv.nodename))
                    err += 1
                    continue
                cmd = ['mksf', '-r', '-C', 'disk', '-I', instance[a[1]], a[0]]
                (ret, buff) = self.vcall(cmd)
                if ret != 0:
                    err += 1
                    continue
        if err > 0:
            raise ex.excError

    def presync(self):
        """ this one is exported as a service command line arg
        """
        cmd = [ 'vgexport', '-m', self.mapfile_name(), '-p', '-s', self.name ]
        ret = qcall(cmd)
        if ret != 0:
            raise ex.excError
        self.write_mksf()

    def is_active(self):
        cmd = [ 'vgdisplay', self.name ]
        process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
        buff = process.communicate()
        if not "available" in buff[0]:
            return False
        return True

    def is_imported(self):
        if not os.path.exists(self.mapfile_name()):
            return False
        if self.dsf:
            dsfflag = '-N'
        else:
            dsfflag = ''
        cmd = [ 'vgimport', '-m', self.mapfile_name(), '-s', '-p', dsfflag, self.name ]
        process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
        buff = process.communicate()
        if not "already exists" in buff[1]:
            return False
        return True

    def is_up(self):
        """Returns True if the volume group is present and activated
        """
        if not os.path.exists(self.mapfile_name()):
            self.do_export()
        if not self.is_imported():
            return False
        if not self.is_active():
            return False
        return True

    def do_import(self):
        if self.is_imported():
            self.log.info("%s is already imported" % self.name)
            return
        if self.dsf:
            dsfflag = '-N'
        else:
            dsfflag = ''
        cmd = [ 'vgimport', '-m', self.mapfile_name(), '-s', dsfflag, self.name ]
        self.log.info(' '.join(cmd))
        process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
        buff = process.communicate()
        if len(buff[1]) > 0 and buff[1] != "vgimport: ":
            self.log.error('error:\n' + buff[1])
        if len(buff[0]) > 0:
            self.log.debug('output:\n' + buff[0])
        if process.returncode != 0:
            raise ex.excError

    def do_export(self):
        preview = False
        if os.path.exists(self.mapfile_name()):
            if not self.is_imported():
                self.log.info("%s is already exported" % self.name)
                return
        elif self.is_active():
            preview = True
        if preview:
            cmd = [ 'vgexport', '-p', '-m', self.mapfile_name(), '-s', self.name ]
        else:
            cmd = [ 'vgexport', '-m', self.mapfile_name(), '-s', self.name ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def do_activate(self):
        if self.is_active():
            self.log.info("%s is already available" % self.name)
            return
        cmd = ['vgchange', '-a', 'y', self.name]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def do_deactivate(self):
        if not self.is_active():
            self.log.info("%s is already unavailable" % self.name)
            return
        cmd = ['vgchange', '-a', 'n', self.name]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def do_start(self):
        self.do_import()
        self.do_activate()

    def do_stop(self):
        self.do_deactivate()
        self.do_export()

    def start(self):
        self.do_mksf()
        self.do_start()

    def disklist(self):
        need_export = False
        if not self.is_active() and not self.is_imported():
            self.do_import()
            need_export = True
        cmd = ['strings', '/etc/lvmtab']
        (ret, out) = self.call(cmd)
        if ret != 0:
            raise ex.excError

        tab = out.split('\n')
        insection = False
        self.disks = set([])
        for e in tab:
            """ move to the first disk of the vg
            """
            if e == '/dev/'+self.name:
                 insection = True
                 continue
            if not insection:
                 continue
            if e == "_KDI":
                 continue
            if "/dev/dsk" not in e and "/dev/disk" not in e:
                 break
            self.disks |= set([e])

        if need_export:
            self.do_export()
        return self.disks
   0707010006724f000081a40000000000000000000000014d9d7e6e00000f64000000b600010002ffffffffffffffff0000002100000000root/opt/opensvc/lib/resVgAIX.py  #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import rcExceptions as ex
import resDg
from subprocess import *

class Vg(resDg.Dg):
    def __init__(self, rid=None, name=None, type=None,
                 always_on=set([]), dsf=True,
                 disabled=False, tags=set([]), optional=False):
        self.label = name
        self.dsf = dsf
        resDg.Dg.__init__(self, rid=rid, name=name,
                          type='disk.vg',
                          always_on=always_on,
                          optional=optional,
                          disabled=disabled, tags=tags)

    def has_it(self):
        """ returns True if the volume is present
        """
        if self.is_active():
            return True
        if self.is_imported():
            return True
        return False

    def is_active(self):
        cmd = [ 'lsvg', self.name ]
        process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
        buff = process.communicate()
        if not "active" in buff[0]:
            return False
        return True

    def is_imported(self):
        cmd = ['lsvg']
        process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
        buff = process.communicate()
        for vg in buff[0].split('\n'):
            if vg == self.name:
                return True
        return False

    def is_up(self):
        """Returns True if the volume group is present and activated
        """
        if not self.is_imported():
            return False
        if not self.is_active():
            return False
        return True

    def do_import(self):
        if self.is_imported():
            self.log.info("%s is already imported" % self.name)
            return
        cmd = ['importvg', self.name]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def do_export(self):
        if not self.is_imported():
            self.log.info("%s is already exported" % self.name)
            return
        cmd = ['exportvg', self.name]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def do_activate(self):
        if self.is_active():
            self.log.info("%s is already available" % self.name)
            return
        cmd = ['varyonvg', self.name]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def do_deactivate(self):
        if not self.is_active():
            self.log.info("%s is already unavailable" % self.name)
            return
        cmd = ['varyoffvg', self.name]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def do_start(self):
        self.do_import()
        self.do_activate()

    def do_stop(self):
        self.do_deactivate()

    def start(self):
        self.do_start()

    def disklist(self):
        cmd = ['lsvg', '-p', self.name]
        (ret, out) = self.call(cmd)
        if ret != 0:
            raise ex.excError

        for e in out.split('\n'):
            x = e.split()
            if len(x) != 5:
                continue
            self.disks |= set([x[0]])

        return self.disks
07070100067236000081a40000000000000000000000014d9d7e6e00000bb3000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/resIpVm.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import rcExceptions as ex
import rcStatus
from subprocess import *
from rcUtilities import qcall
from rcGlobalEnv import rcEnv
import resIp as Res

class Ip(Res.Ip):
    def is_up(self):
        for vm in self.svc.get_res_sets("container."+self.svc.svcmode):
            pass
        if vm.status() == rcStatus.DOWN:
            self.log.debug("container is down")
            self.status_log("container is down")
            return False
        try:
            rcIfconfig = __import__("rcIfconfig"+self.svc.guestos+self.svc.svcmode)
        except:
            print "rcIfconfig"+self.svc.guestos+self.svc.svcmode
            raise ex.excNotSupported
        try:
            ifconfig = rcIfconfig.ifconfig(self.svc.vmname)
        except:
            self.log.error("failed to fetch interface configuration")
            return False
        if ifconfig.has_param("ipaddr", self.addr) is not None or \
           ifconfig.has_param("ip6addr", self.addr) is not None:
            self.log.debug("%s@%s is up" % (self.addr, self.ipDev))
            return True
        self.log.debug("%s@%s is down" % (self.addr, self.ipDev))
        return False

    def allow_start(self):
        for vm in self.svc.get_res_sets("container."+self.svc.svcmode):
            pass
        if self.check_ping() and vm.status() == rcStatus.DOWN:
            self.log.error("%s is already up on another host" % (self.addr))
            raise ex.IpConflict(self.addr)
        return

    def start(self):
        self.getaddr()
        try:
            self.allow_start()
        except ex.IpConflict:
            raise ex.excError

    def stop(self):
        pass

    def __init__(self, rid=None, ipDev=None, ipName=None,
                 mask=None, always_on=set([]),
                 disabled=False, tags=set([]), optional=False):
        Res.Ip.__init__(self, rid=rid, ipDev=ipDev, ipName=ipName,
                        mask=mask, always_on=always_on,
                        disabled=disabled, tags=tags, optional=optional)


if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

 070701000671c9000081a40000000000000000000000014d9d7e6e000006d8000000b600010002ffffffffffffffff0000002a00000000root/opt/opensvc/lib/checkFsInodeLinux.py #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import checks
from rcUtilities import justcall

class check(checks.check):
    chk_type = "fs_i"

    def find_svc(self, mountpt):
        for svc in self.svcs:
            for rs in svc.get_res_sets('fs'):
                for r in rs.resources:
                    if r.mountPoint == mountpt:
                        return svc.svcname
        return ''

    def do_check(self):
        cmd = ['df', '-lPi']
        (out,err,ret) = justcall(cmd)
        if ret != 0:
            return self.undef
        lines = out.split('\n')
        if len(lines) < 2:
            return self.undef
        r = []
        for line in lines[1:]:
            l = line.split()
            if len(l) != 6:
                continue
            r.append({
                      'chk_instance': l[5],
                      'chk_value': l[4],
                      'chk_svcname': self.find_svc(l[5]),
                     })
        return r
07070100067267000081a40000000000000000000000014d9d7e6e00000798000000b600010002ffffffffffffffff0000001e00000000root/opt/opensvc/lib/svcVz.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import svc
import resContainerVz as vz

class SvcVz(svc.Svc):
    def __init__(self, svcname, vmname=None, guestos=None, optional=False, disabled=False, tags=set([])):
        svc.Svc.__init__(self, svcname, optional=optional, disabled=disabled, tags=tags)
        if vmname is None:
            vmname = svcname
        self.vmname = vmname
        self.guestos = guestos
        self += vz.Vz(vmname)
        self.runmethod = ['vzctl', 'exec', vmname]



if __name__ == "__main__":
    for c in (SvcVz,) :
        help(c)
    import mountLinux as mount
    import ipLinux as ip
    print """
    Z=SvcVz()
    Z+=mount.Mount("/mnt1","/dev/sda")
    Z+=mount.Mount("/mnt2","/dev/sdb")
    Z+=ip.Ip("eth0","192.168.0.173")
    Z+=ip.Ip("eth0","192.168.0.174")
    """

    Z=SvcVz()
    Z+=mount.Mount("/mnt1","/dev/sda")
    Z+=mount.Mount("/mnt2","/dev/sdb")
    Z+=ip.Ip("eth0","192.168.0.173")
    Z+=ip.Ip("eth0","192.168.0.174")

    print "Show Z: ", Z
    print "start Z:"
    Z.start()

    print "stop Z:"
    Z.stop()

070701000671d6000081a40000000000000000000000014d9d7e6e00000afa000000b600010002ffffffffffffffff0000001d00000000root/opt/opensvc/lib/lock.py  import fcntl
import os
import time
import rcExceptions as ex
from rcGlobalEnv import rcEnv

class lockTimeout(Exception):
    """ acquire lock timed out
    """

class lockNoLockFile(Exception):
    """ no lockfile specified
    """

class lockCreateError(Exception):
    """ could not create lockfile
    """

class lockAcquire(Exception):
    """ could not acquire lock on lockfile
    """
    def __init__(self, pid):
        self.pid = pid

def monlock(timeout=30, delay=5, fname='svcmon.lock'):
    lockfile = os.path.join(rcEnv.pathlock, fname)
    try:
        lockfd = lock(timeout=timeout, delay=delay, lockfile=lockfile)
    except lockTimeout:
        print("timed out waiting for lock (%s)"%lockfile)
        raise ex.excError
    except lockNoLockFile:
        print("lock_nowait: set the 'lockfile' param")
        raise ex.excError
    except lockCreateError:
        print("can not create lock file (%s)"%lockfile)
        raise ex.excError
    except lockAcquire as e:
        print("another svcmon is currently running (pid=%s)"%e.pid)
        raise ex.excError
    except:
        print("unexpected locking error (%s)"%lockfile)
        raise ex.excError
    return lockfd

def monunlock(lockfd):
    unlock(lockfd)

def lock(timeout=30, delay=5, lockfile=None):
    for i in range(timeout//delay):
        try:
            return lock_nowait(lockfile)
        except lockAcquire:
            time.sleep(delay)
    raise lockTimeout

def lock_nowait(lockfile=None):
    if lockfile is None:
        raise lockNoLockFile

    pid = 0
    dir = os.path.dirname(lockfile)

    if not os.path.exists(dir):
        os.makedirs(dir)

    try:
        with open(lockfile, 'r') as fd:
            pid = int(fd.read())
            fd.close()
    except:
        pass

    try:
        lockfd = os.open(lockfile, os.O_RDWR|os.O_SYNC|os.O_CREAT|os.O_TRUNC, 0644)
    except:
        raise lockCreateError

    try:
        """ test if we already own the lock
        """
        if pid == os.getpid():
            os.close(lockfd)
            return

        """ FD_CLOEXEC makes sure the lock is the held by processes
            we fork from this process
        """
        fcntl.flock(lockfd, fcntl.LOCK_EX|fcntl.LOCK_NB)
        flags = fcntl.fcntl(lockfd, fcntl.F_GETFD)
        flags |= fcntl.FD_CLOEXEC

        """ acquire lock
        """
        fcntl.fcntl(lockfd, fcntl.F_SETFD, flags)

        """ drop our pid in the lockfile
        """
        os.write(lockfd, str(os.getpid()))
        os.fsync(lockfd)
        return lockfd
    except IOError:
        raise lockAcquire(pid)
    except:
        raise

def unlock(lockfd):
    if lockfd is None:
        return
    try:
        os.close(lockfd)
    except:
        """ already released by a parent process ?
        """
        pass

  070701000671c7000081a40000000000000000000000014d9d7e6e0000071d000000b600010002ffffffffffffffff0000002b00000000root/opt/opensvc/lib/checkFsInodeDarwin.py    #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import checks
from rcUtilities import justcall

class check(checks.check):
    chk_type = "fs_i"

    def find_svc(self, mountpt):
        for svc in self.svcs:
            for rs in svc.get_res_sets('fs'):
                for r in rs.resources:
                    if r.mountPoint == mountpt:
                        return svc.svcname
        return ''

    def do_check(self):
        cmd = ['df', '-lPi']
        (out,err,ret) = justcall(cmd)
        if ret != 0:
            return self.undef
        lines = out.split('\n')
        if len(lines) < 2:
            return self.undef
        r = []
        for line in lines[1:]:
            l = line.split()
            if len(l) != 9:
                continue
            if l[5].startswith('/Volumes'):
                continue
            r.append({
                      'chk_instance': l[8],
                      'chk_value': l[7],
                      'chk_svcname': self.find_svc(l[8]),
                     })
        return r
   07070100067214000081a40000000000000000000000014d9d7e6e00000173000000b600010002ffffffffffffffff0000002a00000000root/opt/opensvc/lib/rcUtilitiesDarwin.py from rcUtilities import call, qcall

def check_ping(addr, timeout=5, count=1):
    if ':' in addr:
        ping = 'ping6'
    else:
        ping = 'ping'
    cmd = [ping, '-c', repr(count),
                 '-W', repr(timeout),
                 '-t', repr(timeout),
                 addr]
    (ret, out) = call(cmd)
    if ret == 0:
        return True
    return False

 07070100067256000081a40000000000000000000000014d9d7e6e00001473000000b600010002ffffffffffffffff0000002100000000root/opt/opensvc/lib/resVgZfs.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.
"""Module providing ZFS resources
"""

from rcGlobalEnv import rcEnv
import resDg
from rcUtilities import qcall

import re

class Pool(resDg.Dg):
    """ basic pool resource
    """
    def __init__(self, rid=None, name=None, type=None,
                 optional=False, disabled=False, tags=set([]),
                 always_on=set([])):
        self.label = 'pool ' + name
        resDg.Dg.__init__(self, rid=rid, name=name,
                          type='disk.zpool',
                          always_on=always_on,
                          optional=optional, disabled=disabled, tags=tags)

    def has_it(self):
        """Returns True if the pool is present
        """
        ret = qcall( [ 'zpool', 'list', self.name ] )
        if ret == 0 :
            return True
        return False

    def is_up(self):
        """Returns True if the pool is present and activated
        """
        if not self.has_it():
            return False
        cmd = [ 'zpool', 'list', '-H', '-o', 'health', self.name ]
        (ret, out) = self.call(cmd)
        if out.strip() == "ONLINE" :
            return True
        return False

    def do_start(self):
        if self.is_up():
            self.log.info("%s is already up" % self.name)
            return 0
        cmd = [ 'zpool', 'import', self.name ]
        (ret, out) = self.vcall(cmd)
        return ret

    def do_stop(self):
        if not self.is_up():
            self.log.info("%s is already down" % self.name)
            return 0
        cmd = [ 'zpool', 'export', self.name ]
        (ret, out) = self.vcall(cmd)
        return ret

    def disklist(self):
        """disklist() search zpool vdevs from
        output of : zpool status poolname if status cmd == 0
        else
        output of : zpool import output if status cmd == 0

        disklist(self) update self.disks[]
        """
        if len(self.disks) > 0 :
            return self.disks

        disks = set([])
        cmd = [ 'zpool', 'status', self.name ]
        (ret, out) = self.call(cmd, errlog=False)
        if ret != 0 :
            matchedPool=False
            cmd = [ 'zpool', 'import' ]
            (ret, out) = self.call(cmd)
            if ret != 0 :
                self.disks = disks
                return disks
            for line in out.split('\n'):
                if re.match('^  pool: ', line) is not None:
                    # This is pool: xxxx
                    # set watchNext if it is serached pool
                    # else disable watchNext
                    if line == '  pool: ' + self.name :
                        if matchedPool == True :
                            raise Exception("duplicated pools available")
                        matchedPool = True
                        watchNext = True
                    else :
                        watchNext = False
                elif watchNext == True :
                    # only look for 'tab  c*d vdev entries
                    if re.match('^\t  ', line) is not None:
                        if re.match('^\t  mirror', line) is not None:
                            continue
                        if re.match('^\t  raid', line) is not None:
                            continue
                        disk = line.split()[0]
                        disks.add("/dev/rdsk/" + disk)
        else :
            for line in out.split('\n'):
                if re.match('^\t  ', line) is not None:
                    if re.match('^\t  mirror', line) is not None:
                        continue
                    if re.match('^\t  raid', line) is not None:
                        continue
                    # vdev entry
                    disk=line.split()[0]
                    if re.match("^.*", disk) is not None :
                        disks.add("/dev/rdsk/" + disk )
        self.log.debug("found disks %s held by pool %s" % (disks, self.name))
        for d in disks:
            if re.match('^.*s[0-9]$', d) is None:
                    d += "s2"
            self.disks.add(d)

        return self.disks

if __name__ == "__main__":
    for c in (Pool,) :
        help(c)

    print """p=Pool("svczfs1")"""
    p=Pool("svczfs1")
    print "show p", p
    print """p.do_action("start")"""
    p.do_action("start")
    print """p.do_action("stop")"""
    p.do_action("stop")
 0707010006724b000081a40000000000000000000000014d9d7e6e00002186000000b600010002ffffffffffffffff0000002800000000root/opt/opensvc/lib/resSyncSymclone.py   #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import logging

from rcGlobalEnv import rcEnv
from rcUtilities import which
import rcExceptions as ex
import rcStatus
import time
import datetime
import resSync

class syncSymclone(resSync.Sync):
    def wait_for_devs_ready(self):
        pass

    def get_symdevs(self):
        for symdev in self.symdevs:
            l = symdev.split(':')
            if len(l) != 2:
                self.log.error("symdevs must be in symid:symdev ... format")
                raise ex.excError
            self.symdev[l[0],l[1]] = dict(symid=l[0], symdev=l[1])

    def get_symld(self):
        cmd = ['/usr/symcli/bin/symld', '-g', self.symdg, 'list', '-v']
        (ret, out) = self.call(cmd)
        if ret != 0:
            raise ex.excError
        ld = {}
        for line in out.split('\n'):
            if len(line) == 0:
                continue
            l = line.split(': ')
            if len(l) != 2:
                continue
            if "Device Physical Name" in l[0]:
                """ New logical device
                """
                if ld != {}:
                    self.symld[ld['symid'],ld['symdev']] = ld
                    ld = {}
                ld['pdev'] = l[1].strip()
            elif "  Symmetrix ID" in l[0]:
                ld['symid'] = l[1].strip()
            elif "  Device Symmetrix Name" in l[0]:
                ld['symdev'] = l[1].strip()
            elif "  Device Logical Name" in l[0]:
                ld['symld'] = l[1].strip()
            elif "  Product Revision" in l[0]:
                ld['symrev'] = l[1].strip()
            elif "  Source (SRC) Device Symmetrix Name" in l[0]:
                ld['clone_srcdev'] = l[1].strip()
            elif "  Target (TGT) Device Symmetrix Name" in l[0]:
                ld['clone_tgtdev'] = l[1].strip()
            elif "  State of Session" in l[0]:
                ld['clone_state'] = l[1].strip()
            elif "  Time of Last Clone Action" in l[0]:
                ld['clone_lastaction'] = l[1].strip()
            elif "  Changed Tracks for SRC Device" in l[0]:
                ld['clone_srcchangedtracks'] = l[1].strip()
            elif "  Changed Tracks for TGT Device" in l[0]:
                ld['clone_tgtchangedtracks'] = l[1].strip()
        if ld != {}:
            self.symld[ld['symid'],ld['symdev']] = ld

    def is_active(self):
        cmd = ['/usr/symcli/bin/symclone', '-g', self.symdg, 'verify', '-copied']+self.pairs
        (ret, out) = self.call(cmd)
        if ret == 0:
            return True
        return False

    def is_activable(self):
        cmd = ['/usr/symcli/bin/symclone', '-g', self.symdg, 'verify', '-precopy']+self.pairs
        (ret, out) = self.call(cmd)
        if ret == 0:
            return True
        return False

    def get_pairs(self):
        for symid, dev in self.symdev:
            ld = self.symld[symid,dev]
            if dev == ld['clone_tgtdev']:
                tgtld = ld['symld']
                srcld = self.symld[ld['symid'],ld['clone_srcdev']]['symld']
            else:
                self.log.error("device %s not a clone target"%(dev))
                raise ex.excError
            self.pairs += [srcld, 'sym', 'ld', tgtld]

    def wait_for_active(self):
        delay = 20
        timeout = 300
        for i in range(timeout/delay):
            if self.is_active():
                return
            if i == 0:
                self.log.info("waiting for copied state (max %i secs)"%timeout)
            time.sleep(delay)
        self.log.error("timed out waiting for copied state (%i secs)"%timeout)
        raise ex.excError

    def wait_for_activable(self):
        delay = 30
        for i in range(self.precopy_timeout/delay):
            if self.is_activable():
                return
            if i == 0:
                self.log.info("waiting for precopied state (max %i secs)"%self.precopy_timeout)
            time.sleep(delay)
        self.log.error("timed out waiting for precopied state (%i secs)"%self.precopy_timeout)
        raise ex.excError

    def activate(self):
        self.get_syminfo()
        if self.is_active():
            self.log.info("symclone dg %s is already active"%self.symdg)
            return
        self.wait_for_activable()
        cmd = ['/usr/symcli/bin/symclone', '-g', self.symdg, '-noprompt', 'activate', '-i', '20', '-c', '30']+self.pairs
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError
        self.wait_for_active()
        self.wait_for_devs_ready()

    def can_sync(self, target=None):
        self.get_syminfo()
        self.get_last()
        if skip_sync(self.last):
            return False
        return True

    def recreate(self):
        self.get_syminfo()
        self.get_last()
        if self.skip_sync(self.last):
            return
        self.get_svcstatus()
        if self.svcstatus['overall'].status != rcStatus.DOWN:
            self.log.error("the service (sync excluded) is in '%s' state. Must be in 'down' state"%self.svcstatus['overall'])
            raise ex.excError
        if not self.is_active():
            self.log.info("symclone dg %s is not active"%self.symdg)
            return
        cmd = ['/usr/symcli/bin/symclone', '-g', self.symdg, '-noprompt', 'recreate', '-precopy', '-i', '20', '-c', '30']+self.pairs
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def get_syminfo(self):
        self.get_symdevs()
        self.get_symld()
        self.get_pairs()

    def get_last(self):
        if self.last is not None:
            return
        for symid, symdev in self.symdev:
            ld = self.symld[symid,symdev]
            # format: Thu Feb 25 10:20:56 2010
            last = datetime.datetime.strptime(ld['clone_lastaction'], "%a %b %d %H:%M:%S %Y")
            if self.last is None or last > self.last:
                self.last = last

    def _status(self, verbose=False):
        self.get_syminfo()
        self.get_last()

        if self.last is None:
            return rcStatus.DOWN
        elif self.last < datetime.datetime.now() - datetime.timedelta(minutes=self.sync_max_delay):
            self.status_log("Last sync on %s older than %d minutes"%(self.last, self.sync_max_delay))
            return rcStatus.WARN
        else:
            return rcStatus.UP

    def syncbreak(self):
        self.activate()

    def syncresync(self):
        self.recreate()

    def start(self):
        self.syncbreak()

    def refresh_svcstatus(self):
        self.svcstatus = self.svc.group_status(excluded_groups=set(["sync", 'hb']))

    def get_svcstatus(self):
        if len(self.svcstatus) == 0:
            self.refresh_svcstatus()

    def __init__(self, rid=None, symdg=None, symdevs=[], precopy_timeout=300,
                 sync_max_delay=None, sync_interval=None, sync_days=None,
                 sync_period=None,
                 optional=False, disabled=False, tags=set([]), internal=False):
        resSync.Sync.__init__(self, rid=rid, type="sync.symclone",
                              sync_max_delay=sync_max_delay,
                              sync_interval=sync_interval,
                              sync_days=sync_days,
                              sync_period=sync_period,
                              optional=optional, disabled=disabled, tags=tags)

        self.label = "clone symdg %s"%(symdg)
        self.symdg = symdg
        self.symdevs = symdevs
        self.precopy_timeout = precopy_timeout
        self.disks = set([])
        self.symdev = {}
        self.pdevs = {}
        self.svcstatus = {}
        self.symld = {}
        self.pairs = []
        self.last = None

    def __str__(self):
        return "%s symdg=%s symdevs=%s" % (resSync.Sync.__str__(self),\
                self.symdg, self.symdevs)

  07070100067213000081a40000000000000000000000014d9d7e6e00000141000000b600010002ffffffffffffffff0000002700000000root/opt/opensvc/lib/rcUtilitiesAIX.py    import os
import re
from rcUtilities import call

def check_ping(addr, timeout=5, count=1):
    cmd = ['ping', '-c', repr(count),
                   '-w', repr(timeout)]
    if ':' in addr:
        cmd += ['-a', 'inet6']
    cmd += [addr]
    (ret, out) = call(cmd)
    if ret == 0:
        return True
    return False

   070701000671ec000081a40000000000000000000000014d9d7e6e00000afa000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/rcIfconfigAIX.py #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

from subprocess import *

import rcIfconfig

class ifconfig(rcIfconfig.ifconfig):
    def hexmask_to_str(self, mask):
        mask = mask.replace('0x', '')
        s = [str(int(mask[i:i+2], 16)) for i in range(0, len(mask), 2)]
        return '.'.join(s)

    def parse(self, out):
        prev = ''
        prevprev = ''
        for w in out.split():
            if 'flags=' in w:
                i = rcIfconfig.interface(prev.replace(':',''))
                self.intf.append(i)

                # defaults
                i.link_encap = ''
                i.scope = ''
                i.bcast = ''
                i.mtu = ''
                i.ipaddr = []
                i.mask = []
                i.ip6addr = []
                i.ip6mask = []
                i.hwaddr = ''
                i.flag_up = False
                i.flag_broadcast = False
                i.flag_running = False
                i.flag_multicast = False
                i.flag_loopback = False

                flags = w.split('<')[1].split('>')[0].split(',')
                if 'UP' in flags:
                    i.flag_up = True
                if 'BROADCAST' in flags:
                    i.flag_broadcast = True
                if 'RUNNING' in flags:
                    i.flag_running = True
                if 'MULTICAST' in flags:
                    i.flag_multicast = True
                if 'LOOPBACK' in flags:
                    i.flag_loopback = True
            elif 'inet' == prev:
                i.ipaddr += [w]
            elif 'netmask' == prev:
                i.mask += [self.hexmask_to_str(w)]
            elif 'inet6' == prev:
                i.ip6addr += [w.split('/')[0]]
                i.ip6mask += [w.split('/')[1]]
            elif 'ether' == prev:
                i.hwaddr = w

            prevprev = prev
            prev = w

    def __init__(self):
        self.intf = []
        out = Popen(['ifconfig', '-a'], stdout=PIPE).communicate()[0]
        self.parse(out)
  0707010006721e000081a40000000000000000000000014d9d7e6e00000ebe000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/lib/resContainerJail.py  #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
from datetime import datetime

import rcStatus
import resources as Res
from rcUtilitiesFreeBSD import check_ping
from rcUtilities import qcall
import resContainer
import rcExceptions as ex

class Jail(resContainer.Container):
    """ jail -c name=jail1
                path=/usr/local/opt/jail1.opensvc.com
                host.hostname=jail1.opensvc.com
                ip4.addr=192.168.0.208
                command=/bin/sh /etc/rc
    """
    def files_to_sync(self):
        return []

    def operational(self):
        return True

    def install_drp_flag(self):
        rootfs = self.svc.jailroot
        flag = os.path.join(rootfs, ".drp_flag")
        self.log.info("install drp flag in container : %s"%flag)
        with open(flag, 'w') as f:
            f.write(' ')
            f.close()

    def container_start(self):
        ips = []
        ip6s = []
        for rs in self.svc.get_res_sets("ip"):
            for r in rs.resources:
                if ':' in r.addr:
                    ip6s.append(r.addr)
                else:
                    ips.append(r.addr)
        cmd = ['jail', '-c', 'name='+self.svc.basevmname, 'path='+self.svc.jailroot,
               'host.hostname='+self.svc.vmname]
        if len(ips) > 0:
            cmd += ['ip4.addr='+','.join(ips)]
        if len(ip6s) > 0:
            cmd += ['ip6.addr='+','.join(ip6s)]
        cmd += ['command=/bin/sh', '/etc/rc']
        self.log.info(' '.join(cmd))
        ret = qcall(cmd)
        if ret != 0:
            raise ex.excError

    def container_stop(self):
        cmd = ['jail', '-r', self.svc.basevmname]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def container_forcestop(self):
        """ no harder way to stop a lxc container, raise to signal our
            helplessness
        """
        self.log.error("no forced stop method")
        raise ex.excError

    def ping(self):
        return check_ping(self.addr, timeout=1)

    def is_up(self):
        cmd = ['jls']
        (ret, out) = self.call(cmd)
        if ret != 0:
            raise ex.excError
        for line in out.split('\n'):
            l = line.split()
            if len(l) < 4:
                continue
            if l[2] == self.svc.vmname:
                return True
        return False

    def get_container_info(self):
        print "TODO: get_container_info()"
        return {'vcpus': '0', 'vmem': '0'}

    def _status(self, verbose=False):
        if self.is_up():
            return rcStatus.UP
        else:
            return rcStatus.DOWN

    def __init__(self, name, optional=False, disabled=False, tags=set([])):
        resContainer.Container.__init__(self, rid="jail", name=name, type="container.jail",
                                        optional=optional, disabled=disabled, tags=tags)

    def __str__(self):
        return "%s name=%s" % (Res.Resource.__str__(self), self.name)

  070701000671ca000081a40000000000000000000000014d9d7e6e00000761000000b600010002ffffffffffffffff0000002a00000000root/opt/opensvc/lib/checkFsUsageHP-UX.py #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import checks
from rcUtilities import call

class check(checks.check):
    chk_type = "fs_u"

    def find_svc(self, mountpt):
        for svc in self.svcs:
            for rs in svc.get_res_sets('fs'):
                for r in rs.resources:
                    if r.mountPoint == mountpt:
                        return svc.svcname
        return ''

    def do_check(self):
        """
        Filesystem          kbytes    used   avail %used Mounted on
        /dev/vg00/lvol3    1048576  228080  814208   22% /
        """
        cmd = ['bdf', '-l']
        (ret, out) = call(cmd)
        if ret != 0:
            return self.undef
        lines = out.split('\n')
        if len(lines) < 2:
            return self.undef
        r = []
        for line in lines[1:]:
            l = line.split()
            if len(l) != 6:
                continue
            r.append({'chk_instance': l[0],
                      'chk_value': l[4],
                      'chk_svcname': self.find_svc(l[5]),
                     }
                    )
        return r
   0707010006723c000081a40000000000000000000000014d9d7e6e00001346000000b600010002ffffffffffffffff0000002100000000root/opt/opensvc/lib/resMount.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import resources as Res
import os
import rcExceptions as ex
import rcStatus
from rcGlobalEnv import rcEnv
from rcUtilities import which

class Mount(Res.Resource):
    """Define a mount resource 
    """
    def __init__(self, rid=None, mountPoint=None, device=None, fsType=None,
                 mntOpt=None, snap_size=None, always_on=set([]), optional=False,
                 disabled=False, tags=set([])):
        Res.Resource.__init__(self, rid=rid, type="fs",
                              optional=optional, disabled=disabled, tags=tags)
        self.mountPoint = mountPoint
        self.device = device
        self.fsType = fsType
        self.mntOpt = mntOpt
        self.snap_size = snap_size
        self.always_on = always_on
        self.label = device + '@' + mountPoint
        self.fsck_h = {}
        self.testfile = os.path.join(mountPoint, '.opensvc')

    def start(self):
        if self.fsType == "zfs" :
	    return None
        if not os.path.exists(self.mountPoint):
            try:
                os.makedirs(self.mountPoint)
            except:
                self.log.info("failed to create missing mountpoint %s" % self.mountPoint)
                raise
            self.log.info("create missing mountpoint %s" % self.mountPoint)

    def startstandby(self):
        if rcEnv.nodename in self.always_on:
             self.start()

    def fsck(self):
        if self.fsType not in self.fsck_h:
            self.log.info("fsck not implemented for %s"%self.fsType)
            return
        bin = self.fsck_h[self.fsType]['bin']
        if which(bin) is None:
            self.log.warning("%s not found. bypass."%self.fsType)
            return
        if self.fsck_h[self.fsType].has_key('reportcmd'):
            cmd = self.fsck_h[self.fsType]['reportcmd']
            (ret, out) = self.vcall(cmd, err_to_info=True)
            if ret not in self.fsck_h[self.fsType]['reportclean']:
                return
        cmd = self.fsck_h[self.fsType]['cmd']
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError 

    def need_check_writable(self):
        if 'ro' in self.mntOpt.split(','):
            return False
        if 'nfs' in self.fsType:
            return False
        return True

    def can_check_writable(self):
        """ orverload in child classes to check os-specific conditions
            when a write test might hang (solaris lockfs, linux multipath
            with queueing on and no active path)
        """
        return True

    def check_writable(self):
        if not self.can_check_writable():
            return False
        try:
            f = open(self.testfile, 'w')
            f.write(' ')
            f.close()
        except:
            return False
        return True

    def _status(self, verbose=False):
        if rcEnv.nodename in self.always_on:
            if self.is_up():
                if self.need_check_writable() and not self.check_writable():
                    self.status_log("fs is not writable")
                    return rcStatus.WARN
                return rcStatus.STDBY_UP
            else:
                return rcStatus.STDBY_DOWN
        else:
            if self.is_up():
                if self.need_check_writable() and not self.check_writable():
                    self.status_log("fs is not writable")
                    return rcStatus.WARN
                return rcStatus.UP
            else:
                return rcStatus.DOWN

    def __str__(self):
        return "%s mnt=%s dev=%s fsType=%s mntOpt=%s" % (Res.Resource.__str__(self),\
                self.mountPoint, self.device, self.fsType, self.mntOpt)

    def __cmp__(self, other):
        """order so that deepest mountpoint can be umount first
        """
        return cmp(self.mountPoint, other.mountPoint)

if __name__ == "__main__":
    for c in (Mount,) :
        help(c)
    print """   m=Mount("/mnt1","/dev/sda1","ext3","rw")   """
    m=Mount("/mnt1","/dev/sda1","ext3","rw")
    print "show m", m


  070701000671f4000081a40000000000000000000000014d9d7e6e0000061b000000b600010002ffffffffffffffff0000002b00000000root/opt/opensvc/lib/rcIfconfigLinuxlxc.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

from subprocess import *

import rcIfconfigLinux
from rcGlobalEnv import rcEnv
from rcUtilities import which
import os

class ifconfig(rcIfconfigLinux.ifconfig):
    def __init__(self, hostname):
        self.intf = []

        if which('lxc-attach') and os.path.exists('/proc/1/ns'):
            self.rsh = ['lxc-attach', '-n', hostname]
            cmd = ['echo', '/sbin/ifconfig', '-a']
            p1 = Popen(cmd, stdout=PIPE)
            out = Popen(self.rsh, stdout=PIPE, stdin=p1.stdout).communicate()[0]
        else:
            self.rsh = rcEnv.rsh.split() + [hostname, '--', 'env', 'LANG=C']
            cmd = self.rsh + ['/sbin/ifconfig', '-a']
            out = Popen(cmd, stdout=PIPE).communicate()[0]
        self.parse(out)
 070701000671e9000081a40000000000000000000000014d9d7e6e00000504000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/rcFunctions.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
"""Define some functions
"""

def update_cl_attr(cl=None, module=None, exclude_lstrip="__"):
    """Update class cl attributes with corresponding vars from module.
       vars from module matching exclude_lstrip ("__") are not updated
    """ 
    try:
        mod = __import__(module)
        for p in dir(mod):
            if p in dir(cl) and p.lstrip(exclude_lstrip) == p:
                setattr(cl, p, getattr(mod, p)) 
    except ImportError:
        pass
07070100067261000081a40000000000000000000000014d9d7e6e000005cf000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/svcHpVm.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import svc
import resContainerHpVm as hpvm
import rcStatus
import rcExceptions as ex
from rcGlobalEnv import rcEnv

class SvcHpVm(svc.Svc):
    """ Define hpvm services"""

    def __init__(self, svcname, vmname=None, guestos=None, optional=False, disabled=False, tags=set([])):
        svc.Svc.__init__(self, svcname, optional=optional, disabled=disabled, tags=tags)
        if vmname is None:
            vmname = svcname
        self.vmname = vmname
        self.guestos = guestos
        self += hpvm.HpVm(vmname)
        self.runmethod = rcEnv.rsh.split() + [vmname]

 070701000671cf000081a40000000000000000000000014d9d7e6e000036f6000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/compliance.py    from stat import *
import os
import sys
import re
import datetime
import rcExceptions as ex
import xmlrpcClient
from rcGlobalEnv import rcEnv
from rcUtilities import is_exe, justcall, banner
from subprocess import *

comp_dir = os.path.join(rcEnv.pathvar, 'compliance')

# ex: \x1b[37;44m\x1b[1mContact List\x1b[0m\n
regex = re.compile("\x1b\[([0-9]{1,3}(;[0-9]{1,3})*)?[m|K|G]", re.UNICODE)

class Module(object):
    pattern = '^S*[0-9]+-*%(name)s$'

    def __init__(self, name):
        self.name = name
        self.executable = None

        dl = os.listdir(comp_dir)
        match = []
        for e in dl:
            if re.match(self.pattern%dict(name=name), e) is not None:
                match.append(e)
        if len(match) == 0:
            raise ex.excInitError('module %s not found in %s'%(name, comp_dir))
        if len(match) > 1:
            raise ex.excError('module %s matches too many entries in %s'%(name,
                              comp_dir))
        base = match[0]
        if base[0] == 'S':
            base == base[1:]
        for i, c in enumerate(base):
            if not c.isdigit():
               break
        self.ordering = int(base[0:i])

        locations = []
        locations.append(os.path.join(comp_dir, match[0]))
        locations.append(os.path.join(locations[0], 'main'))
        locations.append(os.path.join(locations[0], 'scripts', 'main'))

        for loc in locations:
            if not os.path.exists(loc):
                continue
            statinfo = os.stat(loc)
            mode = statinfo[ST_MODE]
            if statinfo.st_uid != 0 or statinfo.st_gid not in (0,2,3,4):
                raise ex.excError('%s is not owned by root. security hazard.'%(loc))
            if not S_ISREG(mode):
                continue
            if not is_exe(loc):
                mode |= S_IXUSR
                os.chmod(loc, mode)
            self.executable = loc
        if self.executable is None:
            raise ex.excError('executable not found for module %s'%(name))

    def __str__(self):
        a = []
        a.append("name: %s"%self.name)
        a.append("ordering: %d"%self.ordering)
        a.append("executable: %s"%self.executable)
        return '\n'.join(a)


    def strip_unprintable(self, s):
        return regex.sub('', s)

    def log_action(self, out, ret, action):
        ruleset = ','.join(self.ruleset)
        vars = ['run_nodename', 'run_module', 'run_status', 'run_log',
                'run_ruleset', 'run_action']
        vals = [rcEnv.nodename,
                self.name,
                str(ret),
                self.strip_unprintable(out),
                ruleset,
                action]
        xmlrpcClient.comp_log_action(vars, vals)

    def action(self, action):
        print banner(self.name)

        if action not in ['check', 'fix', 'fixable']:
            print 'action %s not supported'
            return 1

        if self.options.force:
            # short-circuit all pre and post action
            return self.do_action(action)

        if action == 'fix':
            if self.do_action('check') == 0:
                print 'check passed, skip fix'
                return 0
            if self.do_action('fixable') not in (0, 2):
                print 'not fixable, skip fix'
                return 1
            self.do_action('fix')
            r = self.do_action('check')
        elif action == 'check':
            r = self.do_action('check')
            if r == 1:
                self.do_action('fixable')
        elif action == 'fixable':
            r = self.do_action('fixable')
        return r

    def do_action(self, action):
        start = datetime.datetime.now()
        cmd = [self.executable, action]
        log = ''
        print "ACTION:   %s"%action
        print "START:    %s"%str(start)
        print "COMMAND:  %s"%' '.join(cmd)
        print "LOG:"

        import tempfile
        import time
        fo = tempfile.NamedTemporaryFile()
        fe = tempfile.NamedTemporaryFile()
        _fo = open(fo.name, 'r')
        _fe = open(fe.name, 'r')

        def poll_out():
            fop = _fo.tell()
            line = _fo.readline()
            if not line:
                _fo.seek(fop)
                return None
            sys.stdout.write(line)
            sys.stdout.flush()
            return line

        def poll_err():
            fep = _fe.tell()
            line = _fe.readline()
            if not line:
                _fe.seek(fep)
                return None
            line = 'ERR: '+line
            sys.stdout.write(line)
            sys.stdout.flush()
            return line

        def poll_pipes(log):
            i = 0
            while True:
                o = poll_out()
                e = poll_err()
                if o is not None:
                    log += o
                if e is not None:
                    log += e
                if o is None and e is None:
                    break
            return log

        try:
            p = Popen(cmd, stdout=fo, stderr=fe)
            while True:
                time.sleep(0.1)
                log = poll_pipes(log)
                if p.poll() != None:
                    log = poll_pipes(log)
                    break
        except OSError, e:
            fo.close()
            fe.close()
            _fo.close()
            _fe.close()
            if e.errno == 8:
                raise ex.excError("%s execution error (Exec format error)"%self.executable)
            else:
                raise
        fo.close()
        fe.close()
        _fo.close()
        _fe.close()
        end = datetime.datetime.now()
        print "RCODE:    %d"%p.returncode
        print "DURATION: %s"%str(end-start)
        self.log_action(log, p.returncode, action)
        return p.returncode

    def check(self):
        return self.action('check')

    def fix(self):
        return self.action('fix')

    def fixable(self):
        return self.action('fixable')

class Compliance(object):
    def __init__(self, options):
        self.options = options
        self.module_o = {}
        self.module = []

    def __iadd__(self, o):
        self.module_o[o.name] = o
        o.ruleset = self.ruleset
        o.options = self.options
        return self

    def init(self):
        if self.options.moduleset != "" and self.options.module != "":
            raise ex.excError('--moduleset and --module are exclusive')

        if self.options.moduleset == "" and self.options.module == "":
            self.moduleset = self.get_moduleset()
        else:
            self.moduleset = self.options.moduleset.split(',')
            self.module = self.options.module.split(',')
        self.module = self.merge_moduleset_modules()
        self.ruleset = self.get_ruleset()
        self.setup_env()

        if not os.path.exists(comp_dir):
            os.makedirs(comp_dir, 0755)
            raise ex.excError('modules [%s] are not present in %s'%(
                               ','.join(self.module), comp_dir))

        for module in self.module:
            try:
                self += Module(module)
            except ex.excInitError, e:
                print >>sys.stderr, e

        self.ordered_module = self.module_o.keys()
        self.ordered_module.sort(lambda x, y: cmp(self.module_o[x].ordering,
                                                  self.module_o[y].ordering))
        print self

    def __str__(self):
        print banner('run context')
        a = []
        a.append('modules:')
        for m in self.ordered_module:
            a.append(' %0.2d %s'%(self.module_o[m].ordering, m))
        a.append(self.str_ruleset())
        return '\n'.join(a)

    def format_rule_var(self, var):
        var = var.upper().replace('-', '_').replace(' ', '_').replace('.','_')
        var = '_'.join(('OSVC_COMP', var))
        return var

    def format_rule_val(self, val):
        if isinstance(val, unicode):
            val = repr(val).strip("'")
        else:
            val = str(val)
        illegal_chars = """`;$"""
        for c in illegal_chars:
            if c in val:
                print "illegal char %s in variable value: %s"%(c,val)
                return "suppressed"
        return val

    def setup_env(self):
        for rule in self.ruleset.values():
            for var, val in rule['vars']:
                os.environ[self.format_rule_var(var)] = self.format_rule_val(val)

    def get_moduleset(self):
        moduleset = xmlrpcClient.comp_get_moduleset()
        if moduleset is None:
            raise ex.excError('could not fetch moduleset')
        return moduleset

    def get_ruleset(self):
        if len(self.options.ruleset_date) > 0:
            return self.get_dated_ruleset(self.options.ruleset_date)
        return self.get_current_ruleset()

    def get_current_ruleset(self):
        ruleset = xmlrpcClient.comp_get_ruleset()
        if ruleset is None:
            raise ex.excError('could not fetch ruleset')
        return ruleset

    def get_dated_ruleset(self, date):
        ruleset = xmlrpcClient.comp_get_dated_ruleset(self.options.ruleset_date)
        if ruleset is None:
            raise ex.excError('could not fetch ruleset')
        return ruleset

    def str_ruleset(self):
        a = []
        a.append('rules:')
        for rule in self.ruleset.values():
            if len(rule['filter']) == 0:
                a.append(' %s'%rule['name'])
            else:
                a.append(' %s (%s)'%(rule['name'],rule['filter']))
            for var, val in rule['vars']:
                val = self.format_rule_val(val)
                if ' ' in val:
                    val = repr(val)
                a.append('  %s=%s'%(self.format_rule_var(var), val))
        return '\n'.join(a)

    def merge_moduleset_modules(self):
        modules = self.get_moduleset_modules(self.moduleset)
        return set(self.module + modules) - set([''])

    def get_moduleset_modules(self, m):
        moduleset = xmlrpcClient.comp_get_moduleset_modules(m)
        if moduleset is None:
            raise ex.excError('could not expand moduleset modules')
        return moduleset

    def digest_errors(self, err):
        passed = [m for m in err if err[m] == 0]
        errors = [m for m in err if err[m] == 1]
        na = [m for m in err if err[m] == 2]

        n_passed = len(passed)
        n_errors = len(errors)
        n_na = len(na)

        def _s(n):
            if n > 1:
                return 's'
            else:
                return ''

        def modules(l):
            if len(l) == 0:
                return ''
            return '\n%s'%'\n'.join(map(lambda x: ' '+x, l))

        print banner("digest")
        print "%d n/a%s"%(n_na, modules(na))
        print "%d passed%s"%(n_passed, modules(passed))
        print "%d error%s%s"%(n_errors, _s(n_errors), modules(errors))

        if len(errors) > 0:
            return 1
        return 0

    def do_show_moduleset(self):
        self.moduleset = self.get_moduleset()
        for ms in self.moduleset:
            print ms+':'
            for m in self.get_moduleset_modules(ms):
                print ' %s'%m

    def do_show_ruleset(self):
        self.ruleset = self.get_ruleset()
        self.setup_env()
        print self.str_ruleset()

    def do_run(self, action):
        err = {}
        self.init()
        start = datetime.datetime.now()
        for module in self.ordered_module:
            err[module] = getattr(self.module_o[module], action)()
        r = self.digest_errors(err)
        end = datetime.datetime.now()
        print "total duration: %s"%str(end-start)
        return r

    def do_checks(self):
        return self.do_run('check')

    def do_fix(self):
        return self.do_run('fix')

    def do_fixable(self):
        return self.do_run('fixable')

    def do_attach_moduleset(self):
        if len(self.options.moduleset) == 0:
            raise ex.excError('no moduleset specified. use --moduleset')
        err = False
        for moduleset in self.options.moduleset.split(','):
            d = xmlrpcClient.comp_attach_moduleset(moduleset)
            if not d['status']:
                err = True
            print d['msg']
        if err:
            raise ex.excError()

    def do_detach_moduleset(self):
        if len(self.options.moduleset) == 0:
            raise ex.excError('no moduleset specified. use --moduleset')
        err = False
        for moduleset in self.options.moduleset.split(','):
            d = xmlrpcClient.comp_detach_moduleset(moduleset)
            if not d['status']:
                err = True
            print d['msg']
        if err:
            raise ex.excError()

    def do_attach_ruleset(self):
        if len(self.options.ruleset) == 0:
            raise ex.excError('no ruleset specified. use --ruleset')
        err = False
        for ruleset in self.options.ruleset.split(','):
            d = xmlrpcClient.comp_attach_ruleset(ruleset)
            if not d['status']:
                err = True
            print d['msg']
        if err:
            raise ex.excError()

    def do_detach_ruleset(self):
        if len(self.options.ruleset) == 0:
            raise ex.excError('no ruleset specified. use --ruleset')
        err = False
        for ruleset in self.options.ruleset.split(','):
            d = xmlrpcClient.comp_detach_ruleset(ruleset)
            if not d['status']:
                err = True
            print d['msg']
        if err:
            raise ex.excError()

    def do_list_rulesets(self):
        if len(self.options.ruleset) == 0:
            l = xmlrpcClient.comp_list_ruleset()
        else:
            l = xmlrpcClient.comp_list_ruleset(self.options.ruleset)
        print '\n'.join(l)

    def do_list_modulesets(self):
        if len(self.options.moduleset) == 0:
            l = xmlrpcClient.comp_list_moduleset()
        else:
            l = xmlrpcClient.comp_list_moduleset(self.options.moduleset)
        if l is None:
            return
        print '\n'.join(l)


  0707010006720f000081a40000000000000000000000014d9d7e6e0000182f000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/rcStatsSunOS.py  #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2011 Christophe Varoqui <christophe.varoqui@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import os
from rcUtilities import call, which
import rcStats

class StatsProvider(rcStats.StatsProvider):
    def __init__(self, interval=2880, stats_dir=None,
                 stats_start=None, stats_end=None):
        rcStats.StatsProvider.__init__(self, interval=interval,
                                       stats_dir=stats_dir,
                                       stats_start=stats_start,
                                       stats_end=stats_end)
        cmd = ['pagesize']
        (ret, pagesize) = call(cmd)
        self.pagesize = int(pagesize)

    def sarfile(self, day):
        f = os.path.join(os.sep, 'var', 'adm', 'sa', 'sa'+day)
        if os.path.exists(f):
            return f
        return None

    def cpu(self, d, day, start, end):
        cols = ['date',
                'usr',
                'sys',
                'iowait',
                'idle',
                'cpu',
                'nodename']
        f = self.sarfile(day)
        lines = []
        if f is None:
            return cols, lines
        cmd = ['sar', '-u', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd, errlog=False)
        for line in buff.split('\n'):
            l = line.split()
            if len(l) != 5:
                continue
            if l[1] == '%usr':
                continue
            if l[0] == 'Average':
                continue
            l += ['all', self.nodename]
            l[0] = '%s %s'%(d, l[0])
            lines.append(l)
        return cols, lines

    def mem_u(self, d, day, start, end):
        cols = ['date',
                'kbmemfree',
                'nodename']
        f = self.sarfile(day)
        lines = []
        if f is None:
            return cols, lines
        cmd = ['sar', '-r', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd)
        for line in buff.split('\n'):
            l = line.split()
            if len(l) != 3:
                continue
            if l[1] == 'freemem':
                continue
            if l[0] == 'Average':
                continue

            freemem = int(l[1])*self.pagesize/1024
            x = ['%s %s'%(d, l[0]), str(freemem), self.nodename]
            lines.append(x)
        return cols, lines

    def proc(self, d, day, start, end):
        cols = ['date',
                'runq_sz',
                'nodename']
        f = self.sarfile(day)
        lines = []
        if f is None:
            return cols, lines
        cmd = ['sar', '-q', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd)
        for line in buff.split('\n'):
            l = line.split()
            if len(l) != 5:
                continue
            if l[1] == 'runq-sz':
                continue
            if l[0] == 'Average':
                continue
            x = ['%s %s'%(d, l[0]), l[1], self.nodename]
            lines.append(x)
        return cols, lines

    def swap(self, d, day, start, end):
        cols = ['date',
                'kbswpfree',
                'nodename']
        f = self.sarfile(day)
        lines = []
        if f is None:
            return cols, lines
        cmd = ['sar', '-r', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd)
        for line in buff.split('\n'):
            l = line.split()
            if len(l) != 3:
                continue
            if l[1] == 'freemem':
                continue
            if l[0] == 'Average':
                continue

            freeswap = int(l[2])/2
            x = ['%s %s'%(d, l[0]), str(freeswap), self.nodename]
            lines.append(x)
        return cols, lines

    def block(self, d, day, start, end):
        cols = ['date',
                'rbps',
                'wbps',
                'nodename']
        f = self.sarfile(day)
        lines = []
        if f is None:
            return [], []
        cmd = ['sar', '-b', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd)
        for line in buff.split('\n'):
            l = line.split()
            if len(l) != 9:
                continue
            if l[1] == 'bread/s':
                continue
            if l[0] == 'Average':
                continue
            x = ['%s %s'%(d, l[0]), l[1], l[4], self.nodename]
            lines.append(x)
        return cols, lines

    def blockdev(self, d, day, start, end):
        cols = ['date',
                'dev',
                'pct_util',
                'avgqu_sz',
                'rsecps',
                'await',
                'svctm',
                'nodename']
        f = self.sarfile(day)
        lines = []
        if f is None:
            return cols, lines
        cmd = ['sar', '-d', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd, errlog=False)
        for line in buff.split('\n'):
            l = line.split()
            if len(l) == 8:
                date = l[0]
            if len(l) == 7:
                l = [date] + l
            if len(l) != 8:
                continue
            if l[1] == 'device':
                continue
            if l[0] == 'Average':
                continue
            # 00:00:00 device %busy avque r+w/s [blks/s] avwait avserv
            x = ['%s %s'%(d, l[0]), l[1], l[2], l[3], l[4], l[6], l[7], self.nodename]
            lines.append(x)
        return cols, lines

 070701000671e4000081a40000000000000000000000014d9d7e6e0000052c000000b600010002ffffffffffffffff0000002a00000000root/opt/opensvc/lib/rcDiskInfoFreeBSD.py #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

from rcUtilities import call, which
import rcDiskInfo

class diskInfo(rcDiskInfo.diskInfo):
    disk_ids = {}

    def disk_id(self, dev):
        print "%s:disk_id TODO"%__file__
        return ""

    def disk_vendor(self, dev):
        print "%s:disk_vendor TODO"%__file__
        return ""

    def disk_model(self, dev):
        print "%s:disk_model TODO"%__file__
        return ""

    def disk_size(self, dev):
        print "%s:disk_size TODO"%__file__
        return 0

070701000671f3000081a40000000000000000000000014d9d7e6e00000501000000b600010002ffffffffffffffff0000002b00000000root/opt/opensvc/lib/rcIfconfigLinuxkvm.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcExceptions as ex
from subprocess import *

rcIfconfig = __import__("rcIfconfigLinux")
from rcGlobalEnv import rcEnv

class ifconfig(rcIfconfig.ifconfig):
    def __init__(self, hostname):
        self.intf = []
        cmd = rcEnv.rsh.split(' ') + [hostname, 'env', 'LANG=C', 'ifconfig', '-a']
        p = Popen(cmd, stdout=PIPE)
        buff = p.communicate()[0]
        if p.returncode != 0:
            raise ex.excError
        self.parse(buff)
   07070100067228000081a40000000000000000000000014d9d7e6e0000083b000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/resHbLinuxHA.py  #
# Copyright (c) 2011 Christophe Varoqui <christophe.varoqui@opensvc.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import resources as Res
from rcGlobalEnv import rcEnv
import os
import rcStatus
import rcExceptions as ex
from rcUtilities import justcall, which

class Hb(Res.Resource):
    """ HeartBeat ressource
    """
    def __init__(self, rid=None, name=None, always_on=set([]),
                 optional=False, disabled=False, tags=set([])):
        Res.Resource.__init__(self, rid, "hb.linuxha",
                              optional=optional, disabled=disabled, tags=tags)
        self.status_cmd = 'cl_status'
        self.name = name

    def process_running(self):
        cmd = [self.status_cmd, 'hbstatus']
        (out, err, ret) = justcall(cmd)
        if ret != 0:
            return False
        if not 'is running' in out:
            return False
        return True

    def __str__(self):
        return "%s" % (Res.Resource.__str__(self))

    def stop(self):
        pass

    def start(self):
        pass

    def _status(self, verbose=False):
        if not which(self.status_cmd):
            self.status_log("heartbeat is not installed")
            return rcStatus.WARN
        if not self.process_running():
            self.status_log("heartbeat daemons are not running")
            return rcStatus.WARN
        return rcStatus.NA

 07070100067266000081a40000000000000000000000014d9d7e6e00000574000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/svcVbox.py   #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import svc
import resContainerVbox as vbox
from rcGlobalEnv import rcEnv

class SvcVbox(svc.Svc):
    def __init__(self, svcname, vmname=None, guestos=None,
                 optional=False, disabled=False, tags=set([])):
        svc.Svc.__init__(self, svcname,
                         optional=optional, disabled=disabled, tags=tags)
        if vmname is None:
            vmname = svcname
        self.vmname = vmname
        self.guestos = guestos
        self += vbox.Vbox(vmname)
        self.runmethod = rcEnv.rsh.split() + [vmname]

070701000671fd000081a40000000000000000000000014d9d7e6e0000097f000000b600010002ffffffffffffffff0000002800000000root/opt/opensvc/lib/rcMountsFreeBSD.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcMounts
from rcUtilities import *
from subprocess import Popen

def get_src_dir_dev(dev):
    """Given a directory path, return its hosting device
    """
    process = Popen(['df', '-l', dev], stdout=PIPE, stderr=STDOUT, close_fds=True)
    buff = process.communicate()
    out = buff[0]
    i = out.index('/')
    return out[i:].split()[0]

class Mounts(rcMounts.Mounts):

    def match_mount(self, i, dev, mnt):
        """Given a line of 'mount' output, returns True if (dev, mnt) matches
        this line. Returns False otherwize. Also care about weirdos like loops
        and binds, ...
        """
        if os.path.isdir(dev):
            is_bind = True
            src_dir_dev = get_src_dir_dev(dev)
        else:
            is_bind = False

        if i.mnt != mnt:
            return False
        if i.dev == dev:
            return True
        if is_bind and i.dev == src_dir_dev:
            return True
        return False

    def __init__(self):
        self.mounts = []
        (ret, out) = call(['mount'])
        for l in out.split('\n'):
            words = l.split()
            if len(words) < 4:
                return
            dev = words[0]
            mnt = words[2]
            opts = ' '.join(words[3:]).strip('(').strip(')').split(', ')
            type = opts[0]
            if len(opts) < 3:
                mnt_opt = ''
            else:
                mnt_opt = ','.join(opts[2:])
            m = rcMounts.Mount(dev, mnt, type, mnt_opt)
            self.mounts.append(m)

if __name__ == "__main__" :
    help(Mounts)
    for m in Mounts():
        print m
 070701000671dc000081a40000000000000000000000014d9d7e6e000009a6000000b600010002ffffffffffffffff0000002700000000root/opt/opensvc/lib/rcAssetFreeBSD.py    #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import datetime
from rcUtilities import call, which
from rcGlobalEnv import rcEnv
import rcAssetLinux

class Asset(rcAssetLinux.Asset):
    def get_mem_bytes(self):
        cmd = ['sysctl', 'hw.realmem']
        (ret, out) = call(cmd)
        if ret != 0:
            return '0'
        lines = out.split('\n')
        if len(lines) < 1:
            return '0'
        line = lines[0].split()
        if len(line) < 2:
            return '0'
        mb = int(line[-1])
        return str(mb/1024/1024)

    def get_os_vendor(self):
        return 'FreeBSD'

    def get_os_release(self):
        return self.get_os_kernel()

    def get_os_arch(self):
        cmd = ['sysctl', 'hw.machine_arch']
        (ret, out) = call(cmd)
        if ret != 0:
            return 'Unknown'
        lines = out.split('\n')
        if len(lines) < 1:
            return 'Unknown'
        line = lines[0].split()
        if len(line) < 2:
            return 'Unknown'
        return line[-1]

    def get_cpu_model(self):
        cmd = ['sysctl', 'hw.model']
        (ret, out) = call(cmd)
        if ret != 0:
            return 'Unknown'
        lines = out.split('\n')
        if len(lines) < 1:
            return 'Unknown'
        line = lines[0].split()
        if len(line) < 2:
            return 'Unknown'
        return " ".join(line[1:])

    def get_cpu_cores(self):
        cmd = ['sysctl', 'hw.ncpu']
        (ret, out) = call(cmd)
        if ret != 0:
            return 'Unknown'
        lines = out.split('\n')
        if len(lines) < 1:
            return 'Unknown'
        line = lines[0].split()
        if len(line) < 2:
            return 'Unknown'
        return line[-1]
  07070100067233000081a40000000000000000000000014d9d7e6e000005e9000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/resIpLinuxLxc.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

resIpHv = __import__("resIpLinux")
import resIpVm

class Ip(resIpVm.Ip, resIpHv.Ip):
    def __init__(self, rid=None, ipDev=None, ipName=None,
                 mask=None, always_on=set([]),
                 disabled=False, tags=set([]), optional=False):
        resIpVm.Ip.__init__(self, rid=rid, ipDev=ipDev, ipName=ipName,
                            mask=mask, always_on=always_on,
                            disabled=disabled, tags=tags, optional=optional)

    def check_ping(self):
        return resIpHv.Ip.check_ping(self)


if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

   07070100067241000081a40000000000000000000000014d9d7e6e000020a1000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/resMountLinux.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import os

import rcMountsLinux as rcMounts
import resMount as Res
from rcUtilities import qcall, protected_mount, getmount
from rcUtilitiesLinux import major, get_blockdev_sd_slaves, lv_exists
from rcGlobalEnv import rcEnv
import rcExceptions as ex
from stat import *

def try_umount(self):
    cmd = ['umount', self.mountPoint]
    (ret, out) = self.vcall(cmd, err_to_warn=True)
    if ret == 0:
        return 0

    """ don't try to kill process using the source of a 
        protected bind mount
    """
    if protected_mount(self.mountPoint):
        return 1

    """ best effort kill of all processes that might block
        the umount operation. The priority is given to mass
        action reliability, ie don't contest oprator's will
    """
    cmd = ['sync']
    (ret, out) = self.vcall(cmd)

    for i in range(4):
        cmd = ['fuser', '-kmv', self.mountPoint]
        (ret, out) = self.vcall(cmd, err_to_info=True)
        self.log.info('umount %s'%self.mountPoint)
        cmd = ['umount', self.mountPoint]
        ret = qcall(cmd)
        if ret == 0:
            break

    return ret


class Mount(Res.Mount):
    """ define Linux mount/umount doAction """
    def __init__(self, rid, mountPoint, device, fsType, mntOpt, always_on=set([]),
                 snap_size=None, disabled=False, tags=set([]), optional=False):
        self.Mounts = None
        Res.Mount.__init__(self, rid, mountPoint, device, fsType, mntOpt,
                           snap_size, always_on,
                           disabled=disabled, tags=tags, optional=optional)
        self.fsck_h = {
            'ext2': {'bin': 'e2fsck', 'cmd': ['e2fsck', '-p', self.device]},
            'ext3': {'bin': 'e2fsck', 'cmd': ['e2fsck', '-p', self.device]},
            'ext4': {'bin': 'e2fsck', 'cmd': ['e2fsck', '-p', self.device]},
        }

    def is_up(self):
        self.Mounts = rcMounts.Mounts()
        return self.Mounts.has_mount(self.device, self.mountPoint)

    def realdev(self):
        try:
            mode = os.stat(self.device)[ST_MODE]
        except:
            self.log.debug("can not stat %s" % self.device)
            return None
        if S_ISBLK(mode):
            dev = self.device
        else:
            mnt = getmount(self.device)
            if self.Mounts is None:
                self.Mounts = rcMounts.Mounts()
            m = self.Mounts.has_param("mnt", mnt)
            if m is None:
                self.log.debug("can't find dev %(dev)s mounted in %(mnt)s in mnttab"%dict(mnt=mnt, dev=self.device))
                return None
            dev = m.dev

        return dev

    def mplist(self):
        dev = self.realdev()
        if dev is None:
            return set([])

        try:
            self.dm_major = major('device-mapper')
        except:
            return set([])

        return self._mplist([dev])

    def devname_to_dev(self, x):
        if 'cciss!' in x:
            return '/dev/cciss/'+x.replace('cciss!', '')
        return '/dev/'+x

    def _mplist(self, devs):
        mps = set([])
        for dev in devs:
            devmap = False
            if 'dm-' in dev:
                minor = int(dev.replace('/dev/dm-', ''))
                dm = dev.replace('/dev/', '')
                devmap = True
            else:
                try:
                    statinfo = os.stat(dev)
                except:
                    self.log.warning("can not stat %s" % dev)
                    continue
                minor = os.minor(statinfo.st_rdev)
                dm = 'dm-%i'%minor
                devmap = self.is_devmap(statinfo)

            if self.is_multipath(minor):
                mps |= set([dev])
            elif devmap:
                syspath = '/sys/block/' + dm + '/slaves'
                slaves = os.listdir(syspath)
                mps |= self._mplist(map(self.devname_to_dev, slaves))
        return mps

    def is_multipath(self, minor):
        cmd = ['dmsetup', '-j', str(self.dm_major),
                          '-m', str(minor),
                          'table'
              ]
        (ret, buff) = self.call(cmd, errlog=False, cache=True)
        if ret != 0:
            return False
        l = buff.split()
        if len(l) < 3:
            return False
        if l[2] != 'multipath':
            return False
        if 'queue_if_no_path' not in l:
            return False
        cmd = ['dmsetup', '-j', str(self.dm_major),
                          '-m', str(minor),
                          'status'
              ]
        (ret, buff) = self.call(cmd, errlog=False, cache=True)
        if ret != 0:
            return False
        l = buff.split()
        if l.count('A') > 1:
            return False
        return True

    def is_devmap(self, statinfo):
        if os.major(statinfo.st_rdev) == self.dm_major:
            return True
        return False

    def disklist(self):
        dev = self.realdev()
        if dev is None:
            return set([])

        try:
            self.dm_major = major('device-mapper')
        except:
            return set([dev])

        try:
            statinfo = os.stat(dev)
        except:
            self.log.error("can not stat %s" % dev)
            raise ex.excError

        if not self.is_devmap(statinfo):
            return set([dev])

        if lv_exists(self, dev):
            """ if the fs is built on a lv of a private vg, its
                disks will be given by the vg resource.
                if the fs is built on a lv of a shared vg, we
                don't want to account its disks : don't reserve
                them, don't account their size multiple times.
            """
            return set([])

        dm = 'dm-' + str(os.minor(statinfo.st_rdev))
        syspath = '/sys/block/' + dm + '/slaves'
        devs = get_blockdev_sd_slaves(syspath)
        return devs

    def can_check_writable(self):
        if len(self.mplist()) > 0:
            self.log.debug("a multipath under fs has queueing enabled and no active path")
            return False
        return True

    def start(self):
        if self.Mounts is None:
            self.Mounts = rcMounts.Mounts()
        Res.Mount.start(self)
        if self.is_up() is True:
            self.log.info("fs(%s %s) is already mounted"%
                (self.device, self.mountPoint))
            return 0
        self.fsck()
        if not os.path.exists(self.mountPoint):
            os.makedirs(self.mountPoint, 0755)
        if self.fsType != "":
            fstype = ['-t', self.fsType]
        else:
            fstype = []
        if self.mntOpt != "":
            mntopt = ['-o', self.mntOpt]
        else:
            mntopt = []
        cmd = ['mount']+fstype+mntopt+[self.device, self.mountPoint]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError
        self.Mounts = None

    def stop(self):
        if self.Mounts is None:
            self.Mounts = rcMounts.Mounts()
        if self.is_up() is False:
            self.log.info("fs(%s %s) is already umounted"%
                    (self.device, self.mountPoint))
            return
        for i in range(3):
            ret = try_umount(self)
            if ret == 0: break
        if ret != 0:
            self.log.error('failed to umount %s'%self.mountPoint)
            raise ex.excError
        self.Mounts = None

if __name__ == "__main__":
    for c in (Mount,) :
        help(c)

   0707010006720d000081a40000000000000000000000014d9d7e6e00001dea000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/rcStatsHP-UX.py  #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2011 Christophe Varoqui <christophe.varoqui@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import os
from rcUtilities import call
from rcGlobalEnv import rcEnv
import rcStats

class StatsProvider(rcStats.StatsProvider):
    def glancefile(self, day):
        f = os.path.join(rcEnv.pathvar, 'glance'+day)
        if os.path.exists(f):
            return f
        return None

    def cpu(self, d, day, start, end):
        f = self.glancefile(day)
        if f is None:
            return [], []
        cols = ['date',
                'cpu',
                'usr',
                'nice',
                'sys',
                'iowait',
                'steal',
                'irq',
                'soft',
                'guest',
                'idle',
                'nodename']
        lines = []
        with open(f, 'r') as file:
            for line in file:
                l = line.split()
                if len(l) != 24:
                    continue
                """ hpux:            usr nice sys irq wait idle
                                     1   2    3   4   5    6
                    xmlrpc: date cpu usr nice sys iowait steal irq soft guest idle nodename
                """
                ts = '%s %s'%(d, l[0])
                ts = ts.replace('\0','')
                x = [ts,
                     'all',
                     l[1],
                     l[2],
                     l[3],
                     l[5],
                     '0',
                     l[4],
                     '0',
                     '0',
                     l[6],
                     self.nodename]
                lines.append(x)
            return cols, lines

    def mem_u(self, d, day, start, end):
        f = self.glancefile(day)
        if f is None:
            return [], []
        cols = ['date',
                'kbmemfree',
                'kbmemused',
                'pct_memused',
                'kbbuffers',
                'kbcached',
                'kbcommit',
                'pct_commit',
                'kbmemsys',
                'nodename']
        lines = []
        with open(f, 'r') as file:
            for line in file:
                l = line.split()
                if len(l) != 24:
                    continue
                """ hpux:            phys kbmemfree kbcached kbfilecached kbsys kbuser kbswapused kbswap
                                     7    8         9        10           11    12     13         14
                    xmlrpc: date kbmemfree kbmemused pct_memused kbbuffers kbcached kbcommit pct_commit kbmemsys nodename
                """
                phys = int(l[7])
                free = int(l[8])
                swapused = int(l[13])
                swap = int(l[14])
                used = phys - free
                commit = used + swapused
                vm = phys + swap
                if vm == 0 or phys == 0:
                    continue
                pct_commit = 100 * commit / vm
                pct_used = 100 * used / phys

                ts = '%s %s'%(d, l[0])
                ts = ts.replace('\0','')
                x = [ts,
                     l[8],
                     str(used),
                     str(pct_used),
                     l[9],
                     l[10],
                     str(commit),
                     str(pct_commit),
                     l[11],
                     self.nodename]
                lines.append(x)
        return cols, lines

    def proc(self, d, day, start, end):
        f = self.glancefile(day)
        if f is None:
            return [], []
        cols = ['date',
                'runq_sz',
                'plist_sz',
                'ldavg_1',
                'ldavg_5',
                'ldavg_15',
                'nodename']
        lines = []
        with open(f, 'r') as file:
            for line in file.readlines():
                l = line.split()
                if len(l) != 24:
                    continue
                """ hpux:            GBL_LOADAVG GBL_LOADAVG5 GBL_LOADAVG15 GBL_CPU_QUEUE TBL_PROC_TABLE_USED
                                     15          16           17            18            19
                    xmlrpc: date runq_sz plist_sz ldavg_1 ldavg_5 ldavg_15 nodename
                """
                ts = '%s %s'%(d, l[0])
                ts = ts.replace('\0','')
                x = [ts,
                     l[18],
                     l[19],
                     l[15],
                     l[16],
                     l[17],
                     self.nodename]
                lines.append(x)
        return cols, lines

    def swap(self, d, day, start, end):
        f = self.glancefile(day)
        if f is None:
            return [], []
        lines = []
        cols = ['date',
                'kbswpfree',
                'kbswpused',
                'pct_swpused',
                'kbswpcad',
                'pct_swpcad',
                'nodename']

        with open(f, 'r') as file:
            for line in file.readlines():
                l = line.split()
                if len(l) != 24:
                    continue
                """ hpux:        kbswapused kbswap
                                 13         14
                    xmlrpc: date kbswpfree kbswpused pct_swpused kbswpcad pct_swpcad nodename
                """
                swapused = int(l[13])
                swap = int(l[14])
                swapfree = swap - swapused

                ts = '%s %s'%(d, l[0])
                ts = ts.replace('\0','')
                x = [ts,
                     str(swapfree),
                     l[13],
                     str(100 * swapused / swap),
                     '0',
                     '0',
                     self.nodename]
                lines.append(x)
        return cols, lines

    def block(self, d, day, start, end):
        f = self.glancefile(day)
        if f is None:
            return [], []
        cols = ['date',
                'tps',
                'rtps',
                'wtps',
                'rbps',
                'wbps',
                'nodename']

        lines = []
        with open(f, 'r') as file:
            for line in file.readlines():
                l = line.split()
                if len(l) != 24:
                    continue
                """ hpux:        rio wio rkb wkb
                                 20  21  22  23
                    xmlrpc: date tps rtps wtps rbps wbps nodename
                """
                tps = float(l[20]) + float(l[21])
                ts = '%s %s'%(d, l[0])
                ts = ts.replace('\0','')
                x = [ts,
                     str(tps),
                     l[20],
                     l[21],
                     l[22],
                     l[23],
                     self.nodename]
                lines.append(x)
        return cols, lines

  0707010006720b000081a40000000000000000000000014d9d7e6e00001558000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/rcStatsDarwin.py #!/usr/bin/python2.6
#
# Copyright (c) 2011 Christophe Varoqui <christophe.varoqui@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import os
from rcUtilities import call, which
from rcGlobalEnv import rcEnv
import rcStats

class StatsProvider(rcStats.StatsProvider):
    def customfile(self, metric, day):
        f = os.path.join(rcEnv.pathvar, 'stats', metric+day)
        if os.path.exists(f):
            return f
        return None

    def cpu(self, d, day, start, end):
        cols = ['date',
                'cpu',
                'usr',
                'nice',
                'sys',
                'idle',
                'nodename']
        f = self.sarfile(day)
        lines = []
        if f is None:
            return cols, lines
        cmd = ['sar', '-u', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd, errlog=False)
        for line in buff.split('\n'):
            l = line.split()
            if len(l) != 5:
                continue
            if l[1] == '%usr':
                continue
            if l[0] == 'Average:':
                continue
            (time, usr, nice, sys, idle) = l
            l = ['%s %s'%(d, time), 'all', usr, nice, sys, idle, self.nodename]
            lines.append(l)
        return cols, lines

    def mem_u(self, d, day, start, end):
        cols = ['date',
                'kbmemfree',
                'kbmemused',
                'kbbuffers',
                'kbcached',
                'kbmemsys',
                'nodename']
        fname = self.customfile('mem_u', day)
        lines = []
        if fname is None:
            return cols, lines
        try:
            f = open(fname, 'r')
            buff = f.read()
            f.close()
        except:
            return cols, lines
        for line in buff.split('\n'):
            l = line.split()
            if len(l) != 6:
                continue
            (time, free, inactive, active, speculative, wired) = l
            l = ['%s %s'%(d, time), free, active, speculative, inactive, wired, self.nodename]
            lines.append(l)
        return cols, lines

    def blockdev(self, d, day, start, end):
        cols = ['date',
                'dev',
                'tps',
                'rsecps',
                'nodename']
        f = self.sarfile(day)
        lines = []
        if f is None:
            return cols, lines
        cmd = ['sar', '-d', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd, errlog=False)
        for line in buff.split('\n'):
           l = line.split()
           if len(l) != 4:
               continue
           if l[1] == 'device':
               continue
           if l[1] == 'Disk:':
               continue
           if l[0] == 'Average:':
               continue
           l.append(self.nodename)
           l[0] = '%s %s'%(d, l[0])
           lines.append(l)
        return cols, lines

    def netdev(self, d, day, start, end):
        cols = ['date',
                'dev',
                'rxpckps',
                'rxkBps',
                'txpckps',
                'txkBps',
                'nodename']

        f = self.sarfile(day)
        lines = []
        if f is None:
            return cols, lines
        cmd = ['sar', '-n', 'DEV', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd, errlog=False)
        for line in buff.split('\n'):
           l = line.split()
           if len(l) != 6:
               continue
           if l[1] in ['IFACE', 'lo0'] :
               continue
           if 'dummy' in l[1] or 'vnet' in l[1] or 'veth' in l[1] or \
              'gif'   in l[1] or 'stf'  in l[1]:
               continue
           if l[0] == 'Average:':
               continue
           l.append(self.nodename)
           l[0] = '%s %s'%(d, l[0])
           lines.append(l)
        return cols, lines


    def netdev_err(self, d, day, start, end):
        cols = ['date',
                'dev',
                'rxerrps',
                'txerrps',
                'collps',
                'rxdropps',
                'nodename']
        f = self.sarfile(day)
        lines = []
        if f is None:
            return cols, lines
        cmd = ['sar', '-n', 'EDEV', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd, errlog=False)
        for line in buff.split('\n'):
           l = line.split()
           if len(l) != 6:
               continue
           if l[1] in ['IFACE', 'lo0'] :
               continue
           if 'dummy' in l[1] or 'vnet' in l[1] or 'veth' in l[1] or \
              'gif'   in l[1] or 'stf'  in l[1]:
               continue
           if l[0] == 'Average:':
               continue
           l.append(self.nodename)
           l[0] = '%s %s'%(d, l[0])
           lines.append(l)
        return cols, lines


07070100067265000081a40000000000000000000000014d9d7e6e000008ac000000b600010002ffffffffffffffff0000001f00000000root/opt/opensvc/lib/svcLxc.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import svc
import resContainerLxc as lxc
import rcStatus
from rcGlobalEnv import rcEnv
from rcUtilities import which
import os

class SvcLxc(svc.Svc):
    """ Define Lxc services"""

    def __init__(self, svcname, vmname=None, guestos=None, optional=False, disabled=False, tags=set([])):
        svc.Svc.__init__(self, svcname, optional=optional, disabled=disabled, tags=tags)
        if vmname is None:
            vmname = svcname
        self.vmname = vmname
        self.guestos = guestos
        self += lxc.Lxc(vmname)
        if which('lxc-attach') and os.path.exists('/proc/1/ns'):
            self.runmethod = ['lxc-attach', '-n', vmname, '--']
        else:
            self.runmethod = rcEnv.rsh.split() + [vmname]



if __name__ == "__main__":
    for c in (SvcLxc,) :
        help(c)
    import mountLinux as mount
    import ipLinux as ip
    print """
    Z=SvcLxc()
    Z+=mount.Mount("/mnt1","/dev/sda")
    Z+=mount.Mount("/mnt2","/dev/sdb")
    Z+=ip.Ip("eth0","192.168.0.173")
    Z+=ip.Ip("eth0","192.168.0.174")
    """

    Z=SvcLxc()
    Z+=mount.Mount("/mnt1","/dev/sda")
    Z+=mount.Mount("/mnt2","/dev/sdb")
    Z+=ip.Ip("eth0","192.168.0.173")
    Z+=ip.Ip("eth0","192.168.0.174")

    print "Show Z: ", Z
    print "start Z:"
    Z.start()

    print "stop Z:"
    Z.stop()

07070100067210000081a40000000000000000000000014d9d7e6e000016c3000000b600010002ffffffffffffffff0000002100000000root/opt/opensvc/lib/rcStatus.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os

UP = 0
DOWN = 1
WARN = 2
NA = 3
TODO = 4
UNDEF = 5
STDBY_UP = 6
STDBY_DOWN = 7
STDBY_UP_WITH_UP = 8
STDBY_UP_WITH_DOWN = 9

GREEN = 32
RED = 31
YELLOW = 33

def colorize(color, text):
    #if os.isatty(1):
    #    return '\033['+str(color)+'m'+text+'\033[m'
    #else:
    return text

_status_value = {
    'up': UP,
    'down': DOWN,
    'warn': WARN,
    'n/a': NA,
    'na': NA,
    'todo': TODO,
    'undef': UNDEF,
    'stdby up': STDBY_UP,
    'stdby down': STDBY_DOWN,
}

_status_str = {
    UP: colorize(GREEN, 'up'),
    DOWN: colorize(RED, 'down'),
    WARN: colorize(YELLOW, 'warn'),
    NA: 'n/a',
    TODO: 'todo',
    UNDEF: 'undef',
    STDBY_UP: 'stdby up',
    STDBY_DOWN: 'stdby down',
    STDBY_UP_WITH_UP: 'up',
    STDBY_UP_WITH_DOWN: 'stdby up',
}

def status_value(str):
    if str not in _status_value.keys():
        return None
    return _status_value[str.lower()]

def status_str(val):
    if val not in _status_str.keys():
        return None
    return _status_str[val]

def _merge(s1, s2):
    """Merge too status: WARN and TODO taint UP and DOWN
    """
    if s1 not in _status_str:
        raise Exception("left member has unsupported value: %s"%str(s1))
    if s2 not in _status_str:
        raise Exception("right member has unsupported value: %s"%str(s2))

    if s1 == UNDEF: return s2
    if s2 == UNDEF: return s1
    setstate = set([s1, s2])
    if setstate == set([ UP, UP ]): return UP
    if setstate == set([ UP, DOWN ]): return WARN
    if setstate == set([ UP, WARN ]): return WARN
    if setstate == set([ UP, NA ]): return UP
    if setstate == set([ UP, TODO ]): return WARN
    if setstate == set([ UP, STDBY_UP ]): return STDBY_UP_WITH_UP
    if setstate == set([ UP, STDBY_DOWN ]): return WARN
    if setstate == set([ UP, STDBY_UP_WITH_UP ]): return STDBY_UP_WITH_UP
    if setstate == set([ UP, STDBY_UP_WITH_DOWN ]): return WARN
    if setstate == set([ DOWN, DOWN ]): return DOWN
    if setstate == set([ DOWN, WARN ]): return WARN
    if setstate == set([ DOWN, NA ]): return DOWN
    if setstate == set([ DOWN, TODO ]): return WARN
    if setstate == set([ DOWN, STDBY_UP ]): return STDBY_UP_WITH_DOWN
    if setstate == set([ DOWN, STDBY_DOWN ]): return WARN
    if setstate == set([ DOWN, STDBY_UP_WITH_UP ]): return WARN
    if setstate == set([ DOWN, STDBY_UP_WITH_DOWN ]): return STDBY_UP_WITH_DOWN
    if setstate == set([ WARN, WARN ]): return WARN
    if setstate == set([ WARN, NA ]): return WARN
    if setstate == set([ WARN, TODO ]): return WARN
    if setstate == set([ WARN, STDBY_UP ]): return WARN
    if setstate == set([ WARN, STDBY_DOWN ]): return WARN
    if setstate == set([ WARN, STDBY_UP_WITH_UP ]): return WARN
    if setstate == set([ WARN, STDBY_UP_WITH_DOWN ]): return WARN
    if setstate == set([ NA, NA ] ): return NA
    if setstate == set([ NA, TODO ]): return WARN
    if setstate == set([ NA, STDBY_UP ]): return STDBY_UP
    if setstate == set([ NA, STDBY_DOWN ]): return STDBY_DOWN
    if setstate == set([ NA, STDBY_UP_WITH_UP ]): return STDBY_UP_WITH_UP
    if setstate == set([ NA, STDBY_UP_WITH_DOWN ]): return STDBY_UP_WITH_DOWN
    if setstate == set([ TODO, TODO ]): return TODO
    if setstate == set([ TODO, STDBY_UP ]): return TODO
    if setstate == set([ TODO, STDBY_DOWN ]): return TODO
    if setstate == set([ TODO, STDBY_UP_WITH_UP ]): return TODO
    if setstate == set([ TODO, STDBY_UP_WITH_DOWN ]): return TODO
    if setstate == set([ STDBY_UP, STDBY_UP ]): return STDBY_UP
    if setstate == set([ STDBY_UP, STDBY_DOWN ]): return WARN
    if setstate == set([ STDBY_UP, STDBY_UP_WITH_UP ]): return STDBY_UP_WITH_UP
    if setstate == set([ STDBY_UP, STDBY_UP_WITH_DOWN ]): return STDBY_UP_WITH_DOWN
    if setstate == set([ STDBY_DOWN, STDBY_DOWN ]): return WARN
    if setstate == set([ STDBY_DOWN, STDBY_DOWN ]): return WARN
    if setstate == set([ STDBY_DOWN, STDBY_UP_WITH_UP ]): return WARN
    if setstate == set([ STDBY_DOWN, STDBY_UP_WITH_DOWN ]): return WARN
    if setstate == set([ STDBY_UP_WITH_UP, STDBY_UP_WITH_DOWN ]): return WARN
    if setstate == set([ STDBY_UP_WITH_UP, STDBY_UP_WITH_UP ]): return STDBY_UP_WITH_UP
    if setstate == set([ STDBY_UP_WITH_DOWN, STDBY_UP_WITH_DOWN ]): return STDBY_UP_WITH_DOWN
    raise Exception("some member has unsupported value: %s , %s "%(str(s1),str(s2)) )

class Status(object):
    """Class that wraps printing and calculation of resource status
    """
    def reset(self):
        self.status = UNDEF

    def __add__(self, s):
        self.status = _merge(self.status, s.status)
        return self

    def __iadd__(self, s):
        """Merge a status with current global status
        """
        if isinstance(s, Status):
            self.status = _merge(self.status, s.status)
        else:
            self.status = _merge(self.status, s)
        return self

    def __str__(self):
        return status_str(self.status)

    def __init__(self, initial_status=UNDEF):
        self.status = initial_status
 0707010006722a000081a40000000000000000000000014d9d7e6e00001ca5000000b600010002ffffffffffffffff0000001e00000000root/opt/opensvc/lib/resIp.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import resources as Res
from rcGlobalEnv import *

from rcUtilities import qcall, which
rcIfconfig = __import__('rcIfconfig'+rcEnv.sysname)
import socket
import rcStatus
import rcExceptions as ex
import os

class Ip(Res.Resource):
    """ basic ip resource
    """
    def __init__(self, rid=None, ipDev=None, ipName=None, mask=None,
                 optional=False, disabled=False, tags=set([]), always_on=set([])):
        Res.Resource.__init__(self, rid, "ip", optional=optional, disabled=disabled, tags=tags)
        self.ipDev=ipDev
        self.ipName=ipName
        self.mask=mask
        self.label = ipName + '@' + ipDev
        self.always_on = always_on

    def getaddr(self):
        if hasattr(self, 'addr'):
            return
        try:
            a = socket.getaddrinfo(self.ipName, None)
            if len(a) == 0:
                raise Exception
            self.addr = a[0][4][0]
        except:
            if not self.disabled:
                self.log.error("could not resolve name %s"%self.ipName)
                raise ex.excError

    def __str__(self):
        return "%s ipdev=%s ipname=%s" % (Res.Resource.__str__(self),\
                                         self.ipDev, self.ipName)
    def setup_environ(self):
        os.environ['OPENSVC_IPDEV'] = str(self.ipDev)
        os.environ['OPENSVC_IPNAME'] = str(self.ipName)
        os.environ['OPENSVC_MASK'] = str(self.mask)
        try:
            self.getaddr()
            os.environ['OPENSVC_IPADDR'] = str(self.addr)
        except:
            pass
        l = self.rid.split('#')
        if len(l) == 2:
            index = l[1]
        else:
            index = ''
        var = 'OPENSVC_IP'+index
        val = ' '.join((str(self.ipName), str(self.ipDev), str(self.addr),
                        str(self.mask)))
        os.environ[var] = val

    def _status(self, verbose=False):
        try:
            self.getaddr()
        except:
            self.status_log("could not resolve %s to an ip address"%self.ipName)
            return rcStatus.WARN
        try:
            if self.is_up():
                return self.status_stdby(rcStatus.UP)
            else:
                return self.status_stdby(rcStatus.DOWN)
        except ex.excNotSupported:
            self.status_log("not supported")
            return rcStatus.UNDEF

    def arp_announce(self):
        if ':' in self.addr:
            return
        if not which("arping"):
            self.log.warning("arp annouce skipped. install 'arping'")
            return
        cmd = ["arping", "-U", "-c", "1", "-I", self.ipDev, "-s", self.addr, "0.0.0.0"]
        self.log.info(' '.join(cmd))
        qcall(cmd)

    def check_ping(self):
        raise ex.MissImpl('check_ping')

    def startip_cmd(self):
        raise ex.MissImpl('startip_cmd')

    def stopip_cmd(self):
        raise ex.MissImpl('stopip_cmd')

    def is_up(self):
        ifconfig = rcIfconfig.ifconfig()
        if ifconfig.has_param("ipaddr", self.addr) is not None or \
           ifconfig.has_param("ip6addr", self.addr) is not None:
            self.log.debug("%s@%s is up" % (self.addr, self.ipDev))
            return True
        self.log.debug("%s@%s is down" % (self.addr, self.ipDev))
        return False

    def allow_start(self):
        ifconfig = rcIfconfig.ifconfig()
        intf = ifconfig.interface(self.ipDev)
        if intf is None or not intf.flag_up:
            self.log.error("Interface %s is not up. Cannot stack over it." % self.ipDev)
            raise ex.IpDevDown(self.ipDev)
        if self.is_up() is True:
            self.log.info("%s is already up on %s" % (self.addr, self.ipDev))
            raise ex.IpAlreadyUp(self.addr)
        if self.check_ping():
            self.log.error("%s is already up on another host" % (self.addr))
            raise ex.IpConflict(self.addr)
        return

    def startstandby(self):
        if rcEnv.nodename in self.always_on:
             self.start()

    def start(self):
        try:
            self.getaddr()
        except:
            self.log.error("could not resolve %s to an ip address"%self.ipName)
            raise ex.excError
        try:
            self.allow_start()
        except (ex.IpConflict, ex.IpDevDown):
            raise ex.excError
        except ex.IpAlreadyUp:
            return
        self.log.debug('pre-checks passed')

        ifconfig = rcIfconfig.ifconfig()
        if self.mask is None:
            self.mask = ifconfig.interface(self.ipDev).mask
        if self.mask == '':
            self.log.error("No netmask set on parent interface %s" % self.ipDev)
            raise ex.excError
        elif isinstance(self.mask, list):
            if len(self.mask) > 0:
                self.mask = self.mask[0]
            else:
                self.log.error("No netmask set on parent interface %s" % self.ipDev)
                raise ex.excError
        self.stacked_dev = ifconfig.get_stacked_dev(self.ipDev,\
                                                    self.addr,\
                                                    self.log)
        (ret, out) = self.startip_cmd()
        if ret != 0:
            self.log.error("failed")
            raise ex.excError

        self.arp_announce()

    def stop(self):
        try:
            self.getaddr()
        except:
            self.log.error("could not resolve %s to an ip address"%self.ipName)
            raise ex.excError
        if self.is_up() is False:
            self.log.info("%s is already down on %s" % (self.addr, self.ipDev))
            return
        ifconfig = rcIfconfig.ifconfig()
        self.stacked_dev = ifconfig.get_stacked_dev(self.ipDev,\
                                                    self.addr,\
                                                    self.log)
        (ret, out) = self.stopip_cmd()
        if ret != 0:
            self.log.error("failed")
            raise ex.excError

        import time
        tmo = 10
        for i in range(tmo):
            if not self.check_ping():
                break
            time.sleep(1)

        if i == tmo-1:
            self.log.error("%s refuse to go down"%self.addr)
            raise ex.excError


if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

    print """i1=Ip("eth0","192.168.0.173")"""
    i=Ip("eth0","192.168.0.173")
    print "show i", i
    print """i.do_action("start")"""
    i.do_action("start")

   070701000671d2000081a40000000000000000000000014d9d7e6e00000378000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/hostidDarwin.py  #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from uuid import getnode

def hostid():
    return str(getnode())
07070100067217000081a40000000000000000000000014d9d7e6e000009fa000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/lib/rcUtilitiesLinux.py  import os
import re
from rcUtilities import call, qcall

def major(driver):
    path = os.path.join(os.path.sep, 'proc', 'devices')
    try:
        f = open(path)
    except:
        raise
    for line in f.readlines():
        words = line.split()
        if len(words) == 2 and words[1] == driver:
            f.close()
            return int(words[0])
    f.close()
    raise

def get_blockdev_sd_slaves(syspath):
    slaves = set()
    for s in os.listdir(syspath):
        if re.match('^sd[a-z]*', s) is not None:
            slaves.add('/dev/' + s)
            continue
        deeper = os.path.join(syspath, s, 'slaves')
        if os.path.isdir(deeper):
            slaves |= get_blockdev_sd_slaves(deeper)
    return slaves

def check_ping(addr, timeout=5, count=1):
    if ':' in addr:
        ping = 'ping6'
    else:
        ping = 'ping'
    cmd = [ping, '-c', repr(count),
                 '-W', repr(timeout),
                 '-w', repr(timeout),
                 addr]
    (ret, out) = call(cmd)
    if ret == 0:
        return True
    return False

def lv_exists(self, device):
    if qcall(['lvs', device]) == 0:
        return True
    return False

def lv_info(self, device):
    (ret, buff) = self.call(['lvs', '-o', 'vg_name,lv_name,lv_size', '--noheadings', '--units', 'm', device])
    if ret != 0:
        return (None, None, None)
    info = buff.split()
    if 'M' in info[2]:
        lv_size = float(info[2].split('M')[0])
    elif 'm' in info[2]:
        lv_size = float(info[2].split('m')[0])
    else:
        self.log.error("%s output does not have the expected unit (m or M)"%' '.join(cmd))
        ex.excError
    return (info[0], info[1], lv_size)

def devs_to_disks(self, devs=set([])):
    """ If PV is a device map, replace by its sysfs name (dm-*)
        If device map has slaves, replace by its slaves
    """
    disks = set()
    dm_major = major('device-mapper')
    try: lo_major = major('loop')
    except: lo_major = 0
    for dev in devs:
        try:
            statinfo = os.stat(dev)
        except:
            self.log.error("can not stat %s" % dev)
            raise
        if os.major(statinfo.st_rdev) == dm_major:
            dm = 'dm-' + str(os.minor(statinfo.st_rdev))
            syspath = '/sys/block/' + dm + '/slaves'
            disks |= get_blockdev_sd_slaves(syspath)
        elif lo_major != 0 and os.major(statinfo.st_rdev) == lo_major:
            self.log.debug("skip loop device %s from disklist"%dev)
            pass
        else:
            disks.add(dev)
    return disks

  0707010006723f000081a40000000000000000000000014d9d7e6e00001597000000b600010002ffffffffffffffff0000002800000000root/opt/opensvc/lib/resMountFreeBSD.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import os

import rcMountsFreeBSD as rcMounts
import resMount as Res
from rcUtilities import qcall, protected_mount, getmount
from rcGlobalEnv import rcEnv
import rcExceptions as ex
from stat import *

def try_umount(self):
    cmd = ['umount', self.mountPoint]
    (ret, out) = self.vcall(cmd, err_to_warn=True)
    if ret == 0:
        return 0

    """ don't try to kill process using the source of a 
        protected bind mount
    """
    if protected_mount(self.mountPoint):
        return 1

    """ best effort kill of all processes that might block
        the umount operation. The priority is given to mass
        action reliability, ie don't contest oprator's will
    """
    cmd = ['sync']
    (ret, out) = self.vcall(cmd)

    for i in range(4):
        nb_killed = self.killfuser(self.mountPoint)
        self.log.info('umount %s'%self.mountPoint)
        cmd = ['umount', self.mountPoint]
        ret = qcall(cmd)
        if ret == 0 or nb_killed == 0:
            break

    if ret != 0:
        self.log.info("no more process using %s, yet umount fails. try forced umount."%self.mountPoint)
        cmd = ['umount', '-f', self.mountPoint]
        (ret, out) = self.vcall(cmd)

    return ret


class Mount(Res.Mount):
    """ define FreeBSD mount/umount doAction """
    def __init__(self, rid, mountPoint, device, fsType, mntOpt,
                 snap_size=None, always_on=set([]),
                 disabled=False, tags=set([]), optional=False):
        self.Mounts = None
        Res.Mount.__init__(self, rid, mountPoint, device, fsType, mntOpt,
                           snap_size, always_on,
                           disabled=disabled, tags=tags, optional=optional)
        self.fsck_h = {
            'ufs': {'bin': 'fsck', 'cmd': ['fsck', '-t', 'ufs', '-p', self.device]},
        }

    def killfuser(self, dir):
        cmd = ['fuser', '-kmc', dir]
        (ret, out) = self.vcall(cmd, err_to_info=True)

        """ return the number of process we sent signal to
        """
        l = out.split(':')
        if len(l) < 2:
            return 0
        return len(l[1].split())

    def is_up(self):
        self.Mounts = rcMounts.Mounts()
        return self.Mounts.has_mount(self.device, self.mountPoint)

    def realdev(self):
        dev = None
        try:
            mode = os.stat(self.device)[ST_MODE]
        except:
            self.log.debug("can not stat %s" % self.device)
            return None
        if S_ISCHR(mode):
            dev = self.device
        else:
            mnt = getmount(self.device)
            if self.Mounts is None:
                self.Mounts = rcMounts.Mounts()
            m = self.Mounts.has_param("mnt", mnt)
            if m is None:
                self.log.debug("can't find dev %(dev)s mounted in %(mnt)s in mnttab"%dict(mnt=mnt, dev=self.device))
                return None
            dev = m.dev

        return dev

    def disklist(self):
        dev = self.realdev()
        if dev is None:
            return set([])

        try:
            statinfo = os.stat(dev)
        except:
            self.log.error("can not stat %s" % dev)
            raise ex.excError

        return set([dev])

    def can_check_writable(self):
        return True

    def start(self):
        if self.Mounts is None:
            self.Mounts = rcMounts.Mounts()
        Res.Mount.start(self)
        if self.is_up() is True:
            self.log.info("fs(%s %s) is already mounted"%
                (self.device, self.mountPoint))
            return 0
        self.fsck()
        if not os.path.exists(self.mountPoint):
            os.makedirs(self.mountPoint, 0755)
        if self.fsType != "":
            fstype = ['-t', self.fsType]
        else:
            fstype = []
        if self.mntOpt != "":
            mntopt = ['-o', self.mntOpt]
        else:
            mntopt = []
        cmd = ['mount']+fstype+mntopt+[self.device, self.mountPoint]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError
        self.Mounts = None

    def stop(self):
        if self.Mounts is None:
            self.Mounts = rcMounts.Mounts()
        if self.is_up() is False:
            self.log.info("fs(%s %s) is already umounted"%
                    (self.device, self.mountPoint))
            return
        for i in range(3):
            ret = try_umount(self)
            if ret == 0: break
        if ret != 0:
            self.log.error('failed to umount %s'%self.mountPoint)
            raise ex.excError
        self.Mounts = None

if __name__ == "__main__":
    for c in (Mount,) :
        help(c)

 0707010006720c000081a40000000000000000000000014d9d7e6e00001486000000b600010002ffffffffffffffff0000002700000000root/opt/opensvc/lib/rcStatsFreeBSD.py    #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2011 Christophe Varoqui <christophe.varoqui@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import os
from rcUtilities import call, which
import rcStats

class StatsProvider(rcStats.StatsProvider):
    def cpu(self, d, day, start, end):
        cols = ['date',
                'usr',
                'sys',
                'nice',
                'irq',
                'idle',
                'cpu',
                'nodename']
        cmd = ['bsdsar', '-u', '-n', day]
        (ret, buff) = call(cmd, errlog=False)
        lines = []
        if ret != 0:
            return cols, lines
        for line in buff.split('\n'):
            l = line.split()
            if len(l) != 6:
                continue
            if l[0] == 'Time':
                continue
            l += ['ALL', self.nodename]
            l[0] = '%s %s'%(d, l[0])
            lines.append(l)
        return cols, lines

    def kb(self, s):
        n = int(s[0:-1])
        unit = s[-1]
        if unit == 'k' or unit =='K':
            return n
        elif unit == 'M':
            return n*1024
        elif unit == 'G':
            return n*1024*1024
        elif unit == 'T':
            return n*1024*1024*1204
        elif unit == 'P':
            return n*1024*1024*1204*1024

    def mem_u(self, d, day, start, end):
        cols = ['date',
                'kbmemfree',
                'kbmemused',
                'pct_memused',
                'kbmemsys',
                'nodename']

        cmd = ['sysctl', 'hw.physmem']
        (ret, out) = call(cmd)
        physmem = int(out.split(': ')[1])/1024

        cmd = ['sysctl', 'hw.usermem']
        (ret, out) = call(cmd)
        usermem = int(out.split(': ')[1])/1024

        cmd = ['bsdsar', '-r', '-n', day]
        (ret, buff) = call(cmd)
        lines = []
        for line in buff.split('\n'):
            l = line.split()
            if len(l) != 7:
                continue
            if l[0] == 'Time':
                continue
            free = self.kb(l[1])
            used = self.kb(l[2])+self.kb(l[3])
            x = [l[0], str(free), str(used), str(used/(used+free)), str(physmem-usermem), self.nodename]
            x[0] = '%s %s'%(d, x[0])
            lines.append(x)
        return cols, lines

    def swap(self, d, day, start, end):
        cols = ['date',
                'kbswpfree',
                'kbswpused',
                'pct_swpused',
                'kbswpcad',
                'pct_swpcad',
                'nodename']
        cmd = ['bsdsar', '-r', '-n', day]
        (ret, buff) = call(cmd, errlog=False)
        lines = []
        if ret != 0:
            return cols, lines
        for line in buff.split('\n'):
           l = line.split()
           if len(l) != 7:
               continue
           if l[0] == 'Time':
               continue
           free = self.kb(l[6])
           used = self.kb(l[5])
           x = [l[0], str(free), str(used), str(used/(free+used)), '0', '0']
           x.append(self.nodename)
           x[0] = '%s %s'%(d, x[0])
           lines.append(x)
        return cols, lines

    def netdev(self, d, day, start, end):
        cols = ['date',
                'rxpckps',
                'rxkBps',
                'txpckps',
                'txkBps',
                'dev',
                'nodename']
        cmd = ['bsdsar', '-I', '-n', day]
        (ret, buff) = call(cmd, errlog=False)
        lines = []
        if ret != 0:
            return cols, lines
        for line in buff.split('\n'):
           l = line.split()
           if len(l) != 9:
               continue
           if l[0] == 'Time':
               continue
           x = [l[0], l[1], l[3], l[4], l[6], l[8], self.nodename]
           x[0] = '%s %s'%(d, x[0])
           lines.append(x)
        return cols, lines

    def netdev_err(self, d, day, start, end):
        cols = ['date',
                'rxerrps',
                'txerrps',
                'collps',
                'dev',
                'nodename']
        cmd = ['bsdsar', '-I', '-n', day]
        (ret, buff) = call(cmd, errlog=False)
        lines = []
        if ret != 0:
            return cols, lines
        for line in buff.split('\n'):
           l = line.split()
           if len(l) != 9:
               continue
           if l[0] == 'Time':
               continue
           x = [l[0], l[2], l[5], l[7], l[8], self.nodename]
           x[0] = '%s %s'%(d, l[0])
           lines.append(x)
        return cols, lines

  0707010006723d000081a40000000000000000000000014d9d7e6e00001449000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/resMountAIX.py   #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import os

import rcMountsAIX as rcMounts
import resMount as Res
from rcUtilities import qcall, protected_mount, getmount
from rcGlobalEnv import rcEnv
import rcExceptions as ex
from stat import *

def try_umount(self):
    cmd = ['umount', self.mountPoint]
    (ret, out) = self.vcall(cmd, err_to_warn=True)
    if ret == 0:
        return 0

    """ don't try to kill process using the source of a 
        protected bind mount
    """
    if protected_mount(self.mountPoint):
        return 1

    """ best effort kill of all processes that might block
        the umount operation. The priority is given to mass
        action reliability, ie don't contest oprator's will
    """
    cmd = ['sync']
    (ret, out) = self.vcall(cmd)

    for i in range(4):
        cmd = ['fuser', '-k', '-x', '-c', self.mountPoint]
        (ret, out) = self.vcall(cmd, err_to_info=True)
        self.log.info('umount %s'%self.mountPoint)
        cmd = ['umount', self.mountPoint]
        ret = qcall(cmd)
        if ret == 0:
            break

    return ret


class Mount(Res.Mount):
    """ define Linux mount/umount doAction """
    def __init__(self, rid, mountPoint, device, fsType, mntOpt,
                 snap_size=None, always_on=set([]),
                 disabled=False, tags=set([]), optional=False):
        self.Mounts = None
        Res.Mount.__init__(self, rid, mountPoint, device, fsType, mntOpt,
                           snap_size, always_on,
                           disabled=disabled, tags=tags, optional=optional)
        self.fsck_h = {
            'jfs': {'bin': 'fsck', 'cmd': ['fsck', '-p', '-V', 'jfs', self.device]},
            'jfs2': {'bin': 'fsck', 'cmd': ['fsck', '-p', '-V', 'jfs2', self.device]},
        }

    def is_up(self):
        self.Mounts = rcMounts.Mounts()
        return self.Mounts.has_mount(self.device, self.mountPoint)

    def realdev(self):
        try:
            mode = os.stat(self.device)[ST_MODE]
        except:
            self.log.debug("can not stat %s" % self.device)
            return None
        if S_ISBLK(mode):
            dev = self.device
        else:
            mnt = getmount(self.device)
            if self.Mounts is None:
                self.Mounts = rcMounts.Mounts()
            m = self.Mounts.has_param("mnt", mnt)
            if m is None:
                self.log.debug("can't find dev %(dev)s mounted in %(mnt)s in mnttab"%dict(mnt=mnt, dev=self.device))
                return None
            dev = m.dev

        return dev

    def mplist(self):
        dev = self.realdev()
        if dev is None:
            return set([])

        return self._mplist([dev])

    def _mplist(self, devs):
        mps = set([])
        return mps

    def disklist(self):
        dev = self.realdev()
        if dev is None:
            return set([])
        return set([])

    def can_check_writable(self):
        return True

    def start(self):
        if self.Mounts is None:
            self.Mounts = rcMounts.Mounts()
        Res.Mount.start(self)
        if self.is_up() is True:
            self.log.info("fs(%s %s) is already mounted"%
                (self.device, self.mountPoint))
            return 0
        self.fsck()
        if not os.path.exists(self.mountPoint):
            os.makedirs(self.mountPoint, 0755)
        if self.fsType != "":
            fstype = ['-v', self.fsType]
        else:
            fstype = []
        if self.mntOpt != "":
            mntopt = ['-o', self.mntOpt]
        else:
            mntopt = []
        cmd = ['mount']+fstype+mntopt+[self.device, self.mountPoint]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError
        self.Mounts = None

    def stop(self):
        if self.Mounts is None:
            self.Mounts = rcMounts.Mounts()
        if self.is_up() is False:
            self.log.info("fs(%s %s) is already umounted"%
                    (self.device, self.mountPoint))
            return
        for i in range(3):
            ret = try_umount(self)
            if ret == 0: break
        if ret != 0:
            self.log.error('failed to umount %s'%self.mountPoint)
            raise ex.excError
        self.Mounts = None

if __name__ == "__main__":
    for c in (Mount,) :
        help(c)

   07070100067238000081a40000000000000000000000014d9d7e6e00000683000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/lib/resIpZone.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.
"Module implement SunOS specific ip management"

import resIpSunOS as Res
from subprocess import *

class Ip(Res.Ip):
    def __init__(self, rid=None, ipDev=None, ipName=None,
                 mask=None, always_on=set([]),
                 disabled=False, tags=set([]), optional=False):
        Res.Ip.__init__(self, rid=rid, ipDev=ipDev, ipName=ipName,
                        mask=mask, always_on=always_on,
                        disabled=disabled, tags=tags, optional=optional)

    def startip_cmd(self):
        cmd=['ifconfig', self.stacked_dev, 'plumb', self.addr, \
            'netmask', '+', 'broadcast', '+', 'up' , 'zone' , self.svc.vmname ]
        return self.vcall(cmd)


if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

 070701000671e1000081a40000000000000000000000014d9d7e6e0000045c000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/rcDiskInfo.py    #!/usr/bin/python2.6
#
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

class diskInfo(object):
    """Parent class for diskInfo OS"""

    def disk_id(self, dev):
        return "tbd"

    def disk_vendor(self, dev):
        return "tbd"

    def disk_model(self, dev):
        return "tbd"

    def disk_size(self, dev):
        return "tbd"
070701000671de000081a40000000000000000000000014d9d7e6e0000197e000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/rcAssetLinux.py  #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import datetime
from rcUtilities import call, which
import rcAsset

def is_container():
    p = '/proc/1/cgroup'
    if not os.path.exists(p):
        return False
    with open(p, 'r') as f:
        lines = f.readlines()
        if len(lines) != 1:
            return False
        l = lines[0].split(':')
        if l[-1].strip('\n') != '/':
            return True
    return False

class Asset(rcAsset.Asset):
    def __init__(self, node):
        rcAsset.Asset.__init__(self, node)
        self.container = is_container()
        if self.container:
            self.dmidecode = []
        else:
            (ret, out) = call(['dmidecode'])
            if ret != 0:
                self.dmidecode = []
            else:
                self.dmidecode = out.split('\n')

    def get_mem_bytes(self):
        cmd = ['free', '-m']
        (ret, out) = call(cmd)
        if ret != 0:
            return '0'
        lines = out.split('\n')
        if len(lines) < 2:
            return '0'
        line = lines[1].split()
        if len(line) < 2:
            return '0'
        return line[1]

    def get_mem_banks(self):
        if self.container:
            return 'n/a'
        banks =  0
        inBlock = False
        for l in self.dmidecode:
            if not inBlock and l == "Memory Device":
                 inBlock = True
            if inBlock and "Size:" in l:
                 e = l.split()
                 if len(e) == 3:
                     try:
                         size = int(e[1])
                         banks += 1
                     except:
                         pass
        return str(banks)

    def get_mem_slots(self):
        if self.container:
            return 'n/a'
        for l in self.dmidecode:
            if 'Number Of Devices:' in l:
                return l.split()[-1]
        return '0'

    def get_os_vendor(self):
        if os.path.exists('/etc/lsb-release'):
            with open('/etc/lsb-release') as f:
                for line in f.readlines():
                    if 'DISTRIB_ID' in line:
                        return line.split('=')[-1].replace('\n','').strip('"')
        if os.path.exists('/etc/debian_version'):
            return 'Debian'
        if os.path.exists('/etc/SuSE-release'):
            return 'SuSE'
        if os.path.exists('/etc/redhat-release'):
            with open('/etc/redhat-release', 'r') as f:
                if 'CentOS' in f.read():
                    return 'CentOS'
                else:
                    return 'Redhat'
        return 'Unknown'

    def get_os_release(self):
        files = ['/etc/debian_version',
                 '/etc/redhat-release']
        if os.path.exists('/etc/SuSE-release'):
            v = []
            with open('/etc/SuSE-release') as f:
                for line in f.readlines():
                    if 'VERSION' in line:
                        v += [line.split('=')[-1].replace('\n','').strip('" ')]
                    if 'PATCHLEVEL' in line:
                        v += [line.split('=')[-1].replace('\n','').strip('" ')]
	    return '.'.join(v)
        if os.path.exists('/etc/lsb-release'):
            with open('/etc/lsb-release') as f:
                for line in f.readlines():
                    if 'DISTRIB_DESCRIPTION' in line:
                        r = line.split('=')[-1].replace('\n','').strip('"')
                        r = r.replace(self.get_os_vendor(), '').strip()
                        return r
        for f in files:
            if os.path.exists(f):
                (ret, out) = call(['cat', f])
                if ret != 0:
                    return 'Unknown'
                return out.split('\n')[0].replace('CentOS','').strip()
        return 'Unknown'

    def get_os_kernel(self):
        (ret, out) = call(['uname', '-r'])
        if ret != 0:
            return 'Unknown'
        return out.split('\n')[0]

    def get_os_arch(self):
        if which('arch') is not None:
            cmd = ['arch']
        else:
            cmd = ['uname', '-m']
        (ret, out) = call(cmd)
        if ret != 0:
            return 'Unknown'
        return out.split('\n')[0]

    def get_cpu_freq(self):
        p = '/proc/cpuinfo'
        if not os.path.exists(p):
            return 'Unknown'
        with open(p, 'r') as f:
            for line in f.readlines():
                if 'cpu MHz' in line:
                    return line.split(':')[1].strip().split('.')[0]
        return 'Unknown'

    def get_cpu_cores(self):
        with open('/proc/cpuinfo') as f:
            lines = f.readlines()
            lines = [l for l in lines if 'core id' in l]
            if len(lines) == 0:
                return '1'
            c = lines[-1].split(':')[-1].replace('\n','').strip()
            c = int(c) + 1
            return str(c)
        return '0'

    def get_cpu_dies(self):
        if self.container:
            return 'n/a'
        c = 0
        for l in self.dmidecode:
            if 'Processor Information' in l:
                c += 1
        return str(c)

    def get_cpu_model(self):
        (ret, out) = call(['grep', 'model name', '/proc/cpuinfo'])
        if ret != 0:
            return 'Unknown'
        lines = out.split('\n')
        l = lines[0].split(':')
        return l[1].strip()

    def get_serial(self):
        if self.container:
            return 'n/a'
        for l in self.dmidecode:
            if 'Serial Number:' in l:
                return l.split(':')[-1].strip()
        return 'Unknown'

    def get_model(self):
        if self.container:
            return 'container'
        for l in self.dmidecode:
            if 'Product Name:' in l:
                return l.split(':')[-1].strip()
        return 'Unknown'

  07070100067263000081a40000000000000000000000014d9d7e6e000005ca000000b600010002ffffffffffffffff0000001f00000000root/opt/opensvc/lib/svcKvm.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import svc
import resContainerKvm as kvm
import rcStatus
import rcExceptions as ex
from rcGlobalEnv import rcEnv

class SvcKvm(svc.Svc):
    """ Define kvm services"""

    def __init__(self, svcname, vmname=None, guestos=None, optional=False, disabled=False, tags=set([])):
        svc.Svc.__init__(self, svcname, optional=optional, disabled=disabled, tags=tags)
        if vmname is None:
            vmname = svcname
        self.vmname = vmname
        self.guestos = guestos
        self += kvm.Kvm(vmname)
        self.runmethod = rcEnv.rsh.split() + [vmname]


  07070100067243000081a40000000000000000000000014d9d7e6e00001952000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/resScsiReserv.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import resources as Res
import uuid
import re
import time
import rcStatus
import rcExceptions as ex
from rcUtilities import which
from subprocess import *
from rcGlobalEnv import rcEnv
hostId = __import__('hostid'+rcEnv.sysname)


class ScsiReserv(Res.Resource):
    """Define method to acquire and release scsi SPC-3 persistent reservations
    on disks held by a service
    """
    def __init__(self, rid=None, disks=set([]),
                 disabled=False, tags=set([]), optional=False):
        self.hostid = '0x'+hostId.hostid()
        self.disks = disks
        if len(disks) == 0:
            self.label = 'preserv 0 scsi disk'
        elif len(', '.join(disks)) > 48:
            self.label = 'preserv '+', '.join(disks)[0:48]
            self.label += " ..."
        else:
            self.label = ', '.join(disks)
        self.preempt_timeout = 10
        self.prtype = '5'
        Res.Resource.__init__(self, rid=rid+"pr", type="disk.scsireserv",
                              disabled=disabled, tags=tags, optional=optional)

    def scsireserv_supported(self):
        return False

    def ack_unit_attention(self, d):
        raise ex.notImplemented

    def disk_registered(self, disk):
        raise ex.notImplemented

    def disk_register(self, disk):
        raise ex.notImplemented

    def disk_unregister(self, disk):
        raise ex.notImplemented

    def get_reservation_key(self, disk):
        raise ex.notImplemented

    def disk_reserved(self, disk):
        raise ex.notImplemented

    def disk_release(self, disk):
        raise ex.notImplemented

    def disk_reserve(self, disk):
        raise ex.notImplemented

    def disk_preempt_reservation(self, disk, oldkey):
        raise ex.notImplemented

    def ack_all_unit_attention(self):
        for d in self.disks:
            try:
                if self.ack_unit_attention(d) != 0:
                    return 1
            except ex.excScsiPrNotsupported:
                continue
        return 0

    def register(self):
        r = 0
        for d in self.disks:
            try:
                r += self.ack_unit_attention(d)
                r += self.disk_register(d)
            except ex.excScsiPrNotsupported:
                continue
        return r

    def unregister(self):
        r = 0
        for d in self.disks:
            try:
                r += self.ack_unit_attention(d)
                if not self.disk_registered(d):
                    continue
                r += self.disk_unregister(d)
            except ex.excScsiPrNotsupported:
                continue
        return r

    def disk_wait_reservation(self, disk):
        i = 0
        while i>0:
            i -= 1
            if self.disk_reserved(disk):
                self.log.info("reservation acquired for disk %s" % disk)
                return 0
            time.sleep(1)
        self.log.error("timed out waiting for reservation for disk %s" % disk)
        return 1

    def reserve(self):
        r = 0
        for d in self.disks:
            try:
                r += self.ack_unit_attention(d)
                key = self.get_reservation_key(d)
                if key is None:
                    r += self.disk_reserve(d)
                elif key == self.hostid:
                    continue
                else:
                    r += self.disk_preempt_reservation(d, key)
                    r += self.disk_wait_reservation(d)
            except ex.excScsiPrNotsupported:
                continue
        return r

    def release(self):
        r = 0
        for d in self.disks:
            try:
                r += self.ack_unit_attention(d)
                if not self.disk_reserved(d):
                    continue
                r += self.disk_release(d)
            except ex.excScsiPrNotsupported:
                continue
        return r

    def checkreserv(self):
        if self.ack_all_unit_attention() != 0:
            return rcStatus.WARN
        r = rcStatus.Status()
        for d in self.disks:
            try:
                key = self.get_reservation_key(d)
                if key is None:
                    self.log.debug("disk %s is not reserved" % d)
                    r += rcStatus.DOWN
                elif key != self.hostid:
                    self.log.debug("disk %s is reserved by another host whose key is %s" % (d, key))
                    r += rcStatus.DOWN
                else:
                    self.log.debug("disk %s is correctly reserved" % d)
                    r += rcStatus.UP
            except ex.excScsiPrNotsupported:
                continue
        return r.status

    def scsireserv(self):
        if not self.scsireserv_supported():
            return
        r = 0
        r += self.register()
        r += self.reserve()
        return r

    def scsirelease(self):
        if not self.scsireserv_supported():
            return
        r = 0
        r += self.release()
        r += self.unregister()
        return r

    def scsicheckreserv(self):
        if not self.scsireserv_supported():
            return
        return self.checkreserv()

    def _status(self, verbose=False):
        if not self.scsireserv_supported():
            return rcStatus.NA
        return self.scsicheckreserv()

    def start(self):
        if not self.scsireserv_supported():
            return
        if self.scsireserv() != 0:
            raise ex.excError

    def stop(self):
        if not self.scsireserv_supported():
            return
        if self.scsirelease() != 0:
            raise ex.excError


  070701000671eb000081a40000000000000000000000014d9d7e6e0000101c000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/rcIfconfig.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from subprocess import *
import logging
from rcGlobalEnv import *

class interface:
    def __str__(self):
        a = ['ifconfig %s:'%self.name]
        a += [' link_encap = ' + self.link_encap]
        a += [' scope = ' + self.scope]
        a += [' bcast = ' + self.bcast]
        a += [' mtu = ' + self.mtu]
        a += [' ipaddr = ' + str(self.ipaddr)]
        a += [' mask = ' + str(self.mask)]
        a += [' ip6addr = ' + str(self.ip6addr)]
        a += [' ip6mask = ' + str(self.ip6mask)]
        a += [' hwaddr = ' + self.hwaddr]
        a += [' flag_up = ' + str(self.flag_up)]
        a += [' flag_broadcast = ' + str(self.flag_broadcast)]
        a += [' flag_running = ' + str(self.flag_running)]
        a += [' flag_multicast = ' + str(self.flag_multicast)]
        a += [' flag_loopback = ' + str(self.flag_loopback)]
        return '\n'.join(a)

    def __init__(self, name):
        self.name = name
        # defaults
        self.link_encap = ''
        self.scope = ''
        self.bcast = ''
        self.mask = ''
        self.mtu = ''
        self.ipaddr = ''
        self.ip6addr = []
        self.ip6mask = []
        self.hwaddr = ''
        self.flag_up = False
        self.flag_broadcast = False
        self.flag_running = False
        self.flag_multicast = False
        self.flag_loopback = False

class ifconfig(object):
    def add_interface(self, name):
        i = interface(name)
        self.intf.append(i)

    def interface(self, name):
        for i in self.intf:
            if i.name == name:
                return i
        return None

    def has_interface(self, name):
        for i in self.intf:
            if i.name == name:
                return 1
        return 0

    def has_param(self, param, value):
        for i in self.intf:
            if isinstance(getattr(i, param), list):
                if value in getattr(i, param):
                    return i
            else:
                if getattr(i, param) == value:
                    return i
        return None

    def __str__(self):
        for intf in self.intf:
            print intf

    def __init__(self):
        self.intf = []

    def next_stacked_dev(self,dev):
        """Return the first available interfaceX:Y on  interfaceX
        """
        i = 1
        while True:
            stacked_dev = dev+':'+str(i)
            if not self.has_interface(stacked_dev):
                return stacked_dev
            i = i + 1

    def get_stacked_dev(self, dev, addr, log):
        """Upon start, a new interfaceX:Y will have to be assigned.
        Upon stop, the currently assigned interfaceX:Y will have to be
        found for ifconfig down
        """
        if ':' in addr:
            stacked_intf = self.has_param("ip6addr", addr)
        else:
            stacked_intf = self.has_param("ipaddr", addr)
        if stacked_intf is not None:
            if dev not in stacked_intf.name:
                log.error("%s is plumbed but not on %s" % (addr, dev))
                return
            stacked_dev = stacked_intf.name
            log.debug("found matching stacked device %s" % stacked_dev)
        else:
            stacked_dev = self.next_stacked_dev(dev)
            log.debug("allocate new stacked device %s" % stacked_dev)
        return stacked_dev


0707010006726a000081a40000000000000000000000014d9d94550000001c000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/version.py   version = "1.0-110407.1105"
0707010006724a000081a40000000000000000000000014d9d7e6e00003b49000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/resSyncRsync.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import logging

from rcGlobalEnv import rcEnv
from rcUtilities import which
import rcExceptions as ex
import rcStatus
import datetime
import resSync

def lookup_snap_mod():
    if rcEnv.sysname == 'Linux':
        return __import__('snapLvmLinux')
    elif rcEnv.sysname == 'HP-UX':
        return __import__('snapVxfsHP-UX')
    elif rcEnv.sysname == 'AIX':
        return __import__('snapJfs2AIX')
    elif rcEnv.sysname in ['SunOS', 'FreeBSD']:
        return __import__('snapZfsSunOS')
    else:
        raise ex.excError

def remote_fs_mounted(self, node):
    """Verify the remote fs is mounted before we send data.
    """
    if self.dstfs is None:
        """No check has been configured. Assume the admin knows better.
        """
        return True
    cmd = rcEnv.rsh.split(' ')+[node, '--', 'df', self.dstfs]
    (ret, out) = self.call(cmd, cache=True)
    if ret != 0:
        raise ex.excError
    if self.dstfs not in out.split():
        self.log.error("The destination fs %s is not mounted on node %s. refuse to sync %s to protect parent fs"%(self.dstfs, node, self.dst))
        return False
    return True

cache_remote_node_type = {}

def remote_node_type(self, node, target):
    if target == 'drpnodes':
        expected_type = list(set(rcEnv.allowed_svctype) - set(['PRD']))
    elif target == 'nodes':
        expected_type = [self.svc.svctype]
    else:
        self.log.error('unknown sync target: %s'%target)
        raise ex.excError

    rcmd = [os.path.join(rcEnv.pathbin, 'nodemgr'), 'get', '--param', 'node.host_mode']

    if node not in cache_remote_node_type:
        cmd = rcEnv.rsh.split(' ')+[node, '--'] + rcmd
        (ret, out) = self.call(cmd, cache=True)
        if ret != 0:
            raise ex.excError
        words = out.split()
        if len(words) == 1:
            cache_remote_node_type[node] = words[0]
        else:
            cache_remote_node_type[node] = out

    if cache_remote_node_type[node] in expected_type:
        return True
    self.log.error("incompatible remote node '%s' host mode: '%s' (expected in %s)"%\
                   (node, cache_remote_node_type[node], str(expected_type)))
    return False

def get_timestamp_filename(self, node):
    sync_timestamp_d = os.path.join(rcEnv.pathvar, 'sync', node)
    sync_timestamp_f = os.path.join(sync_timestamp_d, self.svc.svcname+'!'+self.rid)
    return sync_timestamp_f

def sync_timestamp(self, node):
    sync_timestamp_f = get_timestamp_filename(self, node)
    sync_timestamp_d = os.path.dirname(sync_timestamp_f)
    sync_timestamp_d_src = os.path.join(rcEnv.pathvar, 'sync', rcEnv.nodename)
    sync_timestamp_f_src = os.path.join(sync_timestamp_d_src, self.svc.svcname+'!'+self.rid)
    if not os.path.isdir(sync_timestamp_d):
        os.makedirs(sync_timestamp_d ,0755)
    if not os.path.isdir(sync_timestamp_d_src):
        os.makedirs(sync_timestamp_d_src ,0755)
    with open(sync_timestamp_f, 'w') as f:
        f.write(str(datetime.datetime.now())+'\n')
        f.close()
    import shutil
    shutil.copy2(sync_timestamp_f, sync_timestamp_d_src)
    cmd = ['rsync'] + self.options + bwlimit_option(self) + ['-R', sync_timestamp_f, sync_timestamp_f_src, node+':/']
    self.vcall(cmd)

def get_timestamp(self, node):
    ts = None
    sync_timestamp_f = get_timestamp_filename(self, node)
    if not os.path.exists(sync_timestamp_f):
        return None
    try:
        with open(sync_timestamp_f, 'r') as f:
            d = f.read()
            ts = datetime.datetime.strptime(d,"%Y-%m-%d %H:%M:%S.%f\n")
            f.close()
    except:
        self.log.info("failed get last sync date for %s to %s"%(self.src, node))
        return ts
    return ts

def bwlimit_option(self):
    if self.bwlimit is not None:
        bwlimit = [ '--bwlimit='+self.bwlimit ]
    elif self.svc.bwlimit is not None:
        bwlimit = [ '--bwlimit='+self.svc.bwlimit ]
    else:
        bwlimit = []
    return bwlimit

class Rsync(resSync.Sync):
    """Defines a rsync job from local node to its remote nodes. Target nodes
    can be restricted to production sibblings or to disaster recovery nodes,
    or both.
    """
    def node_can_sync(self, node):
        ts = get_timestamp(self, node)
        return not self.skip_sync(ts)

    def node_need_sync(self, node):
        ts = get_timestamp(self, node)
        return self.alert_sync(ts)

    def can_sync(self, target=None):
        targets = set([])
        if target is None:
            targets = self.nodes_to_sync('nodes')
            targets |= self.nodes_to_sync('drpnodes')
        else:
            targets = self.nodes_to_sync(target)

        if len(targets) == 0:
            return False
        return True

    def nodes_to_sync(self, target=None, state="syncable", status=False):
        """ Checks are ordered by cost
        """

        """ DRP nodes are not allowed to sync nodes nor drpnodes
        """
        if rcEnv.nodename in self.svc.drpnodes:
            return set([])

        """ Refuse to sync from a flex non-primary node
        """
        if self.svc.clustertype in ["flex", "autoflex"] and \
           self.svc.flex_primary != rcEnv.nodename:
            self.log.debug("won't sync this resource from a flex non-primary node")
            return set([])

        """Discard the local node from the set
        """
        if target in self.target.keys():
            targets = self.target[target].copy()
        else:
            return set([])

        targets -= set([rcEnv.nodename])
        if len(targets) == 0:
            return set([])

        for node in targets.copy():
            if state == "syncable" and not self.node_can_sync(node):
                targets -= set([node])
                continue
            elif state == "late" and not self.node_need_sync(node):
                targets -= set([node])
                continue

        if len(targets) == 0:
            return set([])

        """Accept to sync from here only if the service is up
           Also accept n/a status, because it's what the overall status
           ends up to be when only sync#* are specified using --rid

           sync#i1 is an exception, because we want all prd nodes to
           sync their system files to all drpnodes regardless of the service
           state
        """
        s = self.svc.group_status(excluded_groups=set(["sync", "hb"]))
        if s['overall'].status not in [rcStatus.UP, rcStatus.NA] and \
           self.rid != "sync#i1":
            if s['overall'].status == rcStatus.WARN:
                self.log.debug("won't sync this resource service in warn status")
            self.log.debug("won't sync this resource for a service not up")
            return set([])

        for node in targets.copy():
            if not status and not remote_node_type(self, node, target):
                targets -= set([node])
                continue
            if not status and not remote_fs_mounted(self, node):
                targets -= set([node])
                continue

        if len(targets) == 0:
            return set([])

        return targets

    def sync(self, target):
        if target not in self.target.keys():
            self.log.debug('%s => %s sync not applicable to %s'%(self.src, self.dst, target))
            return 0

        targets = self.nodes_to_sync(target)

        if len(targets) == 0:
            self.log.debug("no nodes to sync")
            raise ex.syncNoNodesToSync

        if "delay_snap" in self.tags:
            if not hasattr(self.rset, 'snaps'):
                Snap = lookup_snap_mod()
                self.rset.snaps.log = self.log
                self.rset.snaps = Snap.Snap(self.rid)
            self.rset.snaps.try_snap(self.rset, target, rid=self.rid)

        if hasattr(self, "alt_src"):
            """ The pre_action() has provided us with a better source
                to sync from. Use that
            """
            src = self.alt_src
        else:
            src = self.src

        if len(src) == 0:
            self.log.debug("no files to sync")
            raise ex.syncNoFilesToSync

        bwlimit = bwlimit_option(self)

        for node in targets:
            dst = node + ':' + self.dst
            cmd = ['rsync'] + self.options + bwlimit + src
            cmd.append(dst)
            (ret, out) = self.vcall(cmd)
            if ret != 0:
                self.log.error("node %s synchronization failed (%s => %s)" % (node, src, dst))
                continue
            sync_timestamp(self, node)
            self.svc.need_postsync |= set([node])
        return

    def pre_action(self, rset, action):
        """Actions to do before resourceSet iterates through the resources to
           trigger action() on each one
        """

        """Don't sync PRD services when running on !PRD node
        """
        if self.svc.svctype == 'PRD' and rcEnv.host_mode != 'PRD':
            self.log.debug("won't sync a PRD service running on a !PRD node")
            raise ex.excAbortAction

        """ Is there at least one node to sync ?
        """
        targets = set([])
        rtargets = {0: set([])}
        need_snap = False
        for i, r in enumerate(rset.resources):
            if r.is_disabled():
                continue
            rtargets[i] = set([])
            if action == "syncnodes":
                rtargets[i] |= r.nodes_to_sync('nodes')
            else:
                rtargets[i] |= r.nodes_to_sync('drpnodes')
            for node in rtargets[i].copy():
                if not r.node_can_sync(node):
                    rtargets[i] -= set([node])
                elif r.snap:
                    need_snap = True
        for i in rtargets:
            targets |= rtargets[i]

        if len(targets) == 0:
            self.log.debug("no node to sync")
            raise ex.excAbortAction

        if not need_snap:
            self.log.debug("snap not needed")
            return

        Snap = lookup_snap_mod()
        try:
            rset.snaps = Snap.Snap(self.rid)
            rset.snaps.log = self.log
            rset.snaps.try_snap(rset, action)
        except ex.syncNotSnapable:
            raise ex.excError

    def post_action(self, rset, action):
        """Actions to do after resourceSet has iterated through the resources to
           trigger action() on each one
        """
        if hasattr(rset, 'snaps'):
            rset.snaps.snap_cleanup(rset)

    def syncnodes(self):
        try:
            self.sync("nodes")
        except ex.syncNoFilesToSync:
            self.log.debug("no file to sync")
            pass
        except ex.syncNoNodesToSync:
            self.log.debug("no node to sync")
            pass

    def syncdrp(self):
        try:
            self.sync("drpnodes")
        except ex.syncNoFilesToSync:
            self.log.debug("no file to sync")
            pass
        except ex.syncNoNodesToSync:
            self.log.debug("no node to sync")
            pass

    def _status(self, verbose=False):
        """ mono-node service should return n/a as a sync state
        """
        target = set([])
        for i in self.target:
            target |= self.target[i]
        if len(target - set([rcEnv.nodename])) == 0:
            self.status_log("no destination nodes")
            return rcStatus.NA

        """ sync state on nodes where the service is not UP
        """
        s = self.svc.group_status(excluded_groups=set(["sync", "hb"]))
        if s['overall'].status != rcStatus.UP or \
           (self.svc.clustertype in ['flex', 'autoflex'] and \
            rcEnv.nodename != self.svc.flex_primary and \
            s['overall'].status == rcStatus.UP):
            if rcEnv.nodename not in target:
                self.status_log("passive node not in sync destination nodes")
                return rcStatus.NA
            if self.node_need_sync(rcEnv.nodename):
                self.status_log("passive node needs update")
                return rcStatus.WARN
            else:
                return rcStatus.UP

        """ sync state on DRP nodes where the service is UP
        """
        if 'drpnodes' in self.target and rcEnv.nodename in self.target['drpnodes']:
            self.status_log("service up on drp node, sync disabled")
            return rcStatus.NA

        """ sync state on nodes where the service is UP
        """
        nodes = []
        nodes += self.nodes_to_sync('nodes', state="late", status=True)
        nodes += self.nodes_to_sync('drpnodes', state="late", status=True)
        if len(nodes) == 0:
            return rcStatus.UP

        self.status_log("%s need update"%', '.join(nodes))
        return rcStatus.DOWN

    def __init__(self, rid=None, src=[], dst=None, options=[], target={}, dstfs=None, snap=False,
                 bwlimit=None, sync_max_delay=None, sync_interval=None,
                 sync_days=None, sync_period=None,
                 optional=False, disabled=False, tags=set([]), internal=False):
        resSync.Sync.__init__(self, rid=rid, type="sync.rsync",
                              sync_max_delay=sync_max_delay,
                              sync_interval=sync_interval,
                              sync_days=sync_days,
                              sync_period=sync_period,
                              optional=optional, disabled=disabled, tags=tags)

        if internal:
            if rcEnv.drp_path in dst:
                self.label = "rsync system files to drpnodes"
            else:
                self.label = "rsync svc config to %s"%(', '.join(target.keys()))
        else:
            self.label = "rsync %s to %s"%(', '.join(src),
                                        ', '.join(target.keys()))
        self.src = src
        self.dst = dst
        self.dstfs = dstfs
        self.snap = snap
        self.target = target
        self.bwlimit = bwlimit
        self.internal = internal
        self.timeout = 3600
        self.options = ['-HpogDtrlvx',
                        '--stats',
                        '--delete',
                        '--force',
                        '--timeout='+str(self.timeout)]
        self.options += options

    def __str__(self):
        return "%s src=%s dst=%s options=%s target=%s" % (resSync.Sync.__str__(self),\
                self.src, self.dst, self.options, str(self.target))

   070701000671dd000081a40000000000000000000000014d9d7e6e000016f8000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/rcAssetHP-UX.py  #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
from rcUtilities import justcall, which
from rcGlobalEnv import rcEnv
from subprocess import *
import rcAsset

class Asset(rcAsset.Asset):
    def __init__(self, node):
        rcAsset.Asset.__init__(self, node)
        # echo "selclass qualifier memory;info;wait;infolog"|cstm
        process = Popen(['cstm'], stdin=PIPE, stdout=PIPE, stderr=None)
        (out, err) = process.communicate(input='selclass qualifier memory;info;wait;infolog')
        if process.returncode != 0:
            self.memory = []
        else:
            self.memory = out.split('\n')

        (out, err, ret) = justcall(['print_manifest'])
        if ret != 0:
            self.manifest = []
        else:
            self.manifest = out.split('\n')

        self.parse_memory()

    def get_mem_bytes(self):
        cmd = ['swapinfo', '-Mq']
        (out, err, ret) = justcall(cmd)
        if ret != 0:
            return '0'
        return str(int(out)//1024)

    def parse_memory(self):
        """
	   DIMM Slot      Size (MB)
	   ---------      ---------
		  0A           2048
		  3D              0
	   ---------      ---------

        or

	   DIMM Location          Size(MB)     DIMM Location          Size(MB)
	   --------------------   --------     --------------------   --------
	   Ext 0 DIMM 0A          2048         Ext 0 DIMM 0B          2048    
	   Ext 0 DIMM 5C          ----         Ext 0 DIMM 5D          ----    

	   Ext 0 Total: 32768 (MB)
        """
        if len(self.memory) == 0:
            return '0'
        self.banks =  0
        self.slots =  0
        begin = 0
        end = 0
        for i, l in enumerate(self.memory):
            if 'DIMM ' in l:
                begin = i+2
        if begin == 0:
            return '0'
        for i in range(begin, len(self.memory)):
            e = self.memory[i].split()
            if len(self.memory[i]) == 0 or '--' in e[0]:
                end = i
                break
        if end == 0:
            return '0'
        for i in range(begin, end):
            e = self.memory[i].split()
            n = len(e)
            if n == 2:
                # old format
                self.slots += 1
                if e[1] != '0':
                    self.banks += 1
                continue
            if n >= 5:
                # new format 1st col
                self.slots += 1
                if not '--' in e[4]:
                    self.banks += 1
            if n == 10:
                # new format 2nd col
                self.slots += 1
                if not '--' in e[9]:
                    self.banks += 1

    def get_mem_banks(self):
        return str(self.banks)

    def get_mem_slots(self):
        return str(self.slots)

    def get_os_vendor(self):
        return 'HP'

    def get_os_release(self):
        (out, err, ret) = justcall(['uname', '-r'])
        if ret != 0:
            return 'Unknown'
        return out.split('\n')[0].strip()

    def get_os_kernel(self):
        (out, err, ret) = justcall(['swlist', '-l', 'bundle', 'QPKBASE'])
        if ret != 0:
            return 'Unknown'
        for line in out.split('\n'):
            if 'QPKBASE' in line:
                return line.split()[1]
        return 'Unknown'

    def get_os_arch(self):
        (out, err, ret) = justcall(['uname', '-m'])
        if ret != 0:
            return 'Unknown'
        return out.split('\n')[0].strip()

    def get_cpu_freq(self):
        process = Popen(['adb', '/stand/vmunix', '/dev/kmem'], stdin=PIPE, stdout=PIPE, stderr=None)
        (out, err) = process.communicate(input='itick_per_usec/2d')
        if process.returncode != 0:
            process = Popen(['adb', '-k', '/stand/vmunix', '/dev/mem'], stdin=PIPE, stdout=PIPE, stderr=None)
            (out, err) = process.communicate(input='itick_per_usec/D')
        if process.returncode != 0:
            return 'Unknown'
        lines = out.split('\n')
        if len(lines) != 2:
            return 'Unknown'
        return lines[1].strip()

    def get_cpu_cores(self):
        for line in self.manifest:
            if 'Processors:' in line:
                return line.split()[-1]
        return '0'

    def get_cpu_dies(self):
        marker = False
        for line in self.manifest:
            if 'Processors:' in line:
                marker = True
                continue
            if marker:
                return line.split()[0]
        return '0'

    def get_cpu_model(self):
        marker = False
        for line in self.manifest:
            if 'Processors:' in line:
                marker = True
                continue
            if marker:
                e = line.split()
                return ' '.join(e[1:]).replace('processors','').replace('processor','')
        return 'Unknown'

    def get_serial(self):
        (out, err, ret) = justcall(['getconf', 'MACHINE_SERIAL'])
        if ret != 0:
            return 'Unknown'
        return out

    def get_model(self):
        (out, err, ret) = justcall(['getconf', 'MACHINE_MODEL'])
        if ret != 0:
            return 'Unknown'
        return out

07070100067211000081a40000000000000000000000014d9d7e6e000015c4000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/rcSymmetrix.py   from rcUtilities import justcall, which
from xml.etree.ElementTree import XML, fromstring
import rcExceptions as ex
import os

class Syms(object):
    syms = []
    def __init__(self):
        self.index = 0
        if which('symcfg') is None:
            print 'Can not find symcli programs in PATH'
            raise ex.excError
        out, err, ret = justcall(['symcfg', 'list', '-output', 'xml_element'])
        if ret != 0:
            print err
            raise ex.excError
        tree = fromstring(out)
        for symm in tree.getiterator('Symm_Info'):
            model = symm.find('model').text
            sid = symm.find('symid').text
            if model in ['VMAX-1']:
                self.syms.append(Vmax(sid))
            if 'DMX' in model or '3000-M' in model:
                self.syms.append(Dmx(sid))
            else:
                print "unsupported sym model: %s"%model

    def __iter__(self):
        return self

    def next(self):
        if self.index == len(self.syms):
            raise StopIteration
        self.index += 1
        return self.syms[self.index-1]

class Sym(object):
    def __init__(self, sid):
        self.keys = ['sym_info',
                     'sym_dir_info',
                     'sym_dev_info',
                     'sym_devrdfa_info',
                     'sym_ficondev_info',
                     'sym_meta_info',
                     'sym_disk_info',
                     'sym_diskgroup_info']

        self.sid = sid

    def symcmd(self, cmd):
        cmd += ['-sid', self.sid, '-output', 'xml_element']
        return justcall(cmd)

    def symaccesscmd(self, cmd):
        if self.aclx is None:
            cmd += ['-output', 'xml_element']
        else:
            cmd += ['-file', self.aclx, '-output', 'xml_element']
        return justcall(cmd)

    def get_sym_info(self):
        cmd = ['symcfg', 'list']
        out, err, ret = self.symcmd(cmd)
        return out

    def get_sym_dir_info(self):
        cmd = ['symcfg', '-dir', 'all', '-v', 'list']
        out, err, ret = self.symcmd(cmd)
        return out

    def get_sym_dev_info(self):
        cmd = ['symdev', 'list']
        out, err, ret = self.symcmd(cmd)
        return out

    def get_sym_devrdfa_info(self):
        cmd = ['symdev', 'list', '-v', '-rdfa']
        out, err, ret = self.symcmd(cmd)
        return out

    def get_sym_ficondev_info(self):
        cmd = ['symdev', 'list', '-ficon']
        out, err, ret = self.symcmd(cmd)
        return out

    def get_sym_meta_info(self):
        cmd = ['symdev', 'list', '-meta', '-v']
        out, err, ret = self.symcmd(cmd)
        return out

    def get_sym_disk_info(self):
        cmd = ['symdisk', 'list', '-v']
        out, err, ret = self.symcmd(cmd)
        return out

    def get_sym_diskgroup_info(self):
        cmd = ['symdisk', 'list', '-dskgrp_summary']
        out, err, ret = self.symcmd(cmd)
        return out

class Vmax(Sym):
    def __init__(self, sid):
        Sym.__init__(self, sid)
        self.keys += ['sym_ig_aclx',
                      'sym_pg_aclx',
                      'sym_sg_aclx',
                      'sym_view_aclx']

        if 'SYMCLI_DB_FILE' in os.environ:
            dir = os.path.dirname(os.environ['SYMCLI_DB_FILE'])
            # flat format
            self.aclx = os.path.join(dir, sid+'.aclx')
            if not os.path.exists(self.aclx):
                # emc grab format
                import glob
                files = glob.glob(os.path.join(dir, sid, sid+'*.aclx'))
                if len(files) == 1:
                    self.aclx = files[0]
            if not os.path.exists(self.aclx):
                print "missing file %s"%self.aclx
        else:
            self.aclx = None

    def symaccesscmd(self, cmd):
        if self.aclx is None:
            cmd += ['-output', 'xml_element']
        else:
            cmd += ['-file', self.aclx, '-output', 'xml_element']
        return justcall(cmd)

    def get_sym_pg_aclx(self):
        cmd = ['symaccess', 'list', '-type', 'port']
        out, err, ret = self.symaccesscmd(cmd)
        return out

    def get_sym_sg_aclx(self):
        cmd = ['symaccess', 'list', '-type', 'storage']
        out, err, ret = self.symaccesscmd(cmd)
        return out

    def get_sym_ig_aclx(self):
        cmd = ['symaccess', 'list', '-type', 'initiator']
        out, err, ret = self.symaccesscmd(cmd)
        return out

    def get_sym_view_aclx(self):
        cmd = ['symaccess', 'list', 'view', '-details']
        out, err, ret = self.symaccesscmd(cmd)
        return out

class Dmx(Sym):
    def __init__(self, sid):
        Sym.__init__(self, sid)
        self.keys += ['sym_maskdb']

        if 'SYMCLI_DB_FILE' in os.environ:
            dir = os.path.dirname(os.environ['SYMCLI_DB_FILE'])
            # flat format
            self.maskdb = os.path.join(dir, sid+'.bin')
            if not os.path.exists(self.maskdb):
                # emc grab format
                self.maskdb = os.path.join(dir, sid, 'symmaskdb_backup.bin')
            if not os.path.exists(self.maskdb):
                print "missing file %s"%self.maskdb
        else:
            self.maskdb = None

    def symaccesscmd(self, cmd):
        if self.maskdb is None:
            cmd += ['-sid', self.sid, '-output', 'xml_element']
        else:
            cmd += ['-f', self.maskdb, '-output', 'xml_element']
        return justcall(cmd)

    def get_sym_maskdb(self):
        cmd = ['symmaskdb', 'list', 'database']
        out, err, ret = self.symaccesscmd(cmd)
        return out


07070100067224000081a40000000000000000000000014d9d7e6e00000f17000000b600010002ffffffffffffffff0000002800000000root/opt/opensvc/lib/resContainerXen.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import resources as Res
import os
import rcExceptions as ex
import resContainer

rcU = __import__("rcUtilities" + os.uname()[0])

class Xen(resContainer.Container):
    startup_timeout = 180
    shutdown_timeout = 120

    def __init__(self, name, optional=False, disabled=False, tags=set([])):
        resContainer.Container.__init__(self, rid="xen", name=name, type="container.xen",
                                        optional=optional, disabled=disabled, tags=tags)

    def __str__(self):
        return "%s name=%s" % (Res.Resource.__str__(self), self.name)

    def list_conffiles(self):
        cf = os.path.join(os.sep, 'opt', 'opensvc', 'var', self.name+'.xml')
        if os.path.exists(cf):
            return [cf]
        return []

    def files_to_sync(self):
        return self.list_conffiles()

    def check_capabilities(self):
        cmd = ['virsh', 'capabilities']
        (ret, out) = self.call(cmd, errlog=False)
        if ret != 0:
            self.status_log("can not fetch capabilities")
            return False
        if 'hvm' not in out:
            self.status_log("hvm not supported by host")
            return False
        return True

    def ping(self):
        return rcU.check_ping(self.addr, timeout=1, count=1)

    def container_start(self):
        cf = os.path.join(os.sep, 'opt', 'opensvc', 'var', self.name+'.xml')
        if os.path.exists(cf):
            cmd = ['virsh', 'define', cf]
            (ret, buff) = self.vcall(cmd)
            if ret != 0:
                raise ex.excError
        cmd = ['virsh', 'start', self.name]
        (ret, buff) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def container_stop(self):
        cmd = ['virsh', 'shutdown', self.name]
        (ret, buff) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def container_forcestop(self):
        cmd = ['virsh', 'destroy', self.name]
        (ret, buff) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def is_up(self):
        cmd = ['virsh', 'dominfo', self.name]
        (ret, out) = self.call(cmd, errlog=False)
        if ret != 0:
            return False
        if "running" in out.split() or "idle" in out.split() :
            return True
        return False

    def get_container_info(self):
        cmd = ['virsh', 'dominfo', self.name]
        (ret, out) = self.call(cmd, errlog=False, cache=True)
        self.info = {'vcpus': '0', 'vmem': '0'}
        if ret != 0:
            return self.info
        for line in out.split('\n'):
            if "CPU(s):" in line: self.info['vcpus'] = line.split(':')[1].strip()
            if "Max memory" in line: self.info['vmem'] = line.split(':')[1].strip()
            if "Autostart:" in line: self.info['autostart'] = line.split(':')[1].strip()
        return self.info           

    def check_manual_boot(self):
        self.get_container_info()
        if self.info['autostart'] == 'disable' :
                return True
        else:
                return False
 07070100067248000081a40000000000000000000000014d9d7e6e0000298b000000b600010002ffffffffffffffff0000002700000000root/opt/opensvc/lib/resSyncEvasnap.py    #
# Copyright (c) 2011 Christophe Varoqui <christophe.varoqui@opensvc.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import logging

from rcGlobalEnv import rcEnv
from rcUtilities import which
import rcExceptions as ex
import rcStatus
import time
import datetime
import xml.etree.ElementTree as ET
import subprocess
import resSync

class syncEvasnap(resSync.Sync):
    def wait_for_devs_ready(self):
        pass

    def can_sync(self, target=None):
        ts = None
 
        """ get oldest snap
        """
        for pair in self.pairs:
            info = self.lun_info(pair['dst'])
            if info is None:
                self.info.debug("snap %s missing"%pair['dst'])
                return True
            _ts = info['creationdatetime']
            if ts is None or _ts < ts:
                ts = _ts
        return not self.skip_sync(ts)

    def recreate(self):
        def snapname(info):
            return info['objectname'].split('\\')[-2]+'_'+self.svc.svcname

        try:
            self.prereq()
        except ex.excError as e:
            self.log.error(str(e))
            raise ex.excError

        status = self._status(skip_prereq=True)

        if not self.can_sync():
            return

        if not self.svc.force and status == rcStatus.UP:
            self.log.info("snapshots are already fresh. use --force to bypass")
            return

        cmd = []
        for pair in self.pairs:
            if pair['dst'] in self._lun_info:
                info = self._lun_info[pair['dst']]
                for mask in pair['mask']:
                    lunid = int(mask.split('\\')[-1])
                    hostpath = '\\'.join(mask.split('\\')[:-1])
                    if hostpath in info['mask'] and info['mask'][hostpath] == lunid:
                        cmd += ['delete lun "%s"'%mask]
                cmd += ['delete vdisk "%s" wait_for_completion'%info['objectname']]
        self.sssu(cmd, verbose=True)

        cmd = []
        for pair in self.pairs:
            info = self.lun_info(pair['src'])
            cmd += ['add snapshot %s vdisk="%s" allocation_policy=demand world_wide_lun_name=%s'%(snapname(info), info['objectname'], self.convert_wwid(pair['dst']))]
        self.sssu(cmd, verbose=True)

        cmd = []
        for pair in self.pairs:
            info = self.lun_info(pair['dst'])
            for mask in pair['mask']:
                lunid = mask.split('\\')[-1]
                hostpath = '\\'.join(mask.split('\\')[:-1])
                cmd += ['add lun %s host="%s" vdisk="%s"'%(lunid, hostpath, snapname(info))]
        self.sssu(cmd, verbose=True)

    def sssu(self, cmd=[], verbose=False, check=True):
        cmd = [self.sssubin,
               "select manager %s username=%s password=%s"%(self.manager, self.username, self.password),
               "select system %s"%self.eva_name] + cmd
        if verbose:
            import re
            from copy import copy
            _cmd = copy(cmd)
            _cmd[1] = re.sub(r'password=.*', 'password=xxxxx', _cmd[1])
            self.log.info(subprocess.list2cmdline(_cmd))
            ret, out = self.call(cmd)
            if 'Error:' in out > 0:
                self.log.error(out)
            else:
                self.log.info(out)
        else:
            ret, out = self.call(cmd)
        if check and "Error" in out:
            raise ex.excError("sssu command execution error")
        return ret, out

    def lun_info(self, wwid):
        if wwid in self._lun_info:
            return self._lun_info[wwid]

        if '-' not in wwid:
            _wwid = wwid
            wwid = self.convert_wwid(wwid)

        info = {
            'parent_wwid': 'unknown',
            'lunid': -1,
            'creationdatetime': datetime.datetime(year=datetime.MINYEAR, month=1, day=1),
            'mask': {}
        }
        try:
            ret, out = self.sssu(["find vdisk lunwwid="+wwid+" xml"])
        except:
            return None
        l = out.split('\n')
        for i, line in enumerate(l):
            if line == '<object>':
                l = l[i:]
                break
        e = ET.fromstring('\n'.join(l))

        for p in e.findall("presentations/presentation"):
            host = p.find("hostname").text
            lunid = p.find("lunnumber").text
            info['mask'][host] = int(lunid)
        
        e_parent_wwid = e.find("sharinginformation/parentvdiskhexuid")
        if e_parent_wwid is not None:
            info['parent_wwid'] = e_parent_wwid.text.replace('-','')

        e_objectname = e.find("objectname")
        if e_objectname is not None:
            info['objectname'] = e_objectname.text

        e_creationdatetime = e.find("creationdatetime")
        if e_parent_wwid is not None:
            try:
                creationdatetime = datetime.datetime.strptime(e_creationdatetime.text, "%d-%b-%Y %H:%M:%S")
                info['creationdatetime'] = creationdatetime
            except:
                self.log.error("failed to parse snapshot creation datetime")
                pass

        self._lun_info[_wwid] = info

        return info

    def _status(self, verbose=False, skip_prereq=False):
        err = False
        errlog = []
        try:
            if not skip_prereq:
                self.prereq()
        except ex.excError as e:
            self.status_log(str(e))
            return rcStatus.WARN
        for pair in self.pairs:
            info = self.lun_info(pair['dst'])
            if info is None:
                errlog.append("snapshot %s does not exists"%pair['dst'])
                err |= True
                continue
            if info['parent_wwid'].lower() != pair['src'].lower():
                errlog.append("snapshot %s exists but incorrect parent wwid"%pair['dst'])
                err |= True
            if info['creationdatetime'] < datetime.datetime.now() - datetime.timedelta(minutes=self.sync_max_delay):
                errlog.append("snapshot %s too old"%pair['dst'])
                err |= True
            for mask in pair['mask']:
                hostpath = '\\'.join(mask.split('\\')[:-1])
                hostname = mask.split('\\')[-2]
                dstlunid = mask.split('\\')[-1]
                if hostpath not in info['mask']:
                    errlog.append("snapshot %s exists but not presented to host %s"%(pair['dst'], hostname))
                    err |= True
                    continue
                try:
                    dstlunid = int(dstlunid)
                    if info['mask'][hostpath] != dstlunid:
                        errlog.append("snapshot %s exists but incorrect lunid for host %s"%(pair['dst'], hostname))
                        err |= True
                except ValueError:
                    pass
        if err:
            self.status_log('. '.join(errlog))
            return rcStatus.WARN
        return rcStatus.UP

    def syncresync(self):
        self.recreate()

    def refresh_svcstatus(self):
        self.svcstatus = self.svc.group_status(excluded_groups=set(["sync", 'hb']))

    def get_svcstatus(self):
        if len(self.svcstatus) == 0:
            self.refresh_svcstatus()

    def convert_wwid(self, wwid):
        s = ""
        for i, c in enumerate(wwid):
            s += c
            if (i+1) % 4 == 0: s += '-'
        return s.strip('-')

    def prereq(self):
        import ConfigParser
        if not which(self.sssubin):
            raise ex.excError("missing %s"%self.sssubin)
        if not os.path.exists(self.conf):
            raise ex.excError("missing %s"%self.conf)
        self.config = ConfigParser.RawConfigParser()
        self.config.read(self.conf)
        if not self.config.has_section(self.eva_name):
            raise ex.excError("no credentials for array %s in %s"%(self.eva_name, self.conf))
        if not self.config.has_option(self.eva_name, "manager"):
            raise ex.excError("no manager set for array %s in %s"%(self.eva_name, self.conf))
        if not self.config.has_option(self.eva_name, "username"):
            raise ex.excError("no username set for array %s in %s"%(self.eva_name, self.conf))
        if not self.config.has_option(self.eva_name, "password"):
            raise ex.excError("no password set for array %s in %s"%(self.eva_name, self.conf))
        self.manager = self.config.get(self.eva_name, "manager")
        self.username = self.config.get(self.eva_name, "username")
        self.password = self.config.get(self.eva_name, "password")
        for pair in self.pairs:
            if len(pair) != 3:
                raise ex.excError("syntax error in pair %s"%str(pair))
        ret, out = self.sssu(check=False)
        if "Error opening https connection" in out:
            raise ex.excError("error login to %s"%self.manager)
        elif "Error" in out:
            raise ex.excError("eva %s is not managed by %s"%(self.eva_name, self.manager))
        

    def __init__(self, rid=None, pairs=[], eva_name="",
                 sync_max_delay=None, sync_interval=None, sync_days=None,
                 sync_period=None,
                 optional=False, disabled=False, tags=set([]), internal=False):
        resSync.Sync.__init__(self, rid=rid, type="sync.evasnap",
                              sync_max_delay=sync_max_delay,
                              sync_interval=sync_interval,
                              sync_days=sync_days,
                              sync_period=sync_period,
                              optional=optional, disabled=disabled, tags=tags)

        self.label = "EVA snapshot %s"%(rid)
        self.eva_name = eva_name
        self.pairs = pairs
        self.sssubin = os.path.join(rcEnv.pathbin, 'sssu')
        self.conf = os.path.join(rcEnv.pathetc, 'sssu.conf')
        self._lun_info = {}

    def __str__(self):
        return "%s eva_name=%s evasnap_masking=%s pairs=%s" % (Res.Resource.__str__(self),\
                self.eva_name, self.evasnap_masking, str(self.pairs))

 07070100067203000081a40000000000000000000000014d9d7e6e0000072c000000b600010002ffffffffffffffff0000002100000000root/opt/opensvc/lib/rcPkgAIX.py  #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
from rcUtilities import call, which
from rcGlobalEnv import rcEnv

def listpkg_dummy():
    print "pushpkg supported on this system"
    return []

def listpkg_rpm():
    (ret, out) = call(cmd, errlog=False, cache=True)
    lines = []
    for line in out.split('\n'):
        l = line.split()
        if len(l) != 3:
            continue
        x = [rcEnv.nodename] + l
        lines.append(x)
    return lines

def listpkg_deb():
    (ret, out) = call(cmd, errlog=False, cache=True)
    lines = []
    arch = ""
    for line in out.split('\n'):
        l = line.split()
        if len(l) < 4:
            continue
        if l[0] != "ii":
            continue
        x = [rcEnv.nodename] + l[1:3] + [arch]
        lines.append(x)
    return lines

if which('dpkg') is not None:
    cmd = ['dpkg', '-l']
    listpkg = listpkg_deb
elif which('rpm') is not None:
    cmd = ['rpm', '-qa', '--queryformat=%{n} %{v}-%{r} %{arch}\n']
    listpkg = listpkg_rpm
else:
    cmd = ['true']
    listpkg = listpkg_dummy

def listpatch():
    return [] 
0707010006722d000081a40000000000000000000000014d9d7e6e00000786000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/resIpFreeBSD.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.
"Module implement Linux specific ip management"

import resIp as Res
import rcExceptions as ex
from rcUtilitiesFreeBSD import check_ping

class Ip(Res.Ip):
    def check_ping(self):
        return check_ping(self.addr)

    def arp_announce(self):
        return

    def startip_cmd(self):
        if ':' in self.addr:
            if '.' in self.mask:
                self.log.error("netmask parameter is mandatory for ipv6 adresses")
                raise ex.excError
            cmd = ['ifconfig', self.ipDev, 'inet6', '/'.join([self.addr, self.mask]), 'add']
        else:
            cmd = ['ifconfig', self.ipDev, 'inet', self.addr, 'netmask', self.mask, 'add']
        return self.vcall(cmd)

    def stopip_cmd(self):
        if ':' in self.addr:
            cmd = ['ifconfig', self.ipDev, 'inet6', self.addr, 'delete']
        else:
            cmd = ['ifconfig', self.ipDev, 'inet', self.addr, 'delete']
        return self.vcall(cmd)



if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

  070701000671f9000081a40000000000000000000000014d9d7e6e000008d9000000b600010002ffffffffffffffff0000002100000000root/opt/opensvc/lib/rcLogger.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import sys
import logging
import logging.handlers
from rcGlobalEnv import *

def initLogger(name):
    log = logging.getLogger(name)
    name_width = len(name) + 8

    """Common log formatter
    """
    fileformatter = logging.Formatter("%(asctime)s - %(name)s - %(levelname)s - %(message)s")
    streamformatter = logging.Formatter("%(asctime)s %(levelname)-7s %(name)-"+str(name_width)+"s %(message)s", datefmt="%H:%M:%S")

    """Common logfile with rotation
    """
    filehandler = logging.handlers.RotatingFileHandler(rcEnv.logfile,
                                                       maxBytes=5242880,
                                                       backupCount=5)
    filehandler.setFormatter(fileformatter)
    log.addHandler(filehandler)

    """Stdout logger
    """
    streamhandler = logging.StreamHandler()
    streamhandler.setFormatter(streamformatter)
    log.addHandler(streamhandler)

    try:
        log.setLevel(rcEnv.loglevel)
    except:
        pass

    if '--debug' in sys.argv:
            rcEnv.loglevel = logging.DEBUG
            log.setLevel(logging.DEBUG)
    elif '--warn' in sys.argv:
            rcEnv.loglevel = logging.WARNING
            log.setLevel(logging.WARNING)
    elif '--error' in sys.argv:
            rcEnv.loglevel = logging.ERROR
            log.setLevel(logging.ERROR)
    else:
            rcEnv.loglevel = logging.INFO
            log.setLevel(logging.INFO)

    return log
   0707010006721b000081a40000000000000000000000014d9d7e6e00000d76000000b600010002ffffffffffffffff0000002100000000root/opt/opensvc/lib/resAppVm.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from subprocess import *
import os
import glob

from rcGlobalEnv import rcEnv
from rcUtilities import qcall, justcall
import resApp
import rcStatus
import rcExceptions as ex

class Apps(resApp.Apps):
    app_d = os.path.join(os.sep, 'svc', 'etc', 'init.d')

    def set_perms(self, rc):
        (ret, out) = self.call(self.prefix+['/usr/bin/find',
                                            self.app_d,
                                            '-name', os.path.basename(rc),
                                            '-a', '-user', 'root',
                                            '-a', '-group', 'root'])
        if len(out) == 0 or rc != out.split()[0]:
            self.vcall(self.prefix+['chown', 'root:root', rc])
        (ret, out) = self.call(self.prefix+['test', '-x', rc])
        if ret != 0:
            self.vcall(self.prefix+['chmod', '+x', rc])

    def checks(self, verbose=False):
        container = self.svc.resources_by_id["container"]
        if container.status(refresh=True) != rcStatus.UP:
            self.log.debug("abort resApp action because container status is %s"%rcStatus.status_str(container.status()))
            self.status_log("container is %s"%rcStatus.status_str(container.status()))
            raise ex.excNotAvailable
        cmd = self.prefix + ['/bin/pwd']
        ret = qcall(cmd)
        if ret != 0:
            self.log.debug("abort resApp action because container is unreachable")
            self.status_log("container is unreachable")
            return False
        cmd = self.prefix + ['test', '-d', self.app_d]
        ret = qcall(cmd)
        if ret == 0:
            return True
        cmd = self.prefix + ['/bin/mkdir', '-p', self.app_d]
        ret = self.vcall(cmd)
        if ret != 0:
            return False
        return True

    def stop_checks(self):
        return self.checks()

    def start_checks(self):
        return self.checks()

    def status_checks(self, verbose=False):
        return self.checks(verbose=verbose)

    def sorted_app_list(self, pattern):
        cmd = self.prefix + ['/usr/bin/find', self.app_d, '-name', pattern]
        p = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
        buff = p.communicate()
        if p.returncode != 0:
            return []
        return sorted(buff[0].split('\n'))

    def app_exist(self, name):
        """ verify app_exists inside Vm
        """
        (out, err, ret) = justcall (self.prefix + ['/bin/ls', '-Ld', name ])
        if ret == 0:
            return True
        else:
            return False

if __name__ == "__main__":
    for c in (Apps,) :
        help(c)
  07070100067209000081a40000000000000000000000014d9d7e6e00000f28000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/rcStats.py   #!/usr/bin/python2.6
#
# Copyright (c) 2011 Christophe Varoqui <christophe.varoqui@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import os
import datetime

class StatsProvider(object):
    def __init__(self, interval=2880, stats_dir=None, stats_start=None, stats_end=None):
        self.stats_dir = stats_dir
        self.interval = interval

        if stats_end is None:
            self.stats_end = datetime.datetime.now()
        else:
            self.stats_end = datetime.datetime.strptime(stats_end,"%Y-%m-%d %H:%M")

        if stats_start is None:
            self.stats_start = self.stats_end - datetime.timedelta(minutes=interval)
        else:
            self.stats_start = datetime.datetime.strptime(stats_start,"%Y-%m-%d %H:%M")
            delta = self.stats_end - self.stats_start
            interval = delta.days * 1440 + delta.seconds // 60

        x, self.nodename, x, x, x = os.uname()

        self.minutes_first_day = 60*self.stats_end.hour + self.stats_end.minute + 1

        one_minute = datetime.timedelta(minutes=1)
        one_day = datetime.timedelta(days=1)
        self.ranges = []
        i = 0
        end = self.stats_end

        while end > self.stats_start:
            start = end - one_day
            if start < self.stats_start:
                start = self.stats_start
            if start.day != end.day:
                start = end - datetime.timedelta(hours=end.hour, minutes=end.minute)
            if start != end:
                self.ranges.append((start, end))
            end = start - one_minute
        #print self.stats_end, interval, map(lambda x: map(lambda y: y.strftime("%d-%m-%y %H:%M"), x), self.ranges)

    def get(self, fname):
        lines = []
        cols = []
        for start, end in self.ranges:
            date = start.strftime("%Y-%m-%d")
            day = start.strftime("%d")
            start = start.strftime("%H:%M:%S")
            end = end.strftime("%H:%M:%S")
            _cols, _lines = getattr(self, fname)(date, day, start, end)
            if len(_cols) == 0 or len(_lines) == 0:
                continue
            cols = _cols
            lines += _lines
        return cols, lines

    def sarfile(self, day):
        if self.stats_dir is None:
            stats_dir = os.path.join(os.sep, 'var', 'log', 'sysstat')
            if not os.path.exists(stats_dir):
                stats_dir = os.path.join(os.sep, 'var', 'log', 'sa')
        else:
            stats_dir = self.stats_dir
        f = os.path.join(stats_dir, 'sa'+day)
        if os.path.exists(f):
            return f
        return None

    def cpu(self, d, day, start, end):
        return [], []

    def mem_u(self, d, day, start, end):
        return [], []

    def proc(self, d, day, start, end):
        return [], []

    def swap(self, d, day, start, end):
        return [], []

    def block(self, d, day, start, end):
        return [], []

    def blockdev(self, d, day, start, end):
        return [], []

    def netdev(self, d, day, start, end):
        return [], []

    def netdev_err(self, d, day, start, end):
        return [], []

if __name__ == "__main__":
    sp = StatsProvider(interval=20)
    print sp.get('cpu')
    print sp.get('swap')
07070100067216000081a40000000000000000000000014d9d7e6e00000101000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/lib/rcUtilitiesHP-UX.py  from rcUtilities import call

def check_ping(addr, timeout=5, count=1):
    cmd = ['ping', addr,
                   '-n', repr(count),
                   '-m', repr(timeout)]
    (ret, out) = call(cmd)
    if ret == 0:
        return True
    return False

   070701000671fa000081a40000000000000000000000014d9d7e6e0000078d000000b600010002ffffffffffffffff0000002100000000root/opt/opensvc/lib/rcMounts.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

class Mount:
    def __init__(self, dev, mnt, type, mnt_opt):
        self.dev = dev
        self.mnt = mnt
        self.type = type
        self.mnt_opt = mnt_opt

    def __str__(self):
        return "Mount: dev[%s] mnt[%s] type[%s] options[%s]" % \
            (self.dev,self.mnt,self.type,self.mnt_opt)

class Mounts:
    def __init__(self):
        """ OS dependent """
        self.mounts = []

    def match_mount(self):
        """ OS dependent """
        pass

    def mount(self, dev, mnt):
        for i in self.mounts:
            if self.match_mount(i, dev, mnt):
                return i
        return None

    def has_mount(self, dev, mnt):
        for i in self.mounts:
            if self.match_mount(i, dev, mnt):
                return True
        return False

    def has_param(self, param, value):
        for i in self.mounts:
            if getattr(i, param) == value:
                return i
        return None

    def __str__(self):
        output="%s" % (self.__class__.__name__)
        for m in self.mounts:
            output+="\n  %s" % m.__str__()
        return output
   07070100067257000081a40000000000000000000000014d9d7e6e000029e7000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/lib/resources.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import rcExceptions as exc
import rcStatus
import logging
import rcUtilities
from rcGlobalEnv import rcEnv

class Resource(object):
    """Define basic resource
    properties: type, optional=optional, disabled=disabled, tags=tags
    a Resource should provide do_action(action):
    with action into (start/stop/status)
    """
    label = None

    def __init__(self, rid=None, type=None, optional=False, disabled=False,
                 tags=set([])):
        self.rid = rid
        self.tags = tags
        self.type = type
        self.optional = optional
        self.disabled = disabled
        self.log = logging.getLogger(str(rid).upper())
        self.rstatus = None
        self.always_on = set([])
        if self.label is None: self.label = type
        self.status_log_str = ""

    def __str__(self):
        output="object=%s rid=%s type=%s" % (self.__class__.__name__,
                                             self.rid, self.type)
        if self.optional : output+=" opt="+str(self.optional)
        if self.disabled : output+=" disa="+str(self.disabled)
        return output

    def __cmp__(self, other):
        """resources needed to be started or stopped in a specific order
        should redefine that. For now consider all resources of a set equals
        """
        return 0

    def setup_environ(self):
        """ setup environement variables for use by triggers and startup
            scripts. This method needs defining in each class with their
            class variable.
            Env vars names should, by convention, be prefixed by OPENSVC_
        """
        pass

    def is_optional(self): return self.optional
    def is_disabled(self): return self.disabled

    def set_optional(self): self.optional=True
    def unset_optional(self): self.optional=False

    def disable(self): self.disabled=True
    def enable(self):  self.disabled=False

    def action_triggers(self, type, action):
        attr = type+"_"+action
        if hasattr(self, attr):
            self.vcall(getattr(self, attr))

    def do_action(self, action):
        self.log.debug('do_action: action=%s res=%s'%(action, self.rid))
        if hasattr(self, action):
            if "stop" in action and rcEnv.nodename in self.always_on and not self.svc.force:
                if hasattr(self, action+'standby'):
                    getattr(self, action+'standby')()
                    return
                else:
                    self.log.info("skip '%s' on standby resource (--force to override)"%action)
                    return
            self.setup_environ()
            self.action_triggers("pre", action)
            getattr(self, action)()
            self.action_triggers("post", action)
            if "start" in action or "stop" in action or "sync" in action:
                """ refresh resource status cache after changing actions
                """
                self.status(refresh=True)
            return

        """Every class inheriting resource should define start() stop() status()
        Alert on these minimal implementation requirements
        """
        if action in ("start","stop","status") :
            raise exc.excUndefined(action,self.__class__.__name__,\
                                    "Resource.do_action")

    def action(self, action=None):
        """ action() try to call do_action() on self
        return if action is not None or if self is disabled
        return status depends on optional property value:
        if self is optional then return True
        else return do_action() return value
        """
        self.log.debug('action: action=%s res=%s'%(action, self.rid))
        if action == None:
            self.log.debug('action: action cannot be None')
            return True
        if self.disabled:
            self.log.debug('action: skip action on disable resource')
            return True
        try :
            self.do_action(action)
        except exc.excUndefined , ex:
            print ex
            return False
        except exc.excError:
            if self.optional:
                pass
            else:
                raise exc.excError

    def status_stdby(self, s):
        """ This function modifies the passed status according
            to this node inclusion in the always_on nodeset
        """
        if rcEnv.nodename not in self.always_on:
            return s
        if s == rcStatus.UP:
            return rcStatus.STDBY_UP
        elif s == rcStatus.DOWN:
            return rcStatus.STDBY_DOWN
        return s

    def _status(self, verbose=False):
        return rcStatus.UNDEF

    def status(self, verbose=False, refresh=False):
        if self.disabled:
            self.status_log("disabled")
            return rcStatus.NA
        if self.rstatus is None or refresh:
            self.status_log_str = ""
            self.rstatus = self._status(verbose)
        return self.rstatus

    def status_log(self, text):
        self.status_log_str += "# " + text

    def status_quad(self):
        r = self.status(verbose=True)
        return (self.rid, rcStatus.status_str(r), self.label, self.status_log_str)

    def call(self, cmd=['/bin/false'], cache=False, info=False,
             errlog=True, err_to_warn=False, err_to_info=False,
             outlog=False):
        """Use subprocess module functions to do a call
        """
        return rcUtilities.call(cmd, log=self.log,
                                cache=cache,
                                info=info, errlog=errlog,
                                err_to_warn=err_to_warn,
                                err_to_info=err_to_info,
                                outlog=outlog)

    def vcall(self, cmd, err_to_warn=False, err_to_info=False):
        """Use subprocess module functions to do a call and
        log the command line using the resource logger
        """
        return rcUtilities.vcall(cmd, log=self.log,
                                 err_to_warn=err_to_warn,
                                 err_to_info=err_to_info)

    def disklist(self):
        """List disks the resource holds. Some resource have none,
        and can leave this function as is.
        """
        return set()

    def presync(self):
        pass

    def postsync(self):
        pass

    def files_to_sync(self):
        return []

class ResourceSet(Resource):
    """ Define Set of same type resources
    Example 1: ResourceSet("fs",[m1,m2])
    Example 2: r=ResourceSet("fs",[ip1])
    It define the resource type
    """
    def __init__(self, type=None, resources=[],
                 optional=False, disabled=False, tags=set([])):
        self.resources = []
        Resource.__init__(self, type=type,
                          optional=optional, disabled=disabled, tags=tags)
        for r in resources:
            self += r

    def __iadd__(self,r):
        """Example 1 iadd another ResourceSet: R+=ResSet ... R+=[m1,m2]
        Example 2 : iadd a single Resource : R+=ip1
        """
        if isinstance(r,ResourceSet) :
            self.resources.extend(r.resources)
        elif isinstance(r,Resource) :
            """ Setup a back pointer to the resource set
            """
            r.rset = self
            self.resources.append(r)
            if hasattr(r, 'pre_action'):
                r.log.debug("install pre_action")
                self.pre_action = r.pre_action
            if hasattr(r, 'post_action'):
                r.log.debug("install post_action")
                self.post_action = r.post_action
        return (self)

    def __str__(self):
        output="resSet %s [" % ( Resource.__str__(self) )
        for r in self.resources:
            output+= " (%s)" % (r.__str__())
        return "%s]" % (output)

    def pre_action(self, rset=None, action=None):
        pass

    def post_action(self, rset=None, action=None):
        pass

    def status(self, verbose=False):
        """aggregate status a ResourceSet
        """
        s = rcStatus.Status()
        for r in self.resources:
            if r.is_disabled():
                continue
            try:
                status = r.status()
            except:
                import sys
                import traceback
                e = sys.exc_info()
                print e[0], e[1], traceback.print_tb(e[2])

                status = rcStatus.NA

            s += status
        return s.status

    def tag_match(self, rtags, keeptags):
        if len(keeptags) == 0:
            return True
        for tag in rtags:
            if tag in keeptags:
                return True
        return False

    def action(self, action=None, tags=set([])):
        """Call action on each resource of the ResourceSet
        """
        resources = [r for r in self.resources if self.tag_match(r.tags, tags)]
        self.log.debug("resources after tags[%s] filter: %s"%(str(tags), str(resources)))
        if action in ["fs", "start", "startstandby"]:
            resources.sort()
        else:
            resources.sort(reverse=True)

        for r in resources:
            try:
                r.action(action)
            except exc.excAbortAction:
                break


if __name__ == "__main__":
    for c in (Resource,ResourceSet) :
        help(c)
    print """m1=Resource("Type1")"""
    m1=Resource("Type1")
    print "m1=",m1
    print """m2=Resource("Type1")"""
    m2=Resource("Type1")
    print "m1=",m1
    print "m2=",m2
    print """sets=ResourceSet("TypeRes2")"""
    sets=ResourceSet("TypeRes2")
    print "sets=", sets
    print """sets+=m1"""
    sets+=m1
    print "sets=", sets
    print """sets+=m2"""
    sets+=m2
    print "sets=", sets


 07070100067258000081a40000000000000000000000014d9d7e6e00001401000000b600010002ffffffffffffffff0000001d00000000root/opt/opensvc/lib/snap.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import resources as Res
import rcExceptions as ex


def find_mount(rs, dir):
    """Sort mounts from deepest to shallowest and return the
       first mount whose 'mountPoint' is matching 'dir'
    """
    for m in sorted(rs.resources, reverse=True):
        if m.is_disabled():
            continue
        if m.mountPoint in dir:
            return m
    return None

def find_mounts(self, mounts_h):
    rs = self.svc.get_res_sets("fs")[0]
    if rs is None:
        self.log.error("can not find fs resources encapsulating %s to snap (no fs resources)"%self.src)
        raise ex.syncNotSnapable
    for src in self.src:
        m = find_mount(rs, src)
        if m is None:
            self.log.error("can not find fs resources encapsulating %s to snap"%src)
            raise ex.syncNotSnapable
        mounts_h[src] = m
    return mounts_h

class Snap(Res.Resource):
    """Defines a snap object
    """
    def __init__(self, rid, optional=False, disabled=False, tags=set([])):
        self.snaps = {}
        Res.Resource.__init__(self, rid, "sync.snap", optional=optional,\
                            disabled=disabled, tags=tags)

    def try_snap(self, rset, action, rid=None):
        if action == "nodes":
            action = "syncnodes"
        if action == "drpnodes":
            action = "syncdrp"

        mounts_h = {}
        for r in rset.resources:
            """ if rid is set, snap only the specified resource.
                Used by resources tagged 'delay_snap' on sync()

                if rid is not set, don't snap resources tagged 'delay_snap'
                (pre_action() code path)
            """
            if rid is None:
                if "delay_snap" in r.tags:
                    continue
            elif rid != r.rid:
                continue

            if r.is_disabled():
                continue

            if r.snap is not True and r.snap is not False:
                self.log.error("service configuration error: 'snap' must be 'true' or 'false'. default is 'false'")
                raise ex.syncConfigSyntaxError

            if not r.snap:
                continue

            if (action == "syncnodes" and not 'nodes' in r.target) or \
               (action == "syncdrp" and not 'drpnodes' in r.target):
                self.log.debug("action %s but resource target is %s"%(action, r.target))
                continue

            mounts_h = find_mounts(r, mounts_h)

        mounts = set(mounts_h.values())
        for m in mounts:
            try:
                self.snapcreate(m)
            except ex.syncNotSnapable:
                self.log.error("Resource not snapable: "+m.__str__())
                continue
            except (ex.syncNotSnapable, ex.syncSnapExists, ex.syncSnapMountError,
                ex.syncSnapCreateError, ex.syncSnapDestroyError):
                """Clean up the mess
                """
                self.snap_cleanup(self.snaps)
                raise ex.excError
            except:
                raise

        """Update src dirs of every sync resource to point to an
           existing snap
        """
        for i, r in enumerate(rset.resources):
            r.alt_src = list(r.src)
            for j, src in enumerate(r.alt_src):
                if not mounts_h.has_key(src):
                    continue
                mnt = mounts_h[src].mountPoint
                if not self.snaps.has_key(mnt):
                    continue
                snap_mnt = self.snaps[mnt]['snap_mnt']
                rset.resources[i].alt_src[j] = src.replace(os.path.join(mnt), os.path.join(snap_mnt), 1)

    def snap_cleanup(self, rset):
        if not hasattr(self, 'snaps'):
            return
        snaps = self.snaps
        if len(snaps) == 0 :
            return
        for s in snaps.keys():
            self.snapdestroykey(s)
        for i, r in enumerate(rset.resources):
            if hasattr(rset.resources[i], 'alt_src'):
                delattr(rset.resources[i], 'alt_src')

    def snapcreate(self, m):
        """ create a snapshot for m
        add self.snaps[m] with
            dict(snapinfo key val)
        """
        raise ex.MissImpl

    def snapdestroykey(self, snaps_key):
        """ destroy a snapshot for a snap key
        """
        raise ex.MissImpl

   07070100067240000081a40000000000000000000000014d9d7e6e00000ecc000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/resMountHP-UX.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import os

import rcStatus
from rcGlobalEnv import rcEnv
rcMounts = __import__('rcMounts'+rcEnv.sysname)
import resMount as Res
from rcUtilities import qcall, protected_mount
import rcExceptions as ex

def try_umount(self):
    cmd = ['umount', self.mountPoint]
    (ret, out) = self.vcall(cmd)
    if ret == 0:
        return 0

    """ don't try to kill process using the source of a
        protected bind mount
    """
    if protected_mount(self.mountPoint):
        return 1

    """ best effort kill of all processes that might block
        the umount operation. The priority is given to mass
        action reliability, ie don't contest oprator's will
    """
    cmd = ['sync']
    (ret, out) = self.vcall(cmd)

    for i in range(4):
        cmd = ['fuser', '-kc', self.mountPoint]
        (ret, out) = self.vcall(cmd)
        self.log.info('umount %s'%self.mountPoint)
        cmd = ['umount', self.mountPoint]
        ret = qcall(cmd)
        if ret == 0:
            break

    return ret


class Mount(Res.Mount):
    """ define HP-UX mount/umount doAction """
    def __init__(self, rid, mountPoint, device, fsType, mntOpt,
                 snap_size=None, always_on=set([]),
                 disabled=False, tags=set([]), optional=False):
        self.Mounts = rcMounts.Mounts()
        Res.Mount.__init__(self, rid, mountPoint, device, fsType, mntOpt,
                           snap_size, always_on,
                           disabled=disabled, tags=tags, optional=optional)
        self.fsck_h = {
            'vxfs': {'bin': 'fsck', 'cmd': ['fsck', '-F', 'vxfs', '-y', self.device]},
        } 

    def is_up(self):
        return self.Mounts.has_mount(self.device, self.mountPoint)

    def start(self):
        Res.Mount.start(self)
        if self.is_up() is True:
            self.log.info("fs(%s %s) is already mounted"%
                (self.device, self.mountPoint))
            return 0
        self.fsck()
        if not os.path.exists(self.mountPoint):
            os.makedirs(self.mountPoint, 0755)
        if self.fsType != "":
            fstype = ['-F', self.fsType]
        else:
            fstype = []
        if self.mntOpt != "":
            mntopt = ['-o', self.mntOpt]
        else:
            mntopt = []
        cmd = ['mount']+fstype+mntopt+[self.device, self.mountPoint]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def stop(self):
        if self.is_up() is False:
            self.log.info("fs(%s %s) is already umounted"%
                    (self.device, self.mountPoint))
            return 0
        for i in range(3):
            ret = try_umount(self)
            if ret == 0: break
        if ret != 0:
            self.log.error('failed to umount %s'%self.mountPoint)
            raise ex.excError

if __name__ == "__main__":
    for c in (Mount,) :
        help(c)

0707010006720e000081a40000000000000000000000014d9d7e6e000024b8000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/rcStatsLinux.py  #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2011 Christophe Varoqui <christophe.varoqui@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import os
import datetime
from rcUtilities import call, which
import rcStats

class StatsProvider(rcStats.StatsProvider):
    def cpu(self, d, day, start, end):
        f = self.sarfile(day)
        if f is None:
            return [], []
        cmd = ['sar', '-t', '-u', 'ALL', '-P', 'ALL', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd, errlog=False)
        if ret != 0:
            cmd = ['sar', '-t', '-u', '-P', 'ALL', '-f', f, '-s', start, '-e', end]
            (ret, buff) = call(cmd)
        cols = []
        lines = []
        for line in buff.split('\n'):
            l = line.split()
            if 'Linux' in l:
                continue
            if len(l) == 7:
                """ redhat 4
                    18:50:01 CPU %user %nice %system %iowait %idle
                """
		cols = ['date',
			'cpu',
			'usr',
			'nice',
			'sys',
			'iowait',
			'idle',
			'nodename']
            elif len(l) == 8:
                """ redhat 5
                    05:20:01 CPU %user %nice %system %iowait %steal %idle
                """
       		cols = ['date',
			'cpu',
			'usr',
			'nice',
			'sys',
			'iowait',
			'steal',
			'idle',
			'nodename']
            elif len(l) == 11:
		cols = ['date',
			'cpu',
			'usr',
			'nice',
			'sys',
			'iowait',
			'steal',
			'irq',
			'soft',
			'guest',
			'idle',
			'nodename']
            else:
                continue
            if l[1] == 'CPU':
                continue
            if l[0] == 'Average:':
                continue
            l.append(self.nodename)
            l[0] = '%s %s'%(d, l[0])
            lines.append(l)
        return cols, lines

    def mem_u(self, d, day, start, end):
        f = self.sarfile(day)
        cols = ['date',
                'kbmemfree',
                'kbmemused',
                'pct_memused',
                'kbbuffers',
                'kbcached',
                'kbcommit',
                'pct_commit',
                'kbmemsys',
                'nodename']

        if f is None:
            return [], []
        cmd = ['sar', '-t', '-r', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd)
        lines = []
        for line in buff.split('\n'):
           l = line.split()
           if len(l) == 10:
               """ redhat 5
               """
               l = l[0:6] + ['0', '0']
           if len(l) != 8:
               continue
           if l[1] == 'kbmemfree':
               continue
           if l[0] == 'Average:':
               continue

           """ Linux has no kbmemsys
           """
           l.append('0')

           l.append(self.nodename)
           l[0] = '%s %s'%(d, l[0])
           lines.append(l)
        return cols, lines

    def proc(self, d, day, start, end):
        f = self.sarfile(day)
        cols = ['date',
                'runq_sz',
                'plist_sz',
                'ldavg_1',
                'ldavg_5',
                'ldavg_15',
                'nodename']

        if f is None:
            return [], []
        cmd = ['sar', '-t', '-q', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd)
        lines = []
        for line in buff.split('\n'):
           l = line.split()
           if len(l) != 6:
               continue
           if l[1] == 'runq-sz':
               continue
           if l[0] == 'Average:':
               continue
           l.append(self.nodename)
           l[0] = '%s %s'%(d, l[0])
           lines.append(l)
        return cols, lines

    def swap(self, d, day, start, end):
        f = self.sarfile(day)
        cols = ['date',
                'kbswpfree',
                'kbswpused',
                'pct_swpused',
                'kbswpcad',
                'pct_swpcad',
                'nodename']

        if f is None:
            return [], []
        cmd = ['sar', '-t', '-S', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd, errlog=False)
        if ret != 0:
            """ redhat 5
            """
            cmd = ['sar', '-t', '-r', '-f', f, '-s', start, '-e', end]
            (ret, buff) = call(cmd)
        lines = []
        for line in buff.split('\n'):
           l = line.split()
           if len(l) == 10:
               """ redhat 5
               """
               l = [l[0]] + l[6:] + ['0']
           if len(l) != 6:
               continue
           if 'kbswpfree'in l:
               continue
           if l[0] == 'Average:':
               continue
           l.append(self.nodename)
           l[0] = '%s %s'%(d, l[0])
           lines.append(l)
        return cols, lines

    def block(self, d, day, start, end):
        f = self.sarfile(day)
        cols = ['date',
                'tps',
                'rtps',
                'wtps',
                'rbps',
                'wbps',
                'nodename']

        if f is None:
            return [], []
        cmd = ['sar', '-t', '-b', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd)
        lines = []
        for line in buff.split('\n'):
           l = line.split()
           if len(l) != 6:
               continue
           if l[1] == 'tps':
               continue
           if l[0] == 'Average:':
               continue
           l.append(self.nodename)
           l[0] = '%s %s'%(d, l[0])
           lines.append(l)
        return cols, lines

    def blockdev(self, d, day, start, end):
        f = self.sarfile(day)
        cols = ['date',
                'dev',
                'tps',
                'rsecps',
                'wsecps',
                'avgrq_sz',
                'avgqu_sz',
                'await',
                'svctm',
                'pct_util',
                'nodename']
        if f is None:
            return [], []
        cmd = ['sar', '-t', '-d', '-p', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd, errlog=False)
        lines = []
        for line in buff.split('\n'):
           l = line.split()
           if len(l) != 10:
               continue
           if l[1] == 'DEV':
               continue
           if l[0] == 'Average:':
               continue
           l.append(self.nodename)
           l[0] = '%s %s'%(d, l[0])
           lines.append(l)
        return cols, lines

    def netdev(self, d, day, start, end):
        f = self.sarfile(day)
        cols = ['date',
                'dev',
                'rxpckps',
                'txpckps',
                'rxkBps',
                'txkBps',
                'nodename']

        if f is None:
            return [], []
        cmd = ['sar', '-t', '-n', 'DEV', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd, errlog=False)
        lines = []
        div = 1
        for line in buff.split('\n'):
           l = line.split()
           if len(l) != 9:
               continue
           if l[1] in ['IFACE', 'lo'] :
               if 'rxbyt/s' in l:
                   div = 1024
               continue
           if 'dummy' in l[1] or 'vnet' in l[1] or 'veth' in l[1] or \
              'pan'   in l[1] or 'sit'  in l[1]:
               continue
           if l[0] == 'Average:':
               continue
           m = l[0:3]
           m.append(str(float(l[4])/div))
           m.append(str(float(l[5])/div))
           m.append(l[6])
           m.append(self.nodename)
           m[0] = '%s %s'%(d, l[0])
           lines.append(m)
        return cols, lines


    def netdev_err(self, d, day, start, end):
        f = self.sarfile(day)
        cols = ['date',
                'dev',
                'rxerrps',
                'txerrps',
                'collps',
                'rxdropps',
                'txdropps',
                'nodename']

        if f is None:
            return [], []
        cmd = ['sar', '-t', '-n', 'EDEV', '-f', f, '-s', start, '-e', end]
        (ret, buff) = call(cmd, errlog=False)
        lines = []
        for line in buff.split('\n'):
           l = line.split()
           if len(l) != 11:
               continue
           if l[1] in ['IFACE', 'lo'] :
               continue
           if 'dummy' in l[1] or 'vnet' in l[1] or 'veth' in l[1] or \
              'pan'   in l[1] or 'sit'  in l[1]:
               continue
           if l[0] == 'Average:':
               continue
           l = l[0:7]
           l.append(self.nodename)
           l[0] = '%s %s'%(d, l[0])
           lines.append(l)
        return cols, lines

if __name__ == "__main__":
    sp = StatsProvider(interval=20)
    print sp.get('cpu')
    print sp.get('swap')
07070100067269000081a40000000000000000000000014d9d7e6e0000114b000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/svcZone.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

__author__="cgaliber"
__date__ ="$11 oct. 2009 21:56:59$"

import svc
import resContainerZone as Zone

class SvcZone(svc.Svc):
    """ Define Zone services"""

    def __init__(self, svcname, vmname=None, guestos=None, optional=False, disabled=False, tags=set([])):
        svc.Svc.__init__(self, svcname, type="container.zone",
            optional=optional, disabled=disabled, tags=tags)
        if vmname is None:
            vmname = svcname
        self.vmname = vmname
        self.guestos = guestos
        self.zone = Zone.Zone(vmname)
        self += self.zone
        self.runmethod = [ '/usr/sbin/zlogin', '-S', vmname ]

    def start(self):
        """start a zone
        check ping
        zone ready
        start ips
        start zone
        start VGs
        start fs
        start apps
        """
        self.sub_set_action("ip", "check_ping")
        self.sub_set_action("disk.scsireserv", "start", tags=set(['preboot']))
        self.sub_set_action("disk.vg", "start", tags=set(['preboot']))
        self.sub_set_action("disk.zpool", "start", tags=set(['preboot']))
        self.sub_set_action("fs", "start", tags=set(['preboot']))
        self.sub_set_action("container.zone", "attach")
        self.sub_set_action("container.zone", "ready")
        self.sub_set_action("ip", "start")
        self.sub_set_action("container.zone", "boot")
        self.sub_set_action("sync.netapp", "start", tags=set(['postboot']))
        self.sub_set_action("disk.scsireserv", "start", tags=set(['postboot']))
        self.sub_set_action("disk.vg", "start", tags=set(['postboot']))
        self.sub_set_action("disk.zpool", "start", tags=set(['postboot']))
        self.sub_set_action("fs", "start")
        self.sub_set_action("app", "start")

    def stop(self):
        """stop a zone:
        stop apps
        stop fs
        stop VGs
        stop zone
        stop ips
        """
        self.sub_set_action("app", "stop")
        self.sub_set_action("fs", "stop", tags=set(['postboot']))
        self.sub_set_action("disk.vg", "stop", tags=set(['postboot']))
        self.sub_set_action("disk.zpool", "stop", tags=set(['postboot']))
        self.sub_set_action("disk.scsireserv", "stop", tags=set(['postboot']))
        self.sub_set_action("container.zone", "stop")
        self.sub_set_action("container.zone", "detach")
        self.sub_set_action("fs", "stop", tags=set(['preboot']))
        self.sub_set_action("disk.vg", "stop", tags=set(['preboot']))
        self.sub_set_action("disk.zpool", "stop", tags=set(['preboot']))
        self.sub_set_action("disk.scsireserv", "stop", tags=set(['preboot']))
        self.sub_set_action("ip", "stop")

    def startip(self):
        self.sub_set_action("ip", "check_ping")
        self.sub_set_action("ip", "start")


if __name__ == "__main__":
    for c in (SvcZone,) :
        help(c)
    import mountSunOS as mount
    import ipSunOS as ip
    print """
    Z=SvcZone()
    Z+=mount.Mount("/mnt1","/dev/sda")
    Z+=mount.Mount("/mnt2","/dev/sdb")
    Z+=ip.Ip("eth0","192.168.0.173")
    Z+=ip.Ip("eth0","192.168.0.174")
    """

    Z=SvcZone()
    Z+=mount.Mount("/mnt1","/dev/sda")
    Z+=mount.Mount("/mnt2","/dev/sdb")
    Z+=ip.Ip("eth0","192.168.0.173")
    Z+=ip.Ip("eth0","192.168.0.174")

    print "Show Z: ", Z
    print "start Z:"
    Z.start()

    print "stop Z:"
    Z.stop()

 07070100067226000081a40000000000000000000000014d9d7e6e00000a93000000b600010002ffffffffffffffff0000001e00000000root/opt/opensvc/lib/resDg.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@opensvc.com>
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@opensvc.com>
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.
"""Module providing Generic device group resources
"""

import resources as Res
import rcStatus
import rcExceptions as exc
from rcGlobalEnv import rcEnv

class Dg(Res.Resource):
    """ basic Dg resource, must be extend for LVM / Veritas / ZFS
    """
    def __init__(self, rid=None, name=None, type=None,
                 always_on=set([]), optional=False,
                 disabled=False, tags=set([])):
        Res.Resource.__init__(self, rid, type,
                              optional=optional, disabled=disabled, tags=tags)
        self.name = name
        self.always_on = always_on
        self.disks = set()

    def __str__(self):
        return "%s name=%s" % (Res.Resource.__str__(self), self.name)

    def disklist(self):
        return self.disks

    def has_it(self): return False
    def is_up(self): return False
    def do_start(self): return False
    def do_stop(self): return False

    def stop(self):
        self.do_stop()

    def start(self):
        self.do_start()

    def startstandby(self):
        if rcEnv.nodename in self.always_on:
             self.start()

    def _status(self, verbose=False):
        if rcEnv.nodename in self.always_on:
            if self.is_up(): return rcStatus.STDBY_UP
            else: return rcStatus.STDBY_DOWN
        else:
            if self.is_up(): return rcStatus.UP
            else: return rcStatus.DOWN

if __name__ == "__main__":
    for c in (Dg,) :
        help(c)

    print """d=Dg("aGenericDg")"""
    d=Dg("aGenericDg")
    print "show d", d
    print """d.do_action("start")"""
    d.do_action("start")
    print """d.do_action("stop")"""
    d.do_action("stop")
 07070100067218000081a40000000000000000000000014d9d7e6e000000c3000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/lib/rcUtilitiesSunOS.py  from rcUtilities import call

def check_ping(addr, timeout=5, count=1):
    cmd = ['ping', addr, "%s" % timeout]
    (ret, out) = call(cmd)
    if ret == 0:
        return True
    return False

 0707010006721a000081a40000000000000000000000014d9d7e6e00001f2c000000b600010002ffffffffffffffff0000001f00000000root/opt/opensvc/lib/resApp.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from subprocess import *
from datetime import datetime
import os
import glob
import sys

from rcUtilities import justcall
from rcGlobalEnv import rcEnv
import resources as Res
import rcStatus
import rcExceptions as ex

class Apps(Res.Resource):
    prefix = []

    def __init__(self, runmethod=[], optional=False, disabled=False, tags=set([])):
        Res.Resource.__init__(self, rid="app", type="app",
                              optional=optional, disabled=disabled, tags=tags) 
        self.prefix = runmethod
        self.label = "app"

    def set_perms(self, rc):
        s = os.stat(rc)
        if s.st_uid != 0 or s.st_gid != 0:
            self.log.info("set %s ownership to uid 0 gid 0"%rc)
            os.chown(rc, 0, 0)
        (ret, out) = self.call(self.prefix+['test', '-x', rc])
        if ret != 0: 
            self.vcall(self.prefix+['chmod', '+x', rc])

    def stop_checks(self):
        if not os.path.exists(self.svc.initd):
            self.log.info("%s is not present, perhaps already stopped"
                            %self.svc.initd)
            return True
        elif not os.path.islink(self.svc.initd):
            self.log.error("%s is not a link"%self.svc.initd)
            return False
        return True

    def start_checks(self):
        if not os.path.exists(self.svc.initd):
            self.log.error("%s is not present"%self.svc.initd)
            return False
        elif not os.path.islink(self.svc.initd):
            self.log.error("%s is not a link"%self.svc.initd)
            return False
        return True

    def startstandby_checks(self):
        if not os.path.exists(self.svc.initd):
            self.log.info("%s is not present, no apps to start for standby"%self.svc.initd)
            return False
        elif not os.path.islink(self.svc.initd):
            self.log.error("%s is not a link"%self.svc.initd)
            return False
        return True

    def status_checks(self, verbose=False):
        if not os.path.exists(self.svc.initd):
            if verbose: self.status_log("%s does not exist"%self.svc.initd)
            return False
        status = self.svc.group_status(excluded_groups=set(["sync", "app", "disk", "hb"]))
        if str(status["overall"]) != "up":
            self.log.debug("abort resApp status because ip+fs status is %s"%status["overall"])
            if verbose: self.status_log("ip+fs status is %s, skip check"%status["overall"])
            return False
        return True

    def app_exist(self, name):
        if os.path.exists(name):
            return True
        else:
            return False

    def app(self, name, action, dedicated_log=True):
        if len(name) == 0:
            return 0
        if not self.app_exist(name):
            return 0

        self.set_perms(name)
        cmd = self.prefix+[name, action]
        try:
            if dedicated_log:
                self.log.info('spawn: %s' % ' '.join(cmd))
                outf = os.path.join(rcEnv.pathtmp, 'svc_'+self.svc.svcname+'_'+os.path.basename(name)+'.log')
                f = open(outf, 'w')
                t = datetime.now()
                p = Popen(cmd, stdin=None, stdout=f.fileno(), stderr=f.fileno())
                p.communicate()
                _len = datetime.now() - t
                self.log.info('%s done in %s - ret %d - logs in %s' % (action, _len, p.returncode, outf))
                f.close()
                return p.returncode
            else:
                (out, err, ret) = justcall(cmd)
                self.log.debug("%s returned out=[%s], err=[%s], ret=[%d]"%(cmd, out, err, ret))
                return ret
        except OSError, e:
            if e.errno == 8:
                self.log.error("%s execution error (Exec format error)"%name)
                return 1
            else:
                self.svc.save_exc()
                return 1
        except:
           self.svc.save_exc()
           return 1

    def sorted_app_list(self, pattern):
        return sorted(glob.glob(os.path.join(self.svc.initd, pattern)))

    def _status(self, verbose=False):
        """Execute each startup script (C* files). Log the return code but
           don't stop on error. Count errors.
        """
        rets = {}
        errs = 0
        nb = 0
        try:
            if not self.status_checks(verbose=verbose):
                return rcStatus.NA
        except ex.excNotAvailable:
                return rcStatus.NA
        for name in self.sorted_app_list('C*'):
            if len(name) == 0:
                continue
            ret = self.app(name, 'status', dedicated_log=False)
            nb += 1
            errs += ret
            rets[name] = ret
        if nb == 0:
            self.status_log("no startup script")
            return rcStatus.NA
        elif errs == 0:
            return rcStatus.UP
        elif errs > 0:
            names = ', '.join([n for n in rets if rets[n] != 0 ])
            self.status_log("%s returned errors"%(names))
            return rcStatus.WARN
        else:
            return rcStatus.DOWN

    def startstandby(self):
        """Execute each startup script (SS* files). Log the return code but
           don't stop on error.
        """
        try:
            if not self.startstandby_checks():
                raise ex.excError
        except ex.excNotAvailable:
            return
        for name in self.sorted_app_list('S*.standby@'+rcEnv.nodename):
            self.app(name, 'start')

    def containerize(self):
        if self.svc.containerize:
            return
        try:
            container = __import__('rcContainer'+rcEnv.sysname)
        except ImportError:
            self.log.info("containerization not supported")
            return
        container.containerize(self)

    def start(self):
        from multiprocessing import Process, Queue
        p = Process(target=self.start_job, args=())
        p.start()
        p.join()
        if p.exitcode != 0:
            raise ex.excError

    def start_job(self):
        """Execute each startup script (S* files). Log the return code but
           don't stop on error.
        """
        #
        # this bug should have be fixed, but it is not the case with python
        # 2.6.2 we ship for el5.
        # it manifests as apache failing to spawn workers because they can't
        # acquire stdin, closed upon thread startup.
        #
        sys.stdin = open(os.devnull)

        try:
            if not self.start_checks():
                sys.exit(1)
        except ex.excNotAvailable:
            return
        if self.svc.containerize:
            self.containerize()
        for name in self.sorted_app_list('S*'):
            self.app(name, 'start')

    def stop(self):
        """Execute each shutdown script (K* files). Log the return code but
           don't stop on error.
        """
        try:
            if not self.stop_checks():
                raise ex.excError
        except ex.excNotAvailable:
            return
        for name in self.sorted_app_list('K*'):
            self.app(name, 'stop')

if __name__ == "__main__":
    for c in (Apps,) :
        help(c)
07070100067204000081a40000000000000000000000014d9d7e6e000006e5000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/rcPkgDarwin.py   #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
from rcUtilities import call, which
from rcGlobalEnv import rcEnv

"""
format:

package-id: com.apple.pkg.X11User
version: 10.6.0.1.1.1238328574
volume: /
location: /
install-time: 1285389505
groups: com.apple.snowleopard-repair-permissions.pkg-group com.apple.FindSystemFiles.pkg-group 
"""

def pkgversion(package):
    cmd = ['pkgutil', '--pkg-info', package]
    (ret, out) = call(cmd, errlog=False, cache=True)
    for line in out.split('\n'):
        l = line.split(': ')
        if len(l) != 2:
            continue
        if l[0] == 'version':
            return l[1]
    return ''

def listpkg():
    if which('pkgutil') is None:
        return []
    cmd = ['pkgutil', '--packages']
    (ret, out) = call(cmd, errlog=False, cache=True)
    lines = []
    for line in out.split('\n'):
        if len(line) == 0:
            continue
        x = [rcEnv.nodename, line, pkgversion(line), ""]
        lines.append(x)
    return lines

def listpatch():
    return []

   070701000671ed000081a40000000000000000000000014d9d7e6e00000a47000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/lib/rcIfconfigDarwin.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

from subprocess import *

import rcIfconfig

class ifconfig(rcIfconfig.ifconfig):
    def parse(self, out):
        prev = ''
        prevprev = ''
        for w in out.split():
            if 'flags=' in w:
                i = rcIfconfig.interface(prev.replace(':',''))
                self.intf.append(i)

                # defaults
                i.link_encap = ''
                i.scope = ''
                i.bcast = ''
                i.mtu = ''
                i.ipaddr = []
                i.mask = []
                i.ip6addr = []
                i.ip6mask = []
                i.hwaddr = ''
                i.flag_up = False
                i.flag_broadcast = False
                i.flag_running = False
                i.flag_multicast = False
                i.flag_loopback = False

                flags = w.split('<')[1].split('>')[0].split(',')
                if 'UP' in flags:
                    i.flag_up = True
                if 'BROADCAST' in flags:
                    i.flag_broadcast = True
                if 'RUNNING' in flags:
                    i.flag_running = True
                if 'MULTICAST' in flags:
                    i.flag_multicast = True
                if 'LOOPBACK' in flags:
                    i.flag_loopback = True
            elif 'inet' == prev:
                i.ipaddr += [w]
            elif 'inet6' == prev:
                i.ip6addr += [w.split('%')[0]]
            elif 'netmask' == prev:
                i.mask += [w]
            elif 'prefixlen' == prev:
                i.ip6mask += [w]
            elif 'ether' == prev:
                i.hwaddr = w

            prevprev = prev
            prev = w

    def __init__(self):
        self.intf = []
        out = Popen(['ifconfig', '-a'], stdout=PIPE).communicate()[0]
        self.parse(out)
 07070100067246000081a40000000000000000000000014d9d7e6e000014fd000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/resSync.py   #
# Copyright (c) 2011 Christophe Varoqui <christophe.varoqui@opensvc.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import logging

import rcExceptions as ex
import resources as Res
import datetime
import time
from rcGlobalEnv import rcEnv

class Sync(Res.Resource):
    def __init__(self, rid=None, sync_max_delay=None,
                 sync_interval=None, sync_period=None, sync_days=None,
                 optional=False, disabled=False, tags=set([]),
                 type=type):
        if sync_max_delay is None:
            self.sync_max_delay = 1500
        else:
            self.sync_max_delay = sync_max_delay

        if sync_interval is None:
            self.sync_interval = 1439
        else:
            self.sync_interval = sync_interval

        if sync_period is None:
            self.sync_period = ["04:00", "06:00"]
        else:
            self.sync_period = sync_period

        if sync_days is None:
            self.sync_days = ["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]
        else:
            self.sync_days = sync_days

        Res.Resource.__init__(self, rid=rid, type=type,
                              optional=optional, disabled=disabled, tags=tags)

    def check_timestamp(self, ts=None, comp='more', delay=10):
        """ Return False if timestamp is fresher than now-interval
            Return True otherwize.
            Zero is a infinite interval
        """
        if ts is None:
            raise
        if delay == 0:
            raise
        limit = ts + datetime.timedelta(minutes=delay)
        if comp == "more" and datetime.datetime.now() < limit:
            return False
        elif comp == "less" and datetime.datetime.now() < limit:
            return False
        else:
            return True
        return True

    def in_period(self):
        if len(self.sync_period) == 0:
            return True
        if isinstance(self.sync_period[0], list):
            r = False
            for p in self.sync_period:
                 r |= self.in_period(p)
            return r
        elif (not isinstance(self.sync_period[0], unicode) and \
              not isinstance(self.sync_period[0], str)) or \
             len(self.sync_period) != 2 or \
             (not isinstance(self.sync_period[1], unicode) and \
              not isinstance(self.sync_period[1], str)):
            self.log.error("malformed period: %s"%str(self.sync_period))
            return False
        start_s, end_s = self.sync_period
        start_t = time.strptime(start_s, "%H:%M")
        end_t = time.strptime(end_s, "%H:%M")
        start = start_t.tm_hour * 60 + start_t.tm_min
        end = end_t.tm_hour * 60 + end_t.tm_min
        try:
            start_t = time.strptime(start_s, "%H:%M")
            end_t = time.strptime(end_s, "%H:%M")
            start = start_t.tm_hour * 60 + start_t.tm_min
            end = end_t.tm_hour * 60 + end_t.tm_min
        except:
            self.log.error("malformed time string: %s"%str(self.sync_period))
            return False
        now = datetime.datetime.now()
        now_m = now.hour * 60 + now.minute
        if start <= end:
            if now_m >= start and now_m <= end:
                return True
        elif start > end:
            """
                  XXXXXXXXXXXXXXXXX
                  23h     0h      1h
            """
            if (now_m >= start and now_m <= 1440) or \
               (now_m >= 0 and now_m <= end):
                return True
        return False

    def in_days(self):
        now = datetime.datetime.now()
        today = now.strftime('%A').lower()
        if today in map(lambda x: x.lower(), self.sync_days):
            return True
        return False

    def skip_sync(self, ts):
        if self.svc.force:
            return False
        if self.sync_interval == 0:
            self.log.debug('skip sync: disabled by sync_interval = 0')
            return True
        if not self.in_days():
            self.log.debug('skip sync: not in allowed days (%s)'%str(self.sync_days))
            return True
        if not self.in_period():
            self.log.debug('skip sync: not in allowed period (%s)'%str(self.sync_period))
            return True
        if ts is None:
            self.log.debug("don't skip sync: no timestamp")
        elif not self.check_timestamp(ts, comp="less", delay=self.sync_interval):
            self.log.debug('skip sync: too soon (%d)'%self.sync_interval)
            return True
        return False

    def alert_sync(self, ts):
        if ts is None:
            return True
        if not self.check_timestamp(ts, comp="less", delay=self.sync_max_delay):
            return False
        return True
   070701000671e0000081a40000000000000000000000014d9d7e6e0000138d000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/lib/rcContainerLinux.py  import os
import rcExceptions as ex
from rcUtilities import justcall

default_cgroup_mntpt = '/cgroup'

def get_cgroup_mntpt():
    (out,err,ret) = justcall(['mount'])
    if ret != 0:
        return None
    for line in out.split('\n'):
        l = line.split()
        if len(l) < 6:
            continue
        if l[4] == 'cgroup':
            return l[2]
    return None

def cgroup_capable(res):
    kconf = os.path.join(os.sep, 'lib', 'modules',
                         os.uname()[2], 'build', '.config')
    if not os.path.exists(kconf):
        kconf = os.path.join(os.sep, 'boot', 'config-'+os.uname()[2])
    if not os.path.exists(kconf):
        res.log.info("can not detect if system supports containerization")
        return False
    with open(kconf, 'r') as f:
        for line in f.readlines():
            l = line.split('=')
            if len(l) != 2:
                continue
            if l[0] == 'CONFIG_CGROUPS' and l[1] == 'y\n':
                return True
    res.log.info("system does not support containerization")
    return False

def set_cgroup(res, name, value):
    if value is None:
        return
    path = os.path.join(res.cgroup, name)
    if not os.path.exists(path):
        res.log.error("can not find %s"%path)
        raise ex.excError
    res.log.info('/bin/echo %s > %s'%(value, path))
    with open(path, 'w') as f:
        f.write(str(value))

def get_cgroup(res, name):
    path = os.path.join(res.cgroup, name)
    if not os.path.exists(path):
        res.log.error("can not find %s"%path)
        raise ex.excError
    with open(path, 'r') as f:
        buff = f.read()
    return buff

def set_mem_cgroup(res):
    if hasattr(res.svc, 'container_mem_limit'):
        mem_limit = int(res.svc.container_mem_limit)
    else:
        mem_limit = None

    if hasattr(res.svc, 'container_vmem_limit'):
        vmem_limit = int(res.svc.container_vmem_limit)
    else:
        vmem_limit = None

    #
    # validate memory limits sanity and order adequately the resize
    # depending on increase/decrease of limits
    #
    if mem_limit is not None and vmem_limit is not None:
        if mem_limit > vmem_limit:
            res.log.error("container_vmem_limit must be greater than container_mem_limit")
            raise ex.excError
        cur_vmem_limit = int(get_cgroup(res, 'memory.memsw.limit_in_bytes'))
        if mem_limit > cur_vmem_limit:
            set_cgroup(res, 'memory.memsw.limit_in_bytes', vmem_limit)
            set_cgroup(res, 'memory.limit_in_bytes', mem_limit)
        else:
            set_cgroup(res, 'memory.limit_in_bytes', mem_limit)
            set_cgroup(res, 'memory.memsw.limit_in_bytes', vmem_limit)
    elif mem_limit is not None:
        cur_vmem_limit = int(get_cgroup(res, 'memory.memsw.limit_in_bytes'))
        if mem_limit > cur_vmem_limit:
            res.log.error("container_mem_limit must not be greater than current container_vmem_limit (%d)"%cur_vmem_limit)
            raise ex.excError
        set_cgroup(res, 'memory.limit_in_bytes', mem_limit)
    elif vmem_limit is not None:
        cur_mem_limit = int(get_cgroup(res, 'memory.limit_in_bytes'))
        if vmem_limit < cur_mem_limit:
            res.log.error("container_vmem_limit must not be lesser than current container_mem_limit (%d)"%cur_mem_limit)
            raise ex.excError
        set_cgroup(res, 'memory.memsw.limit_in_bytes', vmem_limit)

def containerize(res):
    if res.svc.svcmode == 'lxc':
        return
    if not cgroup_capable(res):
        return

    cgroup_mntpt = get_cgroup_mntpt()
    if cgroup_mntpt is None:
        cgroup_mntpt = default_cgroup_mntpt
        if not os.path.exists(cgroup_mntpt):
            res.log.info('mkdir %s'%cgroup_mntpt)
            os.makedirs(cgroup_mntpt)
        (ret, out) = res.vcall(['mount', '-t', 'cgroup', 'none', cgroup_mntpt])
        if ret != 0:
            raise ex.excError

    res.cgroup = os.path.join(cgroup_mntpt, res.svc.svcname)
    if not os.path.exists(res.cgroup):
        os.makedirs(res.cgroup)

    if hasattr(res.svc, 'container_cpus'):
        v_cpus = str(res.svc.container_cpus)
    else:
        # default to all cpus
        import multiprocessing
        v_cpus = '0-%d'%(multiprocessing.cpu_count()-1)

    if hasattr(res.svc, 'container_mems'):
        v_mems = str(res.svc.container_mems)
    else:
        # default to all mems
        v_mems = '0'

    if hasattr(res.svc, 'container_cpu_share'):
        cpu_share = res.svc.container_cpu_share
    else:
        cpu_share = None

    pid = os.getpid()

    try:
        set_cgroup(res, 'cpuset.cpus', v_cpus)
        set_cgroup(res, 'cpu.shares', cpu_share)
        set_cgroup(res, 'cpuset.mems', v_mems)
        set_mem_cgroup(res)
        set_cgroup(res, 'tasks', pid)
    except:
        res.log.error("containerization in '%s' cgroup failed"%res.svc.svcname)
        raise ex.excError
    res.log.info("containerized in '%s' cgroup, with limits cpu[%s], mem[%s]:"%(res.svc.svcname, v_cpus, v_mems))
   0707010006721c000081a40000000000000000000000014d9d7e6e00001678000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/resContainer.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import rcStatus
import resources as Res
import time
import rcExceptions as ex
from rcUtilities import qcall
from rcGlobalEnv import rcEnv
import socket

class Container(Res.Resource):
    """ in seconds
    """
    startup_timeout = 600
    shutdown_timeout = 60

    def __init__(self, name, rid=None, type=None, optional=False, disabled=False, tags=set([])):
        Res.Resource.__init__(self, rid=rid, type=type,
                              optional=optional, disabled=disabled, tags=tags)
        self.sshbin = '/usr/bin/ssh'
        self.name = name
        self.label = name

    def getaddr(self):
        if hasattr(self, 'addr'):
            return
        try:
            a = socket.getaddrinfo(self.name, None)
            if len(a) == 0:
                raise Exception
            self.addr = a[0][4][0]
        except:
            if not disabled:
                raise ex.excInitError

    def __str__(self):
        return "%s name=%s" % (Res.Resource.__str__(self), self.name)

    def operational(self):
        if self.svc.guestos == "Windows":
            """ Windows has no sshd.
            """
            return True
        timeout = 1
        cmd = [ self.sshbin, '-o', 'StrictHostKeyChecking=no',
                                '-o', 'ForwardX11=no',
                                '-o', 'BatchMode=yes',
                                '-n',
                                '-o', 'ConnectTimeout='+repr(timeout),
                                self.name, 'pwd']
        ret = qcall(cmd)
        if ret == 0:
            return True
        return False

    def wait_for_fn(self, fn, tmo, delay):
        for tick in range(tmo//2):
            if fn():
                return
            time.sleep(delay)
        self.log.error("Waited too long for startup")
        raise ex.excError

    def wait_for_startup(self):
        self.log.info("wait for container up status")
        self.wait_for_fn(self.is_up, self.startup_timeout, 2)
        if hasattr(self, 'ping'):
            self.log.info("wait for container ping")
            self.wait_for_fn(self.ping, self.startup_timeout, 2)
        self.log.info("wait for container operational")
        self.wait_for_fn(self.operational, self.startup_timeout, 2)

    def wait_for_shutdown(self):
        self.log.info("wait for container down status")
        for tick in range(self.shutdown_timeout):
            if self.is_down():
                return
            time.sleep(1)
        self.log.error("Waited too long for shutdown")
        raise ex.excError

    def install_drp_flag(self):
        print "TODO: install_drp_flag()"

    def start(self):
        try:
            self.getaddr()
        except:
            self.log.error("could not resolve %s to an ip address"%self.name)
            raise ex.excError
        if self.is_up():
            self.log.info("container %s already started" % self.name)
            return
        if rcEnv.nodename in self.svc.drpnodes:
            self.install_drp_flag()
        self.container_start()
        self.wait_for_startup()

    def stop(self):
        try:
            self.getaddr()
        except:
            self.log.error("could not resolve %s to an ip address"%self.name)
            raise ex.excError
        if self.is_down():
            self.log.info("container %s already stopped" % self.name)
            return
        self.container_stop()
        try:
            self.wait_for_shutdown()
        except ex.excError:
            self.container_forcestop()
            self.wait_for_shutdown()

    def check_capabilities(self):
        #print "TODO: check_capabilities(self)"
        pass

    def container_start(self):
        print "TODO: container_start(self)"

    def container_stop(self):
        print "TODO: container_stop(self)"

    def container_forcestop(self):
        print "TODO: container_forcestop(self)"

    def check_manual_boot(self):
        print "TODO: check_manual_boot(self)"
        return False

    def is_up(self):
        return False

    def is_down(self):
        return not self.is_up()

    def _status(self, verbose=False):
        try:
            self.getaddr()
        except:
            self.status_log("could not resolve %s to an ip address"%self.name)
            return rcStatus.WARN
        if not self.check_capabilities():
            self.status_log("node capabilities do not permit this action")
            return rcStatus.WARN
        if not self.check_manual_boot():
            self.status_log("container auto boot is on")
            return rcStatus.WARN
        if self.is_up():
            return rcStatus.UP
        if self.is_down():
            return rcStatus.DOWN
        else:
            self.status_log("container status is neither up nor down")
            return rcStatus.WARN

    def get_container_info(self):
        print "TODO: get_container_info(self)"
        return {'vcpus': '0', 'vmem': '0'}
07070100067252000081a40000000000000000000000014d9d7e6e00000fd4000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/lib/resVgLdom.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import rcExceptions as ex
import rcStatus
resVg = __import__("resDg")
from subprocess import *
import re

class Vg(resVg.Dg):
    def __init__(self, rid=None, name=None, type=None,
                 optional=False, disabled=False, tags=set([])):
        self.label = name
        resVg.Dg.__init__(self, rid=rid, name=name,
                          type='disk.vg',
                          optional=optional, disabled=disabled, tags=tags)

    def has_it(self):
        return True

    def is_up(self):
        return True

    def _status(self, verbose=False):
        return rcStatus.NA

    def do_start(self):
        pass

    def do_stop(self):
        pass

    def disklist(self):
        """ VCC|name=vccname|...
            VDS|name=vdsname|...
            |vol=volname|..|dev=/dev/...|....
            |vol=volname1|..|dev=/dev/...|....
            VDS|name=vdsname1|..
            |vol=volname2|..|dev=/dev/...|....

            ldm list -o disk -p domname
            VERSION
            DOMAIN|..
            VDISK|name=...|vol=volname@vds|...
            VDISK|name=...|vol=volname2@vds2|...
            """
        vdevname2dev = {}

        cmd = [ '/usr/sbin/ldm', 'list-services' , '-p' ]
        p = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
        buff = p.communicate()
        if p.returncode != 0:
            raise ex.excError
        vds = ''
        for line in buff[0].split('\n'):
            keys = line.split('|')
            if keys[0] == 'VDS' and len(keys) > 1 :
                for k in keys :
                    name_value = k.split('=')
                    if name_value[0] == 'name' and len(name_value) == 2 :
                        vds = name_value[1]
            elif vds != '' and keys[0] == '':
                volname = ''
                dev = ''
                for k in keys :
                    name_value = k.split('=')
                    if name_value[0] == 'vol' and len(name_value) == 2 :
                        volname = name_value[1]
                    elif name_value[0] == 'dev' and len(name_value) == 2 :
                        dev = name_value[1]
                        if re.match('^/dev/dsk/', dev) is None:
                            continue
                        dev = dev.replace('/dev/dsk/','/dev/rdsk/',1)
                        if re.match('^.*s[0-9]$',dev) is None:
                            dev = dev + 's2'
                        vdevname2dev[volname + '@' + vds ] = dev
            else:
                vds = ''

        cmd = ['/usr/sbin/ldm', 'list', '-o', 'disk', '-p', self.svc.vmname]
        p = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
        buff = p.communicate()
        if p.returncode != 0:
            raise ex.excError
        for line in buff[0].split('\n'):
            keys = line.split('|')
            if keys[0] == 'VDISK' and len(keys) > 1 :
                for k in keys :
                    name_value = k.split('=')
                    if name_value[0] == 'vol' and len(name_value) == 2 :
                        vol = name_value[1]
                        if vdevname2dev.has_key(vol):
                            self.disks |= set([ vdevname2dev[vol] ])
        return self.disks
07070100067242000081a40000000000000000000000014d9d7e6e000014e8000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/resMountSunOS.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.
"Module implement SunOS specific mounts"

import os

import rcStatus
import rcMountsSunOS as rcMounts
import resMount as Res
import rcExceptions as ex
from rcZfs import zfs_getprop, zfs_setprop
from rcUtilities import justcall

class Mount(Res.Mount):
    """ define SunOS mount/umount doAction """
    def __init__(self, rid, mountPoint, device, fsType, mntOpt,
                 snap_size=None, always_on=set([]),
                 disabled=False, tags=set([]), optional=False):
        self.rdevice = device.replace('/dsk/','/rdsk/',1)
        self.Mounts = rcMounts.Mounts()
        Res.Mount.__init__(self, rid, mountPoint, device, fsType, mntOpt,
                           snap_size, always_on,
                           disabled=disabled, tags=tags, optional=optional)
        self.fsck_h = {
            'ufs': {'bin': 'fsck',
                    'cmd':       ['fsck', '-F', 'ufs', '-y', self.rdevice],
                    'reportcmd': ['fsck', '-F', 'ufs', '-m', self.rdevice],
                    'reportclean': [ 32 ],
            },
            'vxfs': {'bin': 'fsck',
                    'cmd':       ['fsck', '-F', 'vxfs', '-y', self.rdevice],
                    'reportcmd': ['fsck', '-F', 'vxfs', '-m', self.rdevice],
                    'reportclean': [ 32 ],
            },
        }

    def is_up(self):
        self.Mounts = rcMounts.Mounts()
        return self.Mounts.has_mount(self.device, self.mountPoint)

    def start(self):
        self.Mounts = None
        Res.Mount.start(self)

        if self.is_up() is True:
            self.log.info("fs(%s %s) is already mounted"%
                (self.device, self.mountPoint))
            return

        if self.fsType == 'zfs' :
            if zfs_getprop(self.device, 'mountpoint' ) != self.mountPoint :
                if zfs_setprop(self.device, 'zoned', 'off') :
                    if not zfs_setprop(self.device, 'mountpoint', self.mountPoint) :
                        raise ex.excError

            self.Mounts = None
            if self.is_up() is True:
                return

            (stdout,stderr,returncode)= justcall(['rm', self.mountPoint+"/.opensvc" ])
            ret, out = self.vcall(['zfs', 'mount', self.device ])
            if ret != 0:
                ret, out = self.vcall(['zfs', 'mount', '-O', self.device ])
                if ret != 0:
                    raise ex.excError
            return
        elif self.fsType != "":
            fstype = ['-F', self.fsType]
            self.fsck()
        else:
            fstype = []

        if self.mntOpt != "":
            mntopt = ['-o', self.mntOpt]
        else:
            mntopt = []

        if not os.path.exists(self.mountPoint):
            os.makedirs(self.mountPoint, 0755)
        cmd = ['mount']+fstype+mntopt+[self.device, self.mountPoint]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            self.Mounts = None
            raise ex.excError
        self.Mounts = None

    def try_umount(self):
        if self.fsType == 'zfs' :
            ret, out = self.vcall(['zfs', 'umount', self.device ])
            if ret != 0 :
                ret, out = self.vcall(['zfs', 'umount', '-f', self.device ])
                if ret != 0 :
                    raise ex.excError
            return
        (ret, out) = self.vcall(['umount', self.mountPoint], err_to_info=True)
        if ret == 0 :
            return
        for i in range(4):
            (ret, out) = self.vcall(['fuser', '-ck', self.mountPoint],
                                    err_to_info=True)
            (ret, out) = self.vcall(['umount', self.mountPoint],
                                    err_to_info=True)
            if ret == 0 :
                return
            if self.fsType != 'lofs' :
                (ret, out) = self.vcall(['umount', '-f', self.mountPoint],
                                        err_to_info=True)
                if ret == 0 :
                    return
        raise ex.excError

    def stop(self):
        self.Mounts = None
        if self.is_up() is False:
            self.log.info("fs(%s %s) is already umounted"%
                    (self.device, self.mountPoint))
            return

        try: 
            self.try_umount()
        except:
            self.Mounts = None
            self.log.error("failed")
            raise ex.excError
        self.Mounts = None

if __name__ == "__main__":
    for c in (Mount,) :
        help(c)

070701000671f1000081a40000000000000000000000014d9d7e6e000006d1000000b600010002ffffffffffffffff0000002c00000000root/opt/opensvc/lib/rcIfconfigHP-UXhpvm.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcExceptions as ex
from subprocess import *

rcIfconfig = __import__("rcIfconfigHP-UX")
from rcGlobalEnv import rcEnv

class ifconfig(rcIfconfig.ifconfig):
    def __init__(self, hostname):
        self.intf = []
        cmd = rcEnv.rsh.split(' ') + [hostname, 'netstat', '-win']
        p = Popen(cmd, stdout=PIPE)
        buff = p.communicate()[0]
        if p.returncode != 0:
            raise ex.excError
        intf_list = buff
        for line in intf_list.split('\n'):
            if len(line) == 0:
                continue
            intf = line.split()[0]
            cmd = rcEnv.rsh.split(' ') + [hostname, 'env', 'LANG=C', 'ifconfig', intf]
            p = Popen(cmd, stdout=PIPE, stderr=PIPE)
            out = p.communicate()
            if "no such interface" in out[1]:
                continue
            elif p.returncode != 0:
                raise ex.excError
            self.parse(out[0])
   070701000671df000081a40000000000000000000000014d9d7e6e00000da0000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/rcAssetSunOS.py  #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import datetime
from rcUtilities import call, which
from rcGlobalEnv import rcEnv
import rcAsset

class Asset(rcAsset.Asset):
    def __init__(self, node):
        rcAsset.Asset.__init__(self, node)
        (ret, out) = call(['prtconf'])
        if ret != 0:
            self.prtconf = []
        else:
            self.prtconf = out.split('\n')

    def get_mem_bytes(self):
        for l in self.prtconf:
            if 'Memory size:' in l:
                return l.split(':')[-1].split()[0]
        return '0'

    def get_mem_banks(self):
        return '0'

    def get_mem_slots(self):
        return '0'

    def get_os_vendor(self):
        return 'Oracle'

    def get_os_name(self):
        f = '/etc/release'
        if os.path.exists(f):
            (ret, out) = call(['cat', f])
            if ret != 0:
                return 'Unknown'
            if 'OpenSolaris' in out:
                return 'OpenSolaris'
        return 'SunOS'

    def get_os_release(self):
        f = '/etc/release'
        if os.path.exists(f):
            (ret, out) = call(['cat', f])
            if ret != 0:
                return 'Unknown'
            return out.split('\n')[0].replace('OpenSolaris','').strip()
        return 'Unknown'

    def get_os_kernel(self):
        (ret, out) = call(['uname', '-v'])
        if ret != 0:
            return 'Unknown'
        return out.split('\n')[0]

    def get_os_arch(self):
        (ret, out) = call(['uname', '-m'])
        if ret != 0:
            return 'Unknown'
        return out.split('\n')[0]

    def get_cpu_freq(self):
        (ret, out) = call(['psrinfo', '-pv'])
        if ret != 0:
            return '0'
        for w in out.split():
            if 'MHz)' in w:
                return ' '.join([prev, w.strip(')')])
            prev = w
        return '0'

    def get_cpu_cores(self):
        (ret, out) = call(['psrinfo'])
        if ret != 0:
            return '0'
        return str(len(out.split('\n'))-1)

    def get_cpu_dies(self):
        (ret, out) = call(['psrinfo', '-p'])
        if ret != 0:
            return '0'
        return out.split('\n')[0]

    def get_cpu_model(self):
        (ret, out) = call(['psrinfo', '-pv'])
        if ret != 0:
            return 'Unknown'
        lines = out.split('\n')
        if len(lines) < 3:
            return 'Unknown'
        return lines[2].strip()

    def get_serial(self):
        (ret, out) = call(['hostid'])
        if ret != 0:
            return 'Unknown'
        return out.split('\n')[0]

    def get_model(self):
        for l in self.prtconf:
            if 'System Configuration:' in l:
                return l.split(':')[-1].strip()
        return 'Unknown'

0707010006720a000081a40000000000000000000000014d9d7e6e000012f4000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/rcStatsAIX.py    #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import os
import datetime
from rcUtilities import call, which
from rcGlobalEnv import rcEnv

today = datetime.datetime.today()
yesterday = today - datetime.timedelta(days=1)

def sarfile(day):
    f = os.path.join(os.sep, 'var', 'adm', 'sa', 'sa'+day)
    if os.path.exists(f):
        return f
    return None

def twodays(fn):
    if which('sar') is None:
        return []
    lines = fn(yesterday)
    lines += fn(today)
    return lines

def stats_cpu():
    return twodays(stats_cpu_day)

def stats_cpu_day(t):
    d = t.strftime("%Y-%m-%d")
    day = t.strftime("%d")
    f = sarfile(day)
    if f is None:
        return []
    cmd = ['sar', '-u', '-P', 'ALL', '-f', f]
    (ret, buff) = call(cmd, errlog=False)
    lines = []
    for line in buff.split('\n'):
        l = line.split()
        if len(l) != 6:
            continue
        if l[1] == '%usr':
            continue
        if l[0] == 'Average':
            continue
        # SunOS:  date    %usr     %sys %wio                       %idle
        # xmlrpc: date cpu usr nice sys iowait steal irq soft guest idle nodename
        x = ['%s %s'%(d, l[0]), 'all', '0', '0', '0', '0', '0', '0', '0', '0', '0', rcEnv.nodename]
        x[1] = l[1].replace('-', 'all')
        x[2] = l[2]
        x[4] = l[3]
        x[5] = l[4]
        x[10] = l[5]
        lines.append(x)
    return lines

def stats_mem_u(file, collect_date=None):
    return twodays(stats_mem_u_day)

def stats_mem_u_day(t):
    return []

def stats_proc(file, collect_date=None):
    return twodays(stats_proc_day)

def stats_proc_day(t):
    d = t.strftime("%Y-%m-%d")
    day = t.strftime("%d")
    f = sarfile(day)
    if f is None:
        return []
    cmd = ['sar', '-q', '-f', f]
    (ret, buff) = call(cmd)
    lines = []
    for line in buff.split('\n'):
        l = line.split()
        if len(l) < 3:
            continue
        if ':' not in l[0]:
            continue
        """ xmlrpc: date runq_sz plist_sz ldavg_1 ldavg_5 ldavg_15 nodename
        """
        x = ['%s %s'%(d, l[0]), l[1], '0', '0', '0', '0', rcEnv.nodename]
        lines.append(x)
    return lines

def stats_swap(file, collect_date=None):
    return twodays(stats_swap_day)

def stats_swap_day(t):
    return []

def stats_block(file, collect_date=None):
    return twodays(stats_block_day)

def stats_block_day(t):
    d = t.strftime("%Y-%m-%d")
    day = t.strftime("%d")
    f = sarfile(day)
    if f is None:
        return []
    cmd = ['sar', '-b', '-f', f]
    (ret, buff) = call(cmd)
    lines = []
    for line in buff.split('\n'):
        l = line.split()
        if len(l) != 9:
            continue
        if ':' not in l[1]:
            continue

        """ xmlrpc: date tps rtps wtps rbps wbps nodename
        """
        x = ['%s %s'%(d, l[0]), '0', '0', '0', l[1], l[4], rcEnv.nodename]

        lines.append(x)
    return lines

def stats_blockdev(file, collect_date=None):
    return twodays(stats_blockdev_day)

def stats_blockdev_day(t):
    d = t.strftime("%Y-%m-%d")
    day = t.strftime("%d")
    f = sarfile(day)
    if f is None:
        return []
    cmd = ['sar', '-d', '-f', f]
    (ret, buff) = call(cmd, errlog=False)
    lines = []
    for line in buff.split('\n'):
        l = line.split()
        if len(l) == 8:
            date = l[0]
        if len(l) == 7:
            l = [date] + l
        if len(l) != 8:
            continue
        if l[1] == 'device':
            continue
        if l[0] == 'Average':
            continue
        """ xmlrpc: 22:05:01 DEV tps rd_sec/s wr_sec/s avgrq-sz avgqu-sz await svctm %util
                    00:00:00 device %busy avque r+w/s blks/s avwait avserv
        """
        x = ['%s %s'%(d, l[0]), l[1], l[4], '0', '0', '0', l[3], l[6], l[7], l[2], rcEnv.nodename]
        lines.append(x)
    return lines

def stats_netdev(file, collect_date=None):
    return twodays(stats_netdev_day)

def stats_netdev_day(t):
    return []

def stats_netdev_err(file, collect_date=None):
    return twodays(stats_netdev_err_day)

def stats_netdev_err_day(t):
    return []

070701000671cb000081a40000000000000000000000014d9d7e6e0000071c000000b600010002ffffffffffffffff0000002a00000000root/opt/opensvc/lib/checkFsUsageLinux.py #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import checks
from rcUtilities import justcall

class check(checks.check):
    chk_type = "fs_u"

    def find_svc(self, mountpt):
        for svc in self.svcs:
            for rs in svc.get_res_sets('fs'):
                for r in rs.resources:
                    if r.mountPoint == mountpt:
                        return svc.svcname
        return ''

    def do_check(self):
        cmd = ['df', '-lP']
        (out,err,ret) = justcall(cmd)
        if ret != 0:
            return self.undef
        lines = out.split('\n')
        if len(lines) < 2:
            return self.undef
        r = []
        for line in lines[1:]:
            l = line.split()
            if len(l) != 6:
                continue
            if l[5].startswith('/Volumes'):
                continue
            r.append({
                      'chk_instance': l[5],
                      'chk_value': l[4],
                      'chk_svcname': self.find_svc(l[5]),
                     })
        return r
07070100067227000081a40000000000000000000000014d9d7e6e000018d9000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/resDrbd.py   #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import os
import resources as Res
import rcStatus
import rcExceptions as ex
from rcUtilities import which, justcall
from rcGlobalEnv import rcEnv

class Drbd(Res.Resource):
    """ Drbd device resource

        The tricky part is that drbd devices can be used as PV
        and LV can be used as drbd base devices. Treat the ordering
        with 'prevg' and 'postvg' tags.

        Start 'ups' and promotes the drbd devices to primary.
        Stop 'downs' the drbd devices.
    """
    def __init__(self, rid=None, res=None, always_on=set([]),
                 optional=False, disabled=False, tags=set([])):
        Res.Resource.__init__(self, rid, "disk.drbd",
                              optional=optional, disabled=disabled, tags=tags)
        self.res = res
        self.label = res
        self.drbdadm = None
        self.always_on = always_on
        self.disks = set()
        if 'prevg' not in self.tags and 'postvg' not in self.tags:
            tags |= set(['postvg'])

    def __str__(self):
        return "%s resource=%s" % (Res.Resource.__str__(self),\
                                 self.res)

    def files_to_sync(self):
        cf = os.path.join(os.sep, 'etc', 'drbd.d', self.res+'.res')
        if os.path.exists(cf):
            return [cf]
        self.log.error("%s does not exist"%cf)
        return []

    def drbdadm_cmd(self, cmd):
        if self.drbdadm is None:
            if which('drbdadm'):
                self.drbdadm = 'drbdadm'
            else:
                self.log("drbdadm command not found")
                raise exc.excError
        return [self.drbdadm] + cmd.split() + [self.res]

    def disklist(self):
        if self.disks != set():
            return self.disks

        self.disks = set()
        devps = set()

        (ret, out) = self.call(self.drbdadm_cmd('dump-xml'))
        if ret != 0:
            raise ex.excError

        from xml.etree.ElementTree import XML, fromstring
        tree = fromstring(out)
        
        for res in tree.getiterator('resource'):
            if res.attrib['name'] != self.res:
                continue
            for host in res.getiterator('host'):
                if host.attrib['name'] != rcEnv.nodename:
                    continue
                d = host.find('disk')
                if d is None:
                    continue
                devps |= set([d.text])

        try:
            u = __import__('rcUtilities'+rcEnv.sysname)
            self.disks = u.devs_to_disks(self, devps)
        except:
            self.disks = devps

        return self.disks

    def drbdadm_down(self):
        (ret, out) = self.vcall(self.drbdadm_cmd('down'))
        if ret != 0:
            raise ex.excError

    def drbdadm_up(self):
        (ret, out) = self.vcall(self.drbdadm_cmd('up'))
        if ret != 0:
            raise ex.excError

    def get_cstate(self):
        self.prereq()
        (out, err, ret) = justcall(self.drbdadm_cmd('cstate'))
        if ret != 0:
            if "Device minor not allocated" in err:
                return "Unattached"
            else:
                raise ex.excError
        return out.strip()

    def prereq(self):
        if not os.path.exists("/proc/drbd"):
            (ret, out) = self.vcall(['modprobe', 'drbd'])
            if ret != 0: raise ex.excError

    def start_connection(self):
        cstate = self.get_cstate()
        if cstate == "Connected":
            self.log.info("drbd resource %s is already up"%self.res)
        elif cstate == "StandAlone":
            self.drbdadm_down()
            self.drbdadm_up()
        elif cstate == "WFConnection":
            self.log.info("drbd resource %s peer node is not listening"%self.res)
            pass
        else:
            self.drbdadm_up()

    def get_roles(self):
        (ret, out) = self.call(self.drbdadm_cmd('role'))
        if ret != 0:
            raise ex.excError
        out = out.strip().split('/')
        if len(out) != 2:
            raise ex.excError
        return out

    def start_role(self, role):
        roles = self.get_roles()
        if roles[0] != role:
            (ret, out) = self.vcall(self.drbdadm_cmd(role.lower()))
            if ret != 0:
                raise ex.excError
        else:
            self.log.info("drbd resource %s is already %s"%(self.res, role))

    def startstandby(self):
        self.start_connection()
        roles = self.get_roles()
        if roles[0] == "Primary":
            return
        self.start_role('Secondary')

    def stopstandby(self):
        self.start_connection()
        roles = self.get_roles()
        if roles[0] == "Secondary":
            return
        self.start_role('Secondary')

    def start(self):
        self.start_connection()
        self.start_role('Primary')

    def stop(self):
        self.drbdadm_down()

    def _status(self, verbose=False):
        (ret, out) = self.call(self.drbdadm_cmd('dstate'))
        if ret != 0:
            self.status_log("drbdadm dstate %s failed"%self.res)
            return rcStatus.WARN
        out = out.strip()
        if out == "UpToDate/UpToDate":
            return self.status_stdby(rcStatus.UP)
        elif out == "Unconfigured":
            return self.status_stdby(rcStatus.DOWN)
        self.status_log("unexpected drbd resource %s state: %s"%(self.res, out))
        return rcStatus.WARN

if __name__ == "__main__":
    help(Drbd)
    v = Drbd(res='test')
    print v

   0707010006722f000081a40000000000000000000000014d9d7e6e000005e8000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/lib/resIpHpVm.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

resIpHv = __import__("resIpHP-UX")
import resIpVm

class Ip(resIpVm.Ip, resIpHv.Ip):
    def __init__(self, rid=None, ipDev=None, ipName=None,
                 mask=None, always_on=set([]),
                 disabled=False, tags=set([]), optional=False):
        resIpVm.Ip.__init__(self, rid=rid, ipDev=ipDev, ipName=ipName,
                            mask=mask, always_on=always_on,
                            disabled=disabled, tags=tags, optional=optional)

    def check_ping(self):
        return resIpHv.Ip.check_ping(self)

if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

07070100067230000081a40000000000000000000000014d9d7e6e000005d7000000b600010002ffffffffffffffff0000002100000000root/opt/opensvc/lib/resIpKvm.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

resIpHv = __import__("resIpLinux")
import resIpVm

class Ip(resIpVm.Ip, resIpHv.Ip):
    def __init__(self, rid=None, ipDev=None, ipName=None, mask=None,
                 always_on=set([]), disabled=False, tags=set([]), optional=False):
        resIpVm.Ip.__init__(self, rid=rid, ipDev=ipDev, ipName=ipName,
                            mask=mask, always_on=always_on,
                            disabled=disabled, tags=tags, optional=optional)

    def check_ping(self):
        return resIpHv.Ip.check_ping(self)

if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

 07070100067220000081a40000000000000000000000014d9d7e6e000012f8000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/lib/resContainerLdom.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import resources as Res
import rcExceptions as ex
from rcUtilities import qcall
from rcUtilitiesSunOS import check_ping
import resContainer
from rcGlobalEnv import rcEnv
import os

class Ldom(resContainer.Container):
    def __init__(self, name, optional=False, disabled=False, tags=set([])):
        resContainer.Container.__init__(self, rid="ldom", name=name, type="container.ldom",
                                        optional=optional, disabled=disabled, tags=tags)
        self.shutdown_timeout = 240
        self.sshbin = '/usr/local/bin/ssh'


    def __str__(self):
        return "%s name=%s" % (Res.Resource.__str__(self), self.name)

    def files_to_sync(self):
        import glob
        a = []
        ldomf = os.path.join(rcEnv.pathvar, 'ldom_'+self.name+'.*')
        files = glob.glob(ldomf)
        if len(files) > 0:
            a += files
        return a

    def check_capabilities(self):
        cmd = ['/usr/sbin/ldm', 'list' ]
        (ret, out) = self.call(cmd)
        if ret != 0:
            return False
        return True

    def state(self):
        """ ldm state : None/inactive/bound/active
            ldm list -p domainname outputs:
                VERSION
                DOMAIN|[varname=varvalue]*
        """
        cmd = ['/usr/sbin/ldm', 'list', '-p', self.name]
        (ret, out) = self.call(cmd)
        if ret != 0:
            return None
        for word in out.split("|"):
            a=word.split('=')
            if len(a) == 2:
                if a[0] == 'state':
                    return a[1]
        return None

    def ping(self):
        return check_ping(self.addr)

    def container_action(self,action):
        cmd = ['/usr/sbin/ldm', action, self.name]
        (ret, buff) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError
        return None

    def container_start(self):
        """ ldm bind domain
            ldm start domain
        """
        state = self.state()
        if state == 'None':
            raise ex.excError
        if state == 'inactive':
            self.container_action('bind')
            self.container_action('start')
        if state == 'bound' :
            self.container_action('start')

    def container_forcestop(self):
        """ ldm unbind domain
            ldm stop domain
        """
        if self.state == 'active':
            try:
                self.container_action('stop')
            except ex.excError:
                pass
        self.container_action('unbind')

    def container_stop(self):
        """ launch init 5 into container
            wait_for_shutdown
            ldm stop domain
            ldm unbind domain
        """
        state = self.state()
        if state == 'None':
            raise ex.excError
        if state == 'inactive':
            return None
        if state == 'bound' :
            self.container_action('unbind')
        if state == 'active' :
            cmd = rcEnv.rsh.split() + [ self.name, '/usr/sbin/init', '5' ]
            (ret, buff) = self.vcall(cmd)
            if ret == 0:
                try:
                    self.log.info("wait for container shutdown")
                    self.wait_for_fn(self.is_shutdown, self.shutdown_timeout, 2)
                except ex.excError:
                    pass
            self.container_forcestop()

    def check_manual_boot(self):
        cmd = ['/usr/sbin/ldm', 'list-variable', 'auto-boot?', self.name]
        (ret, out) = self.call(cmd)
        if ret != 0:
            return False
        if out != 'auto-boot?=False' :
            return True
        self.log.info("Auto boot should be turned off")
        return False

    def is_shutdown(self):
        state = self.state()
        if state == 'inactive' or state == 'bound':
            return True
        return False

    def is_down(self):
        if self.state() == 'inactive':
            return True
        return False

    def is_up(self):
        if self.state() == 'active':
            return True
        return False

0707010006724e000081a40000000000000000000000014d9d7e6e00000b0a000000b600010002ffffffffffffffff0000002100000000root/opt/opensvc/lib/resVdisk.py  #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

""" Module providing device path remapping for libvirt VMs
"""

import resources as Res
import rcStatus
import rcExceptions as ex
from rcGlobalEnv import rcEnv

class Vdisk(Res.Resource):
    def __init__(self, rid=None, name=None, devpath={}, type=None,
                 always_on=set([]), optional=False,
                 disabled=False, tags=set([])):
        Res.Resource.__init__(self, rid, "disk.vdisk",
                              optional=optional, disabled=disabled, tags=tags)
        self.name = name
        self.always_on = always_on
        self.disks = set()
        self.devpath = devpath

    def __str__(self):
        return "%s name=%s" % (Res.Resource.__str__(self), self.name)

    def disklist(self):
        return self.disks

    def remap(self):
        path = self.devpath[rcEnv.nodename]
        paths = set(self.devpath.values()) - set(self.devpath[rcEnv.nodename])
        from xml.etree.ElementTree import ElementTree, SubElement
        tree = ElementTree()
        try:
            tree.parse(self.svc.resources_by_id['container'].cf)
        except:
            self.log.error("failed to parse %s"%self.svc.resources_by_id['container'].cf)
            raise ex.excError
        for dev in tree.getiterator('disk'):
            s = dev.find('source')
            if s is None:
                 continue
            il = s.items()
            if len(il) != 1:
                 continue
            attr, devp = il[0]
            if devp in paths:
                self.log.info("remapping device path: %s -> %s"%(devp,path))
                s.set('dev', path)
                #SubElement(dev, "source", {'dev': path})
                tree.write(self.svc.resources_by_id['container'].cf)

    def stop(self):
        pass

    def start(self):
        self.remap()

    def startstandby(self):
        pass

    def _status(self, verbose=False):
        return rcStatus.NA

  07070100067235000081a40000000000000000000000014d9d7e6e000005d5000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/lib/resIpVbox.py #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

from rcGlobalEnv import rcEnv
resIpHv = __import__("resIp"+rcEnv.sysname)
import resIpVm

class Ip(resIpVm.Ip, resIpHv.Ip):
    def __init__(self, rid=None, ipDev=None, ipName=None, mask=None,
                 always_on=set([]), disabled=False, tags=set([]),
                 optional=False):
        resIpVm.Ip.__init__(self, rid=rid, ipDev=ipDev, ipName=ipName,
                            mask=mask, always_on=always_on,
                            disabled=disabled, tags=tags, optional=optional)

    def check_ping(self):
        return resIpHv.Ip.check_ping(self)

if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

   0707010006725b000081a40000000000000000000000014d9d7e6e00000dd8000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/snapVxfsHP-UX.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os

from rcGlobalEnv import rcEnv
from rcUtilities import which, qcall, protected_mount
import rcExceptions as ex
import snap

class Snap(snap.Snap):
    def lv_exists(self, device):
        if qcall(['lvdisplay', device]) == 0:
            return True
        return False

    def lv_info(self, device):
        (ret, buff) = self.call(['lvdisplay', device])
        if ret != 0:
            return (None, None, None)
        vg_name = None
        lv_name = None
        lv_size = 0
        for line in buff.split('\n'):
            if "VG Name" in line:
                vg_name = line.split()[-1]
            if "LV Name" in line:
                lv_name = line.split()[-1]
            if "LV Size" in line:
                lv_size = int(line.split()[-1])
        return (vg_name, lv_name, lv_size)

    def snapcreate(self, m):
        snap_name = ''
        snap_mnt = ''
        (vg_name, lv_name, lv_size) = self.lv_info(m.device)
        if lv_name is None:
            self.log.error("can not snap %s: not a logical volume"%m.device)
            raise ex.syncNotSnapable
        snap_name = 'osvc_sync_'+os.path.basename(lv_name)
        if self.lv_exists(os.path.join(vg_name, snap_name)):
            self.log.error("snap of %s already exists"%(lv_name))
            raise ex.syncSnapExists
        (ret, buff) = self.vcall(['lvcreate', '-L', str(lv_size//10)+'M', '-n', snap_name, vg_name])
        if ret != 0:
            raise ex.syncSnapCreateError
        snap_mnt = '/service/tmp/osvc_sync_'+os.path.basename(vg_name)+'_'+os.path.basename(lv_name)
        if not os.path.exists(snap_mnt):
            os.makedirs(snap_mnt, 0755)
        snap_dev = os.path.join(vg_name, snap_name)
        (ret, buff) = self.vcall(['mount', '-F', 'vxfs', '-o', 'ro,snapof='+m.device, snap_dev, snap_mnt])
        if ret != 0:
            raise ex.syncSnapMountError
        self.snaps[m.mountPoint] = dict(lv_name=lv_name,
                                        vg_name=vg_name,
                                        snap_name=snap_name,
                                        snap_mnt=snap_mnt,
                                        snap_dev=snap_dev)

    def snapdestroykey(self, s):
        if protected_mount(self.snaps[s]['snap_mnt']):
            self.log.error("the snapshot is no longer mounted in %s. panic."%self.snaps[s]['snap_mnt'])
            raise ex.excError

        """ fuser on HP-UX outs to stderr ...
        """
        cmd = ['fuser', '-kc', self.snaps[s]['snap_mnt']]
        ret = qcall(cmd)

        cmd = ['umount', self.snaps[s]['snap_mnt']]
        (ret, out) = self.vcall(cmd)
        cmd = ['lvremove', '-f', self.snaps[s]['snap_dev']]
        (ret, buff) = self.vcall(cmd)

070701000671ce000081a40000000000000000000000014d9d7e6e00000ba0000000b600010002ffffffffffffffff0000001f00000000root/opt/opensvc/lib/checks.py    #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from rcGlobalEnv import rcEnv

class check(object):
    undef = [{
              'check_svcname': '',
              'chk_instance': 'undef',
              'chk_value': '-1'
             }]
    def __init__(self, svcs=[]):
        self.svcs = svcs

    def do_check(self):
        return []

class checks(check):
    check_list = []

    def __init__(self, svcs=[]):
        self.svcs = svcs
        self.register('checkFsUsage')
        self.register('checkFsInode')
        self.register('checkVgUsage')

    def __iadd__(self, c):
        if isinstance(c, check):
            self.check_list.append(c)
        elif isinstance(c, checks):
            self.check_list += c.check_list

    def register(self, chk_name):
        try:
            m = __import__(chk_name+rcEnv.sysname)
        except:
            print '%s not implemented on %s'%(chk_name,rcEnv.sysname)
            return
        self += m.check(svcs=self.svcs)

    def do_checks(self):
        import datetime
        import xmlrpcClient

        now = str(datetime.datetime.now())
        vars = [\
            "chk_nodename",
            "chk_svcname",
            "chk_type",
            "chk_instance",
            "chk_value",
            "chk_updated"]
        vals = []

        for chk in self.check_list:
            d = chk.do_check()
            if len(d) == 0:
                continue
            for i in d:
                if not isinstance(i, dict):
                    continue
                if 'chk_instance' not in i:
                    continue
                if i['chk_instance'] == 'undef':
                    continue
                if 'chk_value' not in i:
                    continue
                if 'chk_svcname' in i:
                    chk_svcname = i['chk_svcname']
                else:
                    chk_svcname = ""
                vals.append([\
                    rcEnv.nodename,
                    chk_svcname,
                    chk.chk_type,
                    i['chk_instance'],
                    i['chk_value'].replace("%",""),
                    now]
                )
        xmlrpcClient.push_checks(vars, vals)
07070100067247000081a40000000000000000000000014d9d7e6e00003a34000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/resSyncDds.py    #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import logging

from rcGlobalEnv import rcEnv
from rcUtilities import which
from rcUtilitiesLinux import lv_info
from subprocess import *
import rcExceptions as ex
import rcStatus
import datetime
import resSync

class syncDds(resSync.Sync):
    def pre_action(self, rset, action):
        """Don't sync PRD services when running on !PRD node
        """
        if self.svc.svctype == 'PRD' and rcEnv.host_mode != 'PRD':
            self.log.debug("won't sync a PRD service running on a !PRD node")
            raise ex.excAbortAction

        for i, r in enumerate(rset.resources):
            if r.is_disabled():
                continue
            if not r.svc_syncable():
                return
            r.get_info()
            if action == 'syncfullsync':
                r.create_snap1()
            elif action in ['syncupdate', 'syncresync', 'syncdrp', 'syncnodes']:
                if action == 'syncnodes' and self.target != ['nodes']:
                    return
                if action == 'syncdrp' and self.target != ['drpnodes']:
                    return
                r.get_info()
                r.get_snap1_uuid()
                nb = 0
                tgts = r.targets.copy()
                for n in tgts:
                    try:
                        r.check_remote(n)
                        nb += 1
                    except:
                        self.targets -= set([n])
                if nb != len(tgts):
                    self.log.error('all destination nodes must be present for dds-based synchronization to proceed')
                    raise ex.excError
                r.create_snap2()

    def snap_exists(self, dev):
        if not os.path.exists(dev):
            self.log.debug('dev path does not exist')
            return False
        cmd = ['lvs', '--noheadings', '-o', 'snap_percent', dev]
        (ret, out) = self.call(cmd, errlog=False)
        if ret != 0:
            return False
        if len(out.strip()) == 0:
            self.log.debug('dev is not a snapshot')
            return False
        return True

    def create_snap(self, dev, lv):
        if self.snap_exists(dev):
            self.log.error('%s should not exist'%dev)
            raise ex.excError
        cmd = ['lvcreate', '-s', '-n', lv,
               '-L', str(self.snap_size)+'M',
               os.path.join(os.sep, 'dev', self.src_vg, self.src_lv)
              ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def set_statefile(self):
        self.statefile = os.path.join(rcEnv.pathvar,
                                      self.svc.svcname+'_'+self.rid+'_dds_state')

    def create_snap1(self):
        if self.snap_exists(self.snap2):
            self.log.error('%s should not exist'%self.snap2)
            raise ex.excError
        self.create_snap(self.snap1, self.snap1_lv)
        self.write_statefile()

    def create_snap2(self):
        self.create_snap(self.snap2, self.snap2_lv)

    def snap_name(self, snap):
        return os.path.basename(self.src_lv).replace('-', '_')+'_osvc_'+snap

    def get_src_info(self):
        (self.src_vg, self.src_lv, self.src_size) = lv_info(self, self.src)
        if self.src_lv is None:
            self.log.error("unable to fetch source logical volume information")
            raise ex.excError
        if self.snap_size == 0:
            self.snap_size = self.src_size//10
        self.snap1_lv = self.snap_name('snap1')
        self.snap2_lv = self.snap_name('snap2')
        self.snap1 = os.path.join(os.sep, 'dev', self.src_vg, self.snap1_lv)
        self.snap2 = os.path.join(os.sep, 'dev', self.src_vg, self.snap2_lv)
        self.snap1_cow = os.path.join(os.sep, 'dev', 'mapper',
                                      '-'.join([self.src_vg.replace('-', '--'),
                                                self.snap1_lv,
                                                'cow'])
                                     )

    def get_peersenders(self):
        self.peersenders = set([])
        if 'nodes' not in self.target:
            self.peersenders |= self.svc.nodes
            self.peersenders -= set([rcEnv.nodename])

    def get_targets(self):
        self.targets = set()
        if 'nodes' in self.target:
            self.targets |= self.svc.nodes
        if 'drpnodes' in self.target:
            self.targets |= self.svc.drpnodes
        self.targets -= set([rcEnv.nodename])

    def get_info(self):
        self.get_targets()
        self.get_src_info()

    def svc_syncable(self):
        s = self.svc.group_status(excluded_groups=set(["sync", "hb"]))
        if s['overall'].status != rcStatus.UP:
            self.log.debug("won't sync this resource for a service not up")
            return False
        if self.svc.clustertype in ["flex", "autoflex"] and \
           self.svc.flex_primary != rcEnv.nodename:
            self.log.debug("won't sync this resource from a flex non-primary node")
            return set([])

        return True

    def syncfullsync(self):
        if not self.svc_syncable():
            return
        for n in self.targets:
            self.do_fullsync(n)

    def do_fullsync(self, node):
        cmd1 = ['dd', 'if='+self.snap1, 'bs=1M']
        cmd2 = rcEnv.rsh.split() + [node, 'dd', 'bs=1M', 'of='+self.dst]
        self.log.info(' '.join(cmd1 + ["|"] + cmd2))
        p1 = Popen(cmd1, stdout=PIPE)
        p2 = Popen(cmd2, stdin=p1.stdout, stdout=PIPE)
        p2.communicate()[0]
        if p2.returncode != 0:
            self.log.error("full sync failed")
            raise ex.excError
        self.push_statefile(node)

    def get_snap1_uuid(self):
        cmd = ['lvs', '--noheadings', '-o', 'uuid', self.snap1]
        (ret, out) = self.call(cmd)
        if ret != 0:
            raise ex.excError
        self.snap1_uuid = out.strip()

    def write_statefile(self):
        self.set_statefile()
        self.get_snap1_uuid()
        self.log.info("update state file with snap uuid %s"%self.snap1_uuid)
        with open(self.statefile, 'w') as f:
             f.write(str(datetime.datetime.now())+';'+self.snap1_uuid+'\n')

    def _push_statefile(self, node):
        cmd = rcEnv.rcp.split() + [self.statefile, node+':'+self.statefile]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def push_statefile(self, node):
        self.set_statefile()
        self._push_statefile(node)
        self.get_peersenders()
        for s in self.peersenders:
            self._push_statefile(s)

    def apply_delta(self, node):
        extract_cmd = ['dds', '--extract', '--cow', self.snap1_cow, '--source',
                       self.snap2]
        merge_cmd = ['dds', '--merge', '--dest', self.dst, '-v']
        merge_cmd = rcEnv.rsh.split() + [node] + merge_cmd
        self.log.info(' '.join(extract_cmd + ["|"] + merge_cmd))
        p1 = Popen(extract_cmd, stdout=PIPE)
        p2 = Popen(merge_cmd, stdin=p1.stdout, stdout=PIPE)
        buff = p2.communicate()
        if p2.returncode != 0:
            if buff[1] is not None and len(buff[1]) > 0:
                self.log.error(buff[1])
            self.log.error("sync update failed")
            raise ex.excError
        if buff[0] is not None and len(buff[0]) > 0:
            self.log.info(buff[0])

    def do_update(self, node):
        self.apply_delta(node)

    def remove_snap1(self):
        if not self.snap_exists(self.snap1):
            return
        cmd = ['lvremove', '-f', self.snap1]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def rename_snap2(self):
        if not self.snap_exists(self.snap2):
            self.log.error("%s should exist"%self.snap2)
            raise ex.excError
        if self.snap_exists(self.snap1):
            self.log.error("%s should not exist"%self.snap1)
            raise ex.excError
        cmd = ['lvrename', self.src_vg, self.snap2_lv, self.snap1_lv]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def rotate_snaps(self):
        self.remove_snap1()
        self.rename_snap2()

    def check_remote(self, node):
        rs = self.get_remote_state(node)
        if self.snap1_uuid != rs['uuid']:
            self.log.error("%s last update uuid doesn't match snap1 uuid"%(node))
            raise ex.excError

    def get_remote_state(self, node):
        self.set_statefile()
        cmd1 = ['env', 'LANG=C', 'cat', self.statefile]
        cmd = rcEnv.rsh.split() + [node] + cmd1
        (ret, out) = self.call(cmd)
        if ret != 0:
            self.log.error("could not fetch %s last update uuid"%node)
            raise ex.excError
        return self.parse_statefile(out, node=node)

    def get_local_state(self):
        self.set_statefile()
        with open(self.statefile, 'r') as f:
            out = f.read()
        return self.parse_statefile(out)

    def parse_statefile(self, out, node=None):
        self.set_statefile()
        if node is None:
            node = rcEnv.nodename
        lines = out.strip().split('\n')
        if len(lines) != 1:
            self.log.error("%s:%s is corrupted"%(node, self.statefile))
            raise ex.excError
        fields = lines[0].split(';')
        if len(fields) != 2:
            self.log.error("%s:%s is corrupted"%(node, self.statefile))
            raise ex.excError
        return dict(date=fields[0], uuid=fields[1])

    def syncnodes(self):
        if self.target != ['nodes']:
            return
        self.syncupdate()

    def syncdrp(self):
        if self.target != ['drpnodes']:
            return
        self.syncupdate()

    def syncupdate(self):
        if not self.svc_syncable():
            return
        for n in self.targets:
            self.do_update(n)
        self.rotate_snaps()
        self.write_statefile()
        for n in self.targets:
            self.push_statefile(n)

    def checksum(self, node, bdev, q=None):
        cmd = ['md5sum', bdev]
        if node != rcEnv.nodename:
            cmd = rcEnv.rsh.split() + [node] + cmd
        (ret, out) = self.call(cmd)
        if ret != 0:
            return ""
        o = out.split()
        if q is not None:
            q.put(o[0])
        else:
            self.checksums[node] = o[0]

    def syncverify(self):
        s = self.svc.group_status(excluded_groups=set(["sync", "hb"]))
        if s['overall'].status != rcStatus.UP:
            self.log.debug("won't verify this resource for a service not up")
            return
        if self.svc.clustertype in ["flex", "autoflex"] and \
           self.svc.flex_primary != rcEnv.nodename:
            self.log.debug("won't verify this resource from a flex non-primary node")
            return set([])

        self.get_info()
        from multiprocessing import Process, Queue
        self.checksums = {}
        queues = {}
        ps = []
        self.log.info("start checksum threads. please be patient.")
        for n in self.targets:
            queues[n] = Queue()
            p = Process(target=self.checksum, args=(n, self.dst, queues[n]))
            p.start()
            ps.append(p)
        self.checksum(rcEnv.nodename, self.snap1)
        self.log.info("md5 %s: %s"%(rcEnv.nodename, self.checksums[rcEnv.nodename]))
        for p in ps:
            p.join()
        for n in self.targets:
            self.checksums[n] = queues[n].get()
            self.log.info("md5 %s: %s"%(n, self.checksums[n]))
        if len(self.checksums) < 2:
            self.log.error("not enough checksums collected")
            raise ex.excError
        err = False
        for n in self.targets:
            if self.checksums[rcEnv.nodename] != self.checksums[n]:
                self.log.error("src/dst checksums differ for %s/%s"%(rcEnv.nodename, n))
                err = True
        if not err:
            self.log.info("src/dst checksums verified")

    def start(self):
        pass

    def stop(self):
        pass

    def can_sync(self, target=None):
        try:
            ls = self.get_local_state()
            last = datetime.datetime.strptime(ls['date'], "%Y-%m-%d %H:%M:%S.%f")
        except IOError:
            return True
        return not self.skip_sync(last)

    def _status(self, verbose=False):
        try:
            ls = self.get_local_state()
            now = datetime.datetime.now()
            last = datetime.datetime.strptime(ls['date'], "%Y-%m-%d %H:%M:%S.%f")
            delay = datetime.timedelta(minutes=self.sync_max_delay)
        except IOError:
            self.status_log("dds state file not found")
            return rcStatus.WARN
        except:
            import sys
            import traceback
            e = sys.exc_info()
            print e[0], e[1], traceback.print_tb(e[2])
            return rcStatus.WARN
        if last < now - delay:
            self.status_log("Last sync on %s older than %i minutes"%(last, self.sync_max_delay))
            return rcStatus.WARN
        return rcStatus.UP

    def __init__(self, rid=None, target=None, src=None, dst=None,
                 delta_store=None, sender=None,
                 snap_size=0, sync_max_delay=None,
                 sync_interval=None, sync_days=None, sync_period=None,
                 optional=False, disabled=False, tags=set([])):
        resSync.Sync.__init__(self, rid=rid, type="sync.dds",
                              sync_max_delay=sync_max_delay,
                              sync_interval=sync_interval,
                              sync_days=sync_days,
                              sync_period=sync_period,
                              optional=optional, disabled=disabled, tags=tags)

        self.label = "dds of %s to %s"%(src, target)
        self.target = target
        self.src = src
        self.dst = dst
        self.snap_size = snap_size
        if delta_store is None:
            self.delta_store = rcEnv.pathvar
        else:
            self.delta_store = delta_store

    def __str__(self):
        return "%s target=%s src=%s" % (resSync.Sync.__str__(self),\
                self.target, self.src)

070701000671da000081a40000000000000000000000014d9d7e6e000012ef000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/rcAsset.py   #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from rcGlobalEnv import rcEnv

class Asset(object):
    def __init__(self, node):
        self.node = node

    def get_mem_bytes(self):
        return '0'

    def get_mem_banks(self):
        return '0'

    def get_mem_slots(self):
        return '0'

    def get_os_vendor(self):
        return 'Unknown'

    def get_os_release(self):
        return 'Unknown'

    def get_os_kernel(self):
        return 'Unknown'

    def get_os_arch(self):
        return 'Unknown'

    def get_cpu_freq(self):
        return 'Unknown'

    def get_cpu_cores(self):
        return '0'

    def get_cpu_dies(self):
        return '0'

    def get_cpu_model(self):
        return 'Unknown'

    def get_serial(self):
        return 'Unknown'

    def get_model(self):
        return 'Unknown'

    def get_environnement(self):
        try:
            return self.node.config.get('node', 'host_mode')
        except:
            return 'TST'

    def get_team_responsible(self):
        try:
            return self.node.config.get('node', 'team_responsible')
        except:
            return None

    def get_loc_country(self):
        try:
            return self.node.config.get('node', 'loc_country')
        except:
            return None

    def get_loc_city(self):
        try:
            return self.node.config.get('node', 'loc_city')
        except:
            return None

    def get_loc_addr(self):
        try:
            return self.node.config.get('node', 'loc_addr')
        except:
            return None

    def get_loc_building(self):
        try:
            return self.node.config.get('node', 'loc_building')
        except:
            return None

    def get_loc_floor(self):
        try:
            return self.node.config.get('node', 'loc_floor')
        except:
            return None

    def get_loc_room(self):
        try:
            return self.node.config.get('node', 'loc_room')
        except:
            return None

    def get_loc_rack(self):
        try:
            return self.node.config.get('node', 'loc_rack')
        except:
            return None

    def get_loc_zip(self):
        try:
            return self.node.config.get('node', 'loc_zip')
        except:
            return None

    def get_asset_dict(self):
        d = {}
        d['nodename'] = rcEnv.nodename
        d['os_name'] = rcEnv.sysname
        d['os_vendor'] = self.get_os_vendor()
        d['os_release'] = self.get_os_release()
        d['os_kernel'] = self.get_os_kernel()
        d['os_arch'] = self.get_os_arch()
        d['mem_bytes'] = self.get_mem_bytes()
        d['mem_banks'] = self.get_mem_banks()
        d['mem_slots'] = self.get_mem_slots()
        d['cpu_freq'] = self.get_cpu_freq()
        d['cpu_cores'] = self.get_cpu_cores()
        d['cpu_dies'] = self.get_cpu_dies()
        d['cpu_model'] = self.get_cpu_model()
        d['serial'] = self.get_serial()
        d['model'] = self.get_model()
        d['environnement'] = self.get_environnement()
        loc_country = self.get_loc_country()
        if loc_country is not None:
            d['loc_country'] = loc_country
        loc_city = self.get_loc_city()
        if loc_city is not None:
            d['loc_city'] = loc_city
        loc_building = self.get_loc_building()
        if loc_building is not None:
            d['loc_building'] = loc_building
        loc_room = self.get_loc_room()
        if loc_room is not None:
            d['loc_room'] = loc_room
        loc_rack = self.get_loc_rack()
        if loc_rack is not None:
            d['loc_rack'] = loc_rack
        loc_addr = self.get_loc_addr()
        if loc_addr is not None:
            d['loc_addr'] = loc_addr
        loc_floor = self.get_loc_floor()
        if loc_floor is not None:
            d['loc_floor'] = loc_floor
        loc_zip = self.get_loc_zip()
        if loc_zip is not None:
            d['loc_zip'] = loc_zip
        team_responsible = self.get_team_responsible()
        if team_responsible is not None:
            d['team_responsible'] = team_responsible
        return d
 07070100067205000081a40000000000000000000000014d9d7e6e0000052c000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/rcPkgFreeBSD.py  #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from rcUtilities import call, which
from rcGlobalEnv import rcEnv

def listpkg():
    if which('pkg_info') is None:
        return []
    cmd = ['pkg_info']
    (ret, out) = call(cmd, errlog=False, cache=True)
    lines = []
    for line in out.split('\n'):
        l = line.split()
        if len(l) < 2:
            continue
        nv = l[0].split('-')
        version = nv[-1]
        pkgname = '-'.join(nv[0:-1])
        x = [rcEnv.nodename, pkgname, version, '']
        lines.append(x)
    return lines

def listpatch():
    return [] 
0707010006723b000081a40000000000000000000000014d9d7e6e00000bd2000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/resLoopLinux.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import re

from rcGlobalEnv import *
from rcUtilities import call, which
import rcStatus
import resLoop as Res
import rcExceptions as ex

def file_to_loop(f):
    """Given a file path, returns the loop device associated. For example,
    /path/to/file => /dev/loop0
    """
    if which('losetup') is None:
        return []
    if not os.path.isfile(f):
        return []
    if rcEnv.sysname != 'Linux':
        return []
    (ret, out) = call(['losetup', '-j', f])
    if len(out) == 0:
        return []
    """ It's possible multiple loopdev are associated with the same file
    """
    devs= []
    for line in out.split('\n'):
        l = line.split(':')
        if len(l) == 0:
            continue
        if len(l[0]) == 0:
            continue
        if not os.path.exists(l[0]):
            continue
        devs.append(l[0])
    return devs

class Loop(Res.Loop):
    def is_up(self):
        """Returns True if the loop group is present and activated
        """
        self.loop = file_to_loop(self.loopFile)
        if len(self.loop) == 0:
            return False
        return True

    def start(self):
        if self.is_up():
            self.log.info("%s is already up" % self.loopFile)
            return
        cmd = [ 'losetup', '-f', self.loopFile ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError
        self.loop = file_to_loop(self.loopFile)
        self.log.info("%s now loops to %s" % (', '.join(self.loop), self.loopFile))

    def stop(self):
        if not self.is_up():
            self.log.info("%s is already down" % self.loopFile)
            return 0
        for loop in self.loop:
            cmd = [ 'losetup', '-d', loop ]
            (ret, out) = self.vcall(cmd)
            if ret != 0:
                raise ex.excError

    def _status(self, verbose=False):
        if self.is_up(): return rcStatus.UP
        else: return rcStatus.DOWN

    def __init__(self, rid, loopFile, always_on=set([]),
                 disabled=False, tags=set([]), optional=False):
        Res.Loop.__init__(self, rid, loopFile, always_on=always_on,
                          disabled=disabled, tags=tags, optional=optional)
  070701000671c8000081a40000000000000000000000014d9d7e6e0000079c000000b600010002ffffffffffffffff0000002a00000000root/opt/opensvc/lib/checkFsInodeHP-UX.py #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import checks
from rcUtilities import call

class check(checks.check):
    chk_type = "fs_i"

    def find_svc(self, mountpt):
        for svc in self.svcs:
            for rs in svc.get_res_sets('fs'):
                for r in rs.resources:
                    if r.mountPoint == mountpt:
                        return svc.svcname
        return ''

    def do_check(self):
        """
        # bdf -li
        Filesystem          kbytes    used   avail %used  iused  ifree %iuse Mounted on
        /dev/vg00/lvol3    1048576  228160  814136   22%   2105  25607    8% /
        """
        cmd = ['bdf', '-li']
        (ret, out) = call(cmd)
        if ret != 0:
            return self.undef
        lines = out.split('\n')
        if len(lines) < 2:
            return self.undef
        r = []
        for line in lines[1:]:
            l = line.split()
            if len(l) != 9:
                continue
            r.append({'chk_instance': l[0],
                      'chk_value': l[7],
                      'chk_svcname': self.find_svc(l[8]),
                     }
                    )
        return r
07070100067254000081a40000000000000000000000014d9d7e6e000012c9000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/resVgLinux.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import re
import os
import rcExceptions as ex
import resDg
from rcGlobalEnv import rcEnv
from rcUtilitiesLinux import major, get_blockdev_sd_slaves, \
                             devs_to_disks
from rcUtilities import which

class Vg(resDg.Dg):
    def __init__(self, rid=None, name=None, type=None,
                 optional=False, disabled=False, tags=set([]),
                 always_on=set([])):
        self.label = name
        self.tag = '@'+rcEnv.nodename
        resDg.Dg.__init__(self, rid=rid, name=name,
                          type='disk.vg',
                          always_on=always_on,
                          optional=optional,
                          disabled=disabled, tags=tags)

    def has_it(self):
        """Returns True if the volume is present
        """
        cmd = [ 'vgs', '--noheadings', '-o', 'name' ]
        (ret, out) = self.call(cmd, cache=True)
        if self.name in out.split():
            return True
        return False

    def is_up(self):
        """Returns True if the volume group is present and activated
        """
        if not self.has_it():
            return False
        cmd = [ 'lvs', '--noheadings', '-o', 'lv_attr', self.name ]
        (ret, out) = self.call(cmd)
        if re.match(' ....-[-o]', out, re.MULTILINE) is None:
            return True
        return False

    def remove_tag(self, tag):
        cmd = [ 'vgchange', '--deltag', '@'+tag, self.name ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def remove_tags(self, tags=[]):
        cmd = ['vgs', '-o', 'tags', '--noheadings', self.name]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError
        out = out.strip(' \n')
        curtags = out.split(',')
        if len(tags) > 0:
            """ remove only specified tags
            """
            for tag in tags:
                tag = tag.lstrip('@')
                if tag in curtags:
                   self.remove_tag(tag)
        else:
            """ remove all tags
            """
            for tag in curtags:
                if len(tag) == 0:
                    continue
                self.remove_tag(tag)

    def add_tags(self):
        cmd = [ 'vgchange', '--addtag', self.tag, self.name ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def do_start(self):
        if self.is_up():
            self.log.info("%s is already up" % self.name)
            return 0
        self.remove_tags()
        self.add_tags()
        cmd = [ 'vgchange', '-a', 'y', self.name ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def remove_parts(self):
        if not which('partx'):
            return
        cmd = ['lvs', '-o', 'name', '--noheadings', self.name]
        (ret, out) = self.call(cmd)
        if ret != 0:
            self.log.error("can not fetch logical volume list from %s"%self.name)
            return
        base_cmd = ['kpartx', '-d']
        for lv in out.split():
             self.vcall(base_cmd+[os.path.join(os.sep, 'dev', self.name, lv)])

    def do_stop(self):
        if not self.is_up():
            self.log.info("%s is already down" % self.name)
            return
        self.remove_tags([self.tag])
        self.remove_parts()
        cmd = [ 'vgchange', '-a', 'n', self.name ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def disklist(self):
        if not self.has_it():
            return set()
        if self.disks != set():
            return self.disks

        self.disks = set()

        cmd = ['vgs', '--noheadings', '-o', 'pv_name', self.name]
        (ret, out) = self.call(cmd, cache=True)
        if ret != 0:
            return self.disks
	pvs = set(out.split())
        self.disks = devs_to_disks(self, pvs)
        self.log.debug("found disks %s held by vg %s" % (self.disks, self.name))
        return self.disks

   07070100067260000081a40000000000000000000000014d9d7e6e000006d9000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/lib/svcHosted.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import svc

class SvcHosted(svc.Svc):
    """Define hosted services
    """

    def __init__(self, svcname, optional=False, disabled=False, tags=set([])):
        svc.Svc.__init__(self, svcname, "Hosted", optional=optional, disabled=disabled, tags=tags)

if __name__ == "__main__":
    for c in (SvcHosted,) :
        help(c)
    import mountSunOS as mount
    import ipSunOS as ip
    print """
    S=SvcHosted()
    S+=mount.Mount("/mnt1","/dev/sda")
    S+=mount.Mount("/mnt2","/dev/sdb")
    S+=ip.Ip("eth0","192.168.0.173")
    S+=ip.Ip("eth0","192.168.0.174")
    """

    S=SvcSone()
    S+=mount.Mount("/mnt1","/dev/sda")
    S+=mount.Mount("/mnt2","/dev/sdb")
    S+=ip.Ip("eth0","192.168.0.173")
    S+=ip.Ip("eth0","192.168.0.174")

    print "Show S: ", S
    print "start S:"
    S.start()

    print "stop S:"
    S.stop()

   07070100067202000081a40000000000000000000000014d9d7e6e000015ef000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/rcOptParser.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import optparse
from rcGlobalEnv import *

action_desc = {
	'printsvc':	'display service live configuration',
	'boot':	        'start a service if executed on the primary node, startstandby if not',
	'shutdown':     'stop a service, disabling the background database logging',
	'start':	'start a service, chaining startip-diskstart-startapp',
	'startstandby':	'start service resources marked always_on',
	'startip':	'configure service ip addresses',
	'mount':	'prepare devices, logical volumes, mount service filesystems, bootstrap containers',
	'startapp':	'execute service application startup script',
	'stop':		'stop a service, chaining stopapp-diskstop-stopip',
	'stopip':	'unconfigure service ip addresses',
	'umount':	'shutdown container, umount service filesystems, deactivate logical volumes',
	'stopapp':	'execute service application stop script',
	'syncnodes':	'send to peer nodes the service config files and additional files described in the config file',
	'syncdrp':	'send to drp nodes the service config files and additional files described in the config file',
	'configure':	'configure a service container, using configuration file information',
	'create':	'create a new service configuration file',
	'update':	'update definitions in an existing service configuration file',
	'disable':	'disable resources passed through --rid in services passed through --service',
	'enable':	'enable resources passed through --rid in services passed through --service',
	'delete':	'delete resources passed through --rid in services passed through --service',
	'startcontainer':	'start the container resource',
	'stopcontainer':	'stop the container resource',
	'status':	'return service overall status code',
	'print_status':	'display service resource status',
	'freeze':	'set up a flag to block actions on this service',
	'thaw':		'remove the flag to unblock actions on this service',
	'frozen':	'report on the current blocking of actions on this service',
	'startloop':	'attach loop resources of this service',
	'stoploop':	'detach loop resources of this service',
	'startvg':	'activate/import volume group resources of this service',
	'stopvg':	'deactivate/deport volume group resources of this service',
	'startpool':	'activate zpool resources of this service',
	'stoppool':	'deactivate zpool resources of this service',
	'startdisk':	'combo action, chaining startvg-mount',
	'stopdisk':	'combo action, chaining umount-stopvg',
	'presync':	'update var files associated to resources',
	'postsync':	'make use of files received from master nodes in var',
	'prstart':	'reserve scsi disks held by this service',
	'prstop':	'release scsi disks held by this service',
	'prstatus':	'report status of reservations on scsi disks held by this service',
	'restart':	'combo action, chaining stop-start',
	'resync':	'combo action, chaining stop-syncresync-start',
	'syncquiesce':	'trigger a storage hardware-assisted disk synchronization',
	'syncbreak':	'split a storage hardware-assisted disk synchronization',
	'syncresync':	're-establish a broken storage hardware-assisted synchronization',
	'syncfullsync':	'trigger a full copy of the volume to its target',
	'syncupdate':	'trigger a one-time resync of the volume to its target',
	'syncverify':	'trigger a one-time checksum-based verify of the volume and its target',
	'syncall':	'combo action, chaining syncnodes-syncdrp-syncupdate',
	'push':         'push service configuration to database',
        'disklist':     'construct disklist',
        'switch':       'stop the service on the local node and start on the remote node',
}

def format_desc(svc=False):
        from textwrap import TextWrapper
        wrapper = TextWrapper(subsequent_indent="%19s"%"", width=78)
	desc = "Supported commands:\n"
	for a in sorted(action_desc):
		if svc and not hasattr(svc, a):
			continue
		text = "  %-16s %s\n"%(a, action_desc[a])
                desc += wrapper.fill(text)
                desc += '\n'
	return desc

class svcOptionParser:
	def __init__(self, svc=False):
		__ver = rcEnv.prog + " version " + str(rcEnv.ver)
		__usage = "%prog [options] command\n\n" + format_desc(svc)
		parser = optparse.OptionParser(version=__ver, usage=__usage)
		parser.add_option("--debug", default="False",
				  action="store_true", dest="debug",
				  help="debug mode")
		parser.add_option("-f", "--force", default=False,
				  action="store_true", dest="force",
				  help="force action, ignore sanity check warnings")
		(self.options, self.args) = parser.parse_args()
		if len(self.args) > 1:
			parser.error("More than one action")
		if len(self.args) is 0:
			parser.error("Missing action")
		self.action = self.args[0]
		if svc and not hasattr(svc, self.action):
			parser.error("unsupported action")
                if svc:
			svc.force = self.options.force
 070701000671d5000081a40000000000000000000000014d9d7e6e00000378000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/hostidSunOS.py   #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from uuid import getnode

def hostid():
    return str(getnode())
070701000671e6000081a40000000000000000000000014d9d7e6e00000c27000000b600010002ffffffffffffffff0000002800000000root/opt/opensvc/lib/rcDiskInfoLinux.py   #!/usr/bin/python2.6
#
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import sys
import os
from rcUtilities import call, which
import rcDiskInfo

class diskInfo(rcDiskInfo.diskInfo):
    disk_ids = {}

    def disk_id(self, dev):
        if dev in self.disk_ids:
            return self.disk_ids[dev]
        if which('scsi_id'):
            scsi_id = 'scsi_id'
        elif which('/lib/udev/scsi_id'):
            scsi_id = '/lib/udev/scsi_id'
        else:
            return ""
        cmd = [scsi_id, '-g', '-u', '-d', dev]
        (ret, out) = call(cmd)
        if ret == 0:
            id = out.split('\n')[0][1:]
            self.disk_ids[dev] = id
            return id
        sdev = dev.replace("/dev/", "/block/")
        cmd = [scsi_id, '-g', '-u', '-s', sdev]
        (ret, out) = call(cmd, errlog=False)
        if ret == 0:
            id = out.split('\n')[0][1:]
            self.disk_ids[dev] = id
            return id
        return ""

    def disk_vendor(self, dev):
        s = ''
        path = dev.replace('/dev/', '/sys/block/')+'/device/vendor'
        if not os.path.exists(path):
            return ""
        with open(path, 'r') as f:
            s = f.read()
            f.close()
        return s

    def disk_model(self, dev):
        s = ''
        path = dev.replace('/dev/', '/sys/block/')+'/device/model'
        if not os.path.exists(path):
            return ""
        with open(path, 'r') as f:
            s = f.read()
            f.close()
        return s

    def disk_size(self, dev):
        size = 0
        if '/dev/mapper/' in dev:
            try:
                statinfo = os.stat(dev)
            except:
                self.log.error("can not stat %s" % dev)
                raise
            dm = 'dm-' + str(os.minor(statinfo.st_rdev))
            path = '/sys/block/' + dm + '/size'
            if not os.path.exists(path):
                return 0
        else:
            path = dev.replace('/dev/', '/sys/block/')+'/size'
            if not os.path.exists(path):
                cmd = ['blockdev', '--getsize', dev]
                (ret, out) = call(cmd)
                if ret != 0:
                    return 0
                return int(out)/2097152

        with open(path, 'r') as f:
            size = f.read()
            f.close()
        return int(size)/2097152

 07070100067225000081a40000000000000000000000014d9d7e6e00001908000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/lib/resContainerZone.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from datetime import datetime
import rcStatus
import resources as Res
import time
import os
from rcUtilities import justcall, vcall
from stat import *
import resContainer

class Zone(resContainer.Container):

    def __init__(self, name, optional=False, disabled=False, tags=set([])):
        """define Zone object attribute :
                name
                label
                state
                zonepath
        """
        Res.Resource.__init__(self, rid="zone", type="container.zone",
                              optional=optional, disabled=disabled, tags=tags)
        self.name = name
        self.label = name
        self.state = None
        self.zonepath = os.path.realpath(os.path.join( 'zones', self.name))
        self.zone_refresh()

    def zoneadm(self, action, option=None):
        if action in [ 'ready' , 'boot' ,'shutdown' , 'halt' ,'attach', 'detach' ] :
            cmd = ['zoneadm', '-z', self.name, action ]
        else:
            self.log.error("unsupported zone action: %s" % action)
            return 1
        if option is not None:
            cmd += option

        t = datetime.now()
        (ret, out) = self.vcall(cmd,err_to_info=True)
        len = datetime.now() - t
        self.log.info('%s done in %s - ret %i - logs in %s'
                    % (action, len, ret, out))
        return ret

    def set_zonepath_perms(self):
        if not os.path.exists(self.zonepath):
            os.makedirs(self.zonepath)
        s = os.stat(self.zonepath)
        if s.st_uid != 0 or s.st_gid != 0:
            self.log.info("set %s ownership to uid 0 gid 0"%self.zonepath)
            os.chown(self.zonepath, 0, 0)
        mode = s[ST_MODE]
        if (S_IWOTH&mode) or (S_IXOTH&mode) or (S_IROTH&mode) or \
           (S_IWGRP&mode) or (S_IXGRP&mode) or (S_IRGRP&mode):
            self.vcall(['chmod', '700', self.zonepath])

    def attach(self):
        self.zone_refresh()
        if self.state in ('installed' , 'ready', 'running'):
            self.log.info("zone container %s already installed" % self.name)
            return 0
        ret = self.zoneadm('attach')
        if ret == 0 :
            return ret
        else :
            return self.zoneadm('attach', ['-F'] )

    def detach(self):
        self.zone_refresh()
        if self.state == "configured" :
            self.log.info("zone container %s already detached/configured" % self.name)
            return 0
        return self.zoneadm('detach')

    def ready(self):
        self.zone_refresh()
        if self.state == 'ready' or self.state == "running" :
            self.log.info("zone container %s already ready" % self.name)
            return 0
        self.set_zonepath_perms()
        return self.zoneadm('ready')

    def install_drp_flag(self):
        rootfs = self.zonepath
        flag = os.path.join(rootfs, ".drp_flag")
        self.log.info("install drp flag in container : %s"%flag)
        with open(flag, 'w') as f:
            f.write(' ')
            f.close()

    def boot(self):
        self.zone_refresh()
        if self.state == "running" :
            self.log.info("zone container %s already running" % self.name)
            return 0
        return self.zoneadm('boot')

    def stop(self):
        """ Need wait poststat after returning to installed state on ipkg
            example : /bin/ksh -p /usr/lib/brand/ipkg/poststate zonename zonepath 5 4
        """
        self.zone_refresh()
        if self.state in [ 'installed', 'configured'] :
            self.log.info("zone container %s already stopped" % self.name)
            return 0
        if self.state == 'running':
            (ret, out) = self.vcall(['zlogin' , self.name , '/sbin/init' , '0'])
            for t in range(self.shutdown_timeout):
                self.zone_refresh()
                if self.state == 'installed':
                    for t2 in range(self.shutdown_timeout):
                        time.sleep(1)
                        (out,err,st) = justcall([ 'pgrep', '-fl', 'ipkg/poststate.*'+ self.name])
                        if st == 0 : 
                            self.log.info("Waiting for ipkg poststate complete: %s" % out)
                        else:
                            break
                    return 0
                time.sleep(1)
            self.log.info("timeout out waiting for %s shutdown", self.name)
        return self.zoneadm('halt')

    def _status(self, verbose=False):
        self.zone_refresh()
        if self.state == 'running' :
            return rcStatus.UP
        else:
            return rcStatus.DOWN

    def zone_refresh(self):
        """ refresh Zone object attributes:
                state
                zonepath
                brand
            from zoneadm -z zonename list -p
            zoneid:zonename:state:zonepath:uuid:brand:ip-type
        """

        (out,err,st) = justcall([ 'zoneadm', '-z', self.name, 'list', '-p' ])

        if st == 0 :
            (zoneid,zonename,state,zonepath,uuid,brand,iptype)=out.split(':')
            if zonename == self.name :
                self.state = state
                self.zonepath = zonepath
                self.brand = brand
                return True
            else:
                return False
        else:
            return False

    def __str__(self):
        return "%s name=%s" % (Res.Resource.__str__(self), self.name)


if __name__ == "__main__":
    for c in (Zone,) :
        help(c)
0707010006723a000081a40000000000000000000000014d9d7e6e00000c38000000b600010002ffffffffffffffff0000002700000000root/opt/opensvc/lib/resLoopFreeBSD.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import re

from rcGlobalEnv import *
from rcUtilities import call, which
import rcStatus
import resLoop as Res
import rcExceptions as ex

def file_to_loop(f):
    """Given a file path, returns the loop device associated. For example,
    /path/to/file => /dev/loop0
    """
    if which('mdconfig') is None:
        return []
    if not os.path.isfile(f):
        return []
    (ret, out) = call(['mdconfig', '-l', '-v'])
    if ret != 0:
        return []
    """ It's possible multiple loopdev are associated with the same file
    """
    devs= []
    for line in out.split('\n'):
        l = line.split()
        if len(l) < 4:
            continue
        path = ' '.join(l[3:])
        if path != f:
            continue
        if not os.path.exists('/dev/'+l[0]):
            continue
        devs.append(l[0])
    return devs

class Loop(Res.Loop):
    def is_up(self):
        """Returns True if the loop group is present and activated
        """
        self.loop = file_to_loop(self.loopFile)
        if len(self.loop) == 0:
            return False
        return True

    def start(self):
        if self.is_up():
            self.log.info("%s is already up" % self.loopFile)
            return
        cmd = ['mdconfig', '-a', '-t', 'vnode', '-f', self.loopFile]
        (ret, out) = self.call(cmd, info=True, outlog=False)
        if ret != 0:
            raise ex.excError
        self.loop = file_to_loop(self.loopFile)
        self.log.info("%s now loops to %s" % (', '.join(self.loop), self.loopFile))

    def stop(self):
        if not self.is_up():
            self.log.info("%s is already down" % self.loopFile)
            return 0
        for loop in self.loop:
            cmd = ['mdconfig', '-d', '-u', loop.strip('md')]
            (ret, out) = self.vcall(cmd)
            if ret != 0:
                raise ex.excError

    def _status(self, verbose=False):
        if self.is_up():
            return self.status_stdby(rcStatus.UP)
        else:
            return self.status_stdby(rcStatus.DOWN)

    def __init__(self, rid, loopFile, always_on=set([]),
                 disabled=False, tags=set([]), optional=False):
        Res.Loop.__init__(self, rid, loopFile, always_on=always_on,
                          disabled=disabled, tags=tags, optional=optional)
0707010006724d000081a40000000000000000000000014d9d7e6e00003589000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/resSyncZfs.py    #
# Copyright (c) 2011 Christophe Varoqui <christophe.varoqui@opensvc.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
from rcGlobalEnv import rcEnv
import datetime
from subprocess import *
import rcExceptions as ex
import rcStatus
import resSync
from rcZfs import a2pool_dataset

class SyncZfs(resSync.Sync):
    """define zfs sync resource to be zfs send/zfs receive between nodes
    """
    def __init__(self, rid=None, target=None, src=None, dst=None,
                 delta_store=None, sender=None, recursive = True,
                 snap_size=0, sync_max_delay=None, sync_interval=None,
                 sync_days=None, sync_period=None,
                 optional=False, disabled=False, tags=set([])):
        resSync.Sync.__init__(self, rid=rid, type="sync.zfs",
                              sync_max_delay=sync_max_delay,
                              sync_interval=sync_interval,
                              sync_days=sync_days,
                              sync_period=sync_period,
                              optional=optional, disabled=disabled, tags=tags)

        self.label = "zfs of %s to %s"%(src, target)
        self.target = target
        self.sender = sender
        self.recursive = recursive
        (self.src_pool, self.src_ds) = a2pool_dataset(src)
        (self.dst_pool, self.dst_ds) = a2pool_dataset(dst)
        if delta_store is None:
            self.delta_store = rcEnv.pathvar
        else:
            self.delta_store = delta_store

    def pre_action(self, rset, action):
        """Prepare dataset snapshots
        Don't sync PRD services when running on !PRD node
        skip snapshot creation if delay_snap in tags
        delay_snap should be used for oracle archive datasets
        """
        if self.svc.svctype == 'PRD' and rcEnv.host_mode != 'PRD':
            self.log.debug("won't sync a PRD service running on a !PRD node")
            raise ex.excAbortAction

        for i, r in enumerate(rset.resources):
            if r.is_disabled():
                continue
            if 'delay_snap' in r.tags:
                continue
            r.get_info()
            if action in ['syncupdate', 'syncresync', 'syncdrp', 'syncnodes']:
                if action == 'syncnodes' and self.target != ['nodes']:
                    return
                if action == 'syncdrp' and self.target != ['drpnodes']:
                    return
                nb = 0
                tgts = r.targets.copy()
                if len(tgts) == 0 :
                    continue
            r.get_info()
            if not r.snap_exists(r.src_snap_tosend):
                r.create_snap(r.src_snap_tosend)

    def __str__(self):
        return "%s target=%s src=%s" % (resSync.Sync.__str__(self),\
                self.target, self.src)

    def snap_exists(self, snapname, node=None):
        cmd = ['env', 'PATH=/usr/sbin:/sbin', 'zfs', 'list', '-t', 'snapshot', snapname]
        if node is not None:
            cmd = rcEnv.rsh.split() + [node] + cmd
        (ret, out) = self.call(cmd, errlog=False)
        if ret == 0:
            return True
        else:
            return False

    def create_snap(self, snap):
        if self.snap_exists(snap):
            self.log.error('%s should not exist'%snap)
            raise ex.excError
        if self.recursive :
            cmd = ['zfs', 'snapshot' , '-r' , snap ]
        else:
            cmd = ['zfs', 'snapshot' , snap ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def get_src_info(self):
        self.src_snap_sent = self.src_ds + '@sent'
        self.src_snap_tosend = self.src_ds + '@tosend'

    def get_dst_info(self):
        self.dst_snap_sent = self.dst_ds + '@sent'
        self.dst_snap_tosend = self.dst_ds + '@tosend'

    def get_peersenders(self):
        self.peersenders = set([])
        if 'nodes' == self.sender:
            self.peersenders |= self.svc.nodes
            self.peersenders -= set([rcEnv.nodename])

    def get_targets(self):
        self.targets = set()
        if 'nodes' in self.target:
            self.targets |= self.svc.nodes
        if 'drpnodes' in self.target:
            self.targets |= self.svc.drpnodes
        self.targets -= set([rcEnv.nodename])

    def get_info(self):
        self.get_targets()
        self.get_src_info()
        self.get_dst_info()

    def syncnodes(self):
        """alias to syncupdate"""
        self.syncupdate()

    def syncfullsync(self):
        """alias to syncupdate"""
        self.syncupdate()

    def zfs_send_incremental(self, node):
        if self.recursive :  
            send_cmd = ['zfs', 'send', '-R', '-i',
                            self.src_snap_sent, self.src_snap_tosend]
        else:
            send_cmd = ['zfs', 'send', '-i',
                            self.src_snap_sent, self.src_snap_tosend]

	receive_cmd = ['env', 'PATH=/usr/sbin:/sbin', 'zfs', 'receive', '-dF', self.dst_pool]
        if node is not None:
            receive_cmd = rcEnv.rsh.strip(' -n').split() + [node] + receive_cmd

        self.log.info(' '.join(send_cmd + ["|"] + receive_cmd))
        p1 = Popen(send_cmd, stdout=PIPE)
        p2 = Popen(receive_cmd, stdin=p1.stdout, stdout=PIPE)
        buff = p2.communicate()
        if p2.returncode != 0:
            if buff[1] is not None and len(buff[1]) > 0:
                self.log.error(buff[1])
            self.log.error("sync update failed")
            raise ex.excError
        if buff[0] is not None and len(buff[0]) > 0:
            self.log.info(buff[0])

    def zfs_send_initial(self, node=None):
        if self.recursive :  
            send_cmd = ['zfs', 'send', '-R', self.src_snap_tosend]
        else:
            send_cmd = ['zfs', 'send', self.src_snap_tosend]

	receive_cmd = ['env', 'PATH=/usr/sbin:/sbin', 'zfs', 'receive', '-dF', self.dst_pool ]
        if node is not None:
            receive_cmd = rcEnv.rsh.strip(' -n').split() + [node] + receive_cmd

        self.log.info(' '.join(send_cmd + ["|"] + receive_cmd))
        p1 = Popen(send_cmd, stdout=PIPE)
        p2 = Popen(receive_cmd, stdin=p1.stdout, stdout=PIPE)
        buff = p2.communicate()
        if p2.returncode != 0:
            if buff[1] is not None and len(buff[1]) > 0:
                self.log.error(buff[1])
            self.log.error("full sync failed")
            raise ex.excError
        if buff[0] is not None and len(buff[0]) > 0:
            self.log.info(buff[0])

    def remove_snap(self, snap, node=None):
        if not self.snap_exists(snap, node=node):
            return
        if self.recursive :
            cmd = ['zfs', 'destroy', '-r', snap]
        else:
            cmd = ['zfs', 'destroy', snap]
        if node is not None:
            cmd = rcEnv.rsh.split() + [node, 'env', 'PATH=/usr/sbin:/sbin'] + cmd
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def rename_snap(self, src, dst,  node=None):
        if self.snap_exists(dst, node):
            self.log.error("%s should not exist"%dst)
            raise ex.excError
        if self.recursive :
            cmd = ['zfs', 'rename', '-r', src, dst]
        else:
            cmd = ['zfs', 'rename', src, dst]

        if node is not None:
            cmd = rcEnv.rsh.split() + [node, 'env', 'PATH=/usr/sbin:/sbin'] + cmd
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def rotate_snaps(self, src, dst, node=None):
        self.remove_snap(dst, node)
        self.rename_snap(src, dst, node)

    def syncupdate(self):
        """
        test if service status is UP else return
        create the snap_tosend if not already created (during pre_action)
        if a snap has already been sent
        then for all targets
             zfs_send_incremental
             rotate snap
        else for all targets
            zfs_send_initial
            rotate snap
        rotate snap on local node
        """
        s = self.svc.group_status(excluded_groups=set(["sync", "hb"]))
        if s['overall'].status != rcStatus.UP:
            self.log.debug("won't sync this resource for a service not up")
            return

        """ Refuse to sync from a flex non-primary node
        """
        if self.svc.clustertype in ["flex", "autoflex"] and \
           self.svc.flex_primary != rcEnv.nodename:
            self.log.debug("won't sync this resource from a flex non-primary node")
            return set([])

        self.get_info()
        if not self.snap_exists(self.src_snap_tosend):
            self.create_snap(self.src_snap_tosend)
        if self.snap_exists(self.src_snap_sent):
            for n in self.targets:
                self.zfs_send_incremental(n)
                self.rotate_snaps(self.dst_snap_tosend, self.dst_snap_sent, n)
        else:
            for n in self.targets:
                self.zfs_send_initial(n)
                self.rotate_snaps(self.dst_snap_tosend, self.dst_snap_sent, n)
        self.rotate_snaps(self.src_snap_tosend, self.src_snap_sent)
        self.write_statefile()
        for n in self.targets:
            self.push_statefile(n)

    def start(self):
        pass

    def stop(self):
        pass

    def can_sync(self, target=None):
        try:
            ls = self.get_local_state()
            ts = datetime.datetime.strptime(ls['date'], "%Y-%m-%d %H:%M:%S.%f")
        except IOError:
            self.log.error("zfs state file not found")
            return True
        except:
            import sys
            import traceback
            e = sys.exc_info()
            print e[0], e[1], traceback.print_tb(e[2])
            return False
        if self.skip_sync(ts):
            self.status_log("Last sync on %s older than %i minutes"%(ts, self.sync_max_delay))
            return False
        return True

    def _status(self, verbose=False):
        try:
            ls = self.get_local_state()
            now = datetime.datetime.now()
            last = datetime.datetime.strptime(ls['date'], "%Y-%m-%d %H:%M:%S.%f")
            delay = datetime.timedelta(minutes=self.sync_max_delay)
        except IOError:
            self.status_log("zfs state file not found")
            return rcStatus.WARN
        except:
            import sys
            import traceback
            e = sys.exc_info()
            print e[0], e[1], traceback.print_tb(e[2])
            return rcStatus.WARN
        if last < now - delay:
            self.status_log("Last sync on %s older than %i minutes"%(last, self.sync_max_delay))
            return rcStatus.WARN
        return rcStatus.UP

    def check_remote(self, node):
        rs = self.get_remote_state(node)
        if self.snap1_uuid != rs['uuid']:
            self.log.error("%s last update uuid doesn't match snap1 uuid"%(node))
            raise ex.excError

    def get_remote_state(self, node):
        self.set_statefile()
        cmd1 = ['env', 'LANG=C', 'cat', self.statefile]
        cmd = rcEnv.rsh.split() + [node] + cmd1
        (ret, out) = self.call(cmd)
        if ret != 0:
            self.log.error("could not fetch %s last update uuid"%node)
            raise ex.excError
        return self.parse_statefile(out, node=node)

    def get_local_state(self):
        self.set_statefile()
        with open(self.statefile, 'r') as f:
            out = f.read()
        return self.parse_statefile(out)

    def get_snap_uuid(self, snap):
        cmd = ['zfs', 'list', '-H', '-o', 'creation', '-t', 'snapshot', snap]
        (ret, out) = self.call(cmd)
        if ret != 0:
            raise ex.excError
        self.snap_uuid = out.strip()

    def set_statefile(self):
        self.statefile = os.path.join(rcEnv.pathvar,
                                      self.svc.svcname+'_'+self.rid+'_zfs_state')

    def write_statefile(self):
        self.set_statefile()
        self.get_snap_uuid(self.src_snap_sent)
        self.log.info("update state file with snap uuid %s"%self.snap_uuid)
        with open(self.statefile, 'w') as f:
             f.write(str(datetime.datetime.now())+';'+self.snap_uuid+'\n')

    def _push_statefile(self, node):
        cmd = rcEnv.rcp.split() + [self.statefile, node+':'+self.statefile.replace('#', '\#')]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def push_statefile(self, node):
        self.set_statefile()
        self._push_statefile(node)
        self.get_peersenders()
        for s in self.peersenders:
            self._push_statefile(s)

    def parse_statefile(self, out, node=None):
        self.set_statefile()
        if node is None:
            node = rcEnv.nodename
        lines = out.strip().split('\n')
        if len(lines) != 1:
            self.log.error("%s:%s is corrupted"%(node, self.statefile))
            raise ex.excError
        fields = lines[0].split(';')
        if len(fields) != 2:
            self.log.error("%s:%s is corrupted"%(node, self.statefile))
            raise ex.excError
        return dict(date=fields[0], uuid=fields[1])

   0707010006725a000081a40000000000000000000000014d9d7e6e00000d3d000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/snapLvmLinux.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os

from rcGlobalEnv import rcEnv
from rcUtilities import qcall, protected_mount
from rcUtilitiesLinux import lv_info, lv_exists
import rcExceptions as ex
import snap

class Snap(snap.Snap):
    def mntopt_and_ro(self, m):
        if m.mntOpt is None:
            return 'ro'
        opt_set = set(m.mntOpt.split(','))
        opt_set -= set(['rw', 'ro'])
        opt_set |= set(['ro'])
        return ','.join(opt_set)

    def snapcreate(self, m):
        snap_name = ''
        snap_mnt = ''
        (vg_name, lv_name, lv_size) = lv_info(self, m.device)
        if lv_name is None:
            self.log.error("can not snap %s: not a logical volume"%m.device)
            raise ex.syncNotSnapable
        snap_name = 'osvc_sync_'+lv_name
        if lv_exists(self, os.path.join(os.sep, 'dev', vg_name, snap_name)):
            self.log.error("snap of %s already exists"%(lv_name))
            raise ex.syncSnapExists

        if m.snap_size is not None:
            snap_size = m.snap_size
        else:
            snap_size = int(lv_size//10)

        (ret, buff) = self.vcall(['lvcreate', '-s', '-L'+str(snap_size)+'M', '-n', snap_name, os.path.join(vg_name, lv_name)])
        if ret != 0:
            raise ex.syncSnapCreateError
        snap_mnt = os.path.join(rcEnv.pathtmp,
                                'osvc_sync_'+vg_name+'_'+lv_name)
        if not os.path.exists(snap_mnt):
            os.makedirs(snap_mnt, 0755)
        snap_dev = os.path.join(os.sep, 'dev', vg_name, snap_name)
        self.vcall(['fsck', '-a', snap_dev], err_to_warn=True)
        (ret, buff) = self.vcall(['mount', '-o', self.mntopt_and_ro(m), snap_dev, snap_mnt])
        if ret != 0:
            raise ex.syncSnapMountError
        self.snaps[m.mountPoint] = dict(lv_name=lv_name,
                                        vg_name=vg_name,
                                        snap_name=snap_name,
                                        snap_mnt=snap_mnt,
                                        snap_dev=snap_dev)

    def snapdestroykey(self, s):
        if protected_mount(self.snaps[s]['snap_mnt']):
            self.log.error("the snapshot is no longer mounted in %s. panic."%self.snaps[s]['snap_mnt'])
            raise ex.excError
        cmd = ['fuser', '-kmv', self.snaps[s]['snap_mnt']]
        (ret, out) = self.vcall(cmd, err_to_info=True)
        cmd = ['umount', self.snaps[s]['snap_mnt']]
        (ret, out) = self.vcall(cmd)
        cmd = ['lvremove', '-f', self.snaps[s]['snap_dev']]
        (ret, buff) = self.vcall(cmd)
        del(self.snaps[s])

   070701000671d8000081a40000000000000000000000014d9d7e6e000059d4000000b600010002ffffffffffffffff0000001d00000000root/opt/opensvc/lib/node.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@opensvc.com>
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

from svc import Svc
from freezer import Freezer
import svcBuilder
import xmlrpcClient
import os
import ConfigParser
import datetime
import time
import sys
from rcGlobalEnv import rcEnv

class Options(object):
    def __init__(self):
        self.force = False
        self.debug = False
        self.stats_dir = None
        self.stats_start = None
        self.stats_end = None
        self.moduleset = ""
        self.module = ""
        self.ruleset_date = ""
        os.environ['LANG'] = 'C'

class Node(Svc, Freezer):
    """ Defines a cluster node.  It contain list of Svc.
        Implements node-level actions and checks.
    """
    def __init__(self):
        self.nodeconf = os.path.join(os.path.dirname(__file__), '..', 'etc', 'node.conf')
        self.dotnodeconf = os.path.join(os.path.dirname(__file__), '..', 'etc', '.node.conf')
        self.setup_sync_flag = os.path.join(rcEnv.pathvar, 'last_setup_sync')
        self.config_defaults = {
          'host_mode': 'TST',
          'push_interval': 1439,
          'push_days': '["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]',
          'push_period': '["04:00", "06:00"]',
          'sync_interval': 1439,
          'sync_days': '["monday", "tuesday", "wednesday", "thursday", "friday", "saturday", "sunday"]',
          'sync_period': '["04:00", "06:00"]',
          'comp_check_interval': 10072,
          'comp_check_days': '["sunday"]',
          'comp_check_period': '["05:00", "06:00"]',
        }
        self.load_config()
        self.options = Options()
        self.svcs = None
        Freezer.__init__(self, '')
        self.action_desc = {
          'syncservices':   'send var files, config files and configured replications to other nodes for each node service',
          'updateservices': 'refresh var files associated with services',
          'pushasset':      'push asset information to collector',
          'pushservices':   'push service configuration to collector',
          'pushstats':      'push performance metrics to collector',
          'pushpkg':        'push package/version list to collector',
          'pushpatch':      'push patch/version list to collector',
          'pushsym':        'push symmetrix configuration to collector',
          'prkey':          'show persistent reservation key of this node',
          'checks':         'run node sanity checks, push results to collector',
          'compliance_check': 'run compliance checks',
          'compliance_fix':   'run compliance fixes',
          'compliance_fixable': 'verify compliance fixes prerequisites',
          'compliance_show_moduleset': 'show compliance rules applying to this node',
          'compliance_list_moduleset': 'list available compliance modulesets. --moduleset f% limit the scope to modulesets matching the f% pattern.',
          'compliance_attach_moduleset': 'attach moduleset specified by --moduleset for this node',
          'compliance_detach_moduleset': 'detach moduleset specified by --moduleset for this node',
          'compliance_list_ruleset': 'list available compliance rulesets. --ruleset f% limit the scope to rulesets matching the f% pattern.',
          'compliance_show_ruleset': 'show compliance rules applying to this node',
          'compliance_attach_ruleset': 'attach ruleset specified by --ruleset for this node',
          'compliance_detach_ruleset': 'detach ruleset specified by --ruleset for this node',
          'get': 'get the value of the node configuration parameter pointed by --param',
          'set': 'set a node configuration parameter (pointed by --param) value (pointed by --value)',
          'delete': 'delete a node configuration parameter (pointed by --param)',
        }

    def _setup_sync_conf(self):
        sync_interval = 9999
        sync_days = set([])
        sync_period = []
        if self.svcs is None:
            self.svcs = svcBuilder.build_services()
        for svc in self.svcs:
            for rs in [_rs for _rs in svc.resSets if _rs.type.startswith('sync')]:
                for r in rs.resources:
                    sync_days |= set(r.sync_days)
                    if not isinstance(r.sync_period[0], list):
                        rsync_period = [r.sync_period]
                    else:
                        rsync_period = r.sync_period
                    for rp in rsync_period:
                        rp = map(lambda x: str(x), rp)
                        if rp not in sync_period:
                            sync_period.append(rp)
                    if r.sync_interval < sync_interval:
                        sync_interval = r.sync_interval
        if not self.config.has_section('sync'):
            self.config.add_section('sync')
        import json
        if sync_interval != 9999:
            self.config.set('sync', 'interval', sync_interval)
        if len(sync_days) > 0:
            self.config.set('sync', 'days', json.dumps(list(sync_days)))
        if len(sync_period) > 0:
            self.config.set('sync', 'period', json.dumps(sync_period))
        self.write_dotconfig()
        with open(self.setup_sync_flag, 'w') as f:
            f.write(str(time.time()))

    def write_dotconfig(self):
        for o in self.config_defaults:
            if self.config.has_option('DEFAULT', o):
                self.config.remove_option('DEFAULT', o)
        for s in self.config.sections():
            if s == 'sync':
                continue
            self.config.remove_section(s)
        try:
            fp = open(self.dotnodeconf, 'w')
            self.config.write(fp)
            fp.close()
        except:
            print >>sys.stderr, "failed to write new %s"%self.dotnodeconf
            raise Exception()
        self.load_config()

    def write_config(self):
        for o in self.config_defaults:
            if self.config.has_option('DEFAULT', o):
                self.config.remove_option('DEFAULT', o)
        if self.config.has_section('sync'):
            self.config.remove_section('sync')
        try:
            fp = open(self.nodeconf, 'w')
            self.config.write(fp)
            fp.close()
        except:
            print >>sys.stderr, "failed to write new %s"%self.nodeconf
            raise Exception()
        self.load_config()

    def load_config(self):
        self.config = ConfigParser.RawConfigParser(self.config_defaults)
        self.config.read(self.nodeconf)
        self.config.read(self.dotnodeconf)

    def setup_sync_outdated(self):
        """ return True if one env file has changed in the last 10'
            else return False
        """
        import datetime
        import glob
        envs = glob.glob(os.path.join(rcEnv.pathetc, '*.env'))
        if not os.path.exists(self.setup_sync_flag):
            return True
        for pathenv in envs:
            try:
                mtime = os.stat(pathenv).st_mtime
                f = open(self.setup_sync_flag)
                last = float(f.read())
                f.close()
            except:
                return True
            if mtime > last:
                return True
        return False

    def setup_sync_conf(self):
        if self.setup_sync_outdated():
            self._setup_sync_conf()
            return
        elif not self.config.has_section('sync'):
            self._setup_sync_conf()
            return
        elif not self.config.has_option('sync', 'interval') or \
           not self.config.has_option('sync', 'days') or \
           not self.config.has_option('sync', 'period'):
            self._setup_sync_conf()

    def format_desc(self):
        from textwrap import TextWrapper
        wrapper = TextWrapper(subsequent_indent="%29s"%"", width=78)
        desc = "Supported commands:\n"
        for a in sorted(self.action_desc):
            if not hasattr(self, a):
                continue
            text = "  %-26s %s\n"%(a.replace('_', ' '),
                                   self.action_desc[a])
            desc += wrapper.fill(text)
            desc += '\n'
        return desc

    def __iadd__(self, s):
        if not isinstance(s, Svc):
                pass
        self.svcs.append(s)
        return self

    def action(self, a):
        return getattr(self, a)()

    def check_timestamp(self, timestamp_f, comp='more', delay=10):
        """ Return False if timestamp is fresher than now-interval
            Return True otherwize.
            Zero is a infinite interval
        """
        if delay == 0:
            return False
        if not os.path.exists(timestamp_f):
            return True
        try:
            with open(timestamp_f, 'r') as f:
                d = f.read()
                last = datetime.datetime.strptime(d,"%Y-%m-%d %H:%M:%S.%f\n")
                limit = last + datetime.timedelta(minutes=delay)
                if comp == "more" and datetime.datetime.now() < limit:
                    return False
                elif comp == "less" and datetime.datetime.now() < limit:
                    return False
                else:
                    return True
                f.close()
        except:
            return True
        return True

    def timestamp(self, timestamp_f, interval):
        if not self.check_timestamp(timestamp_f, 'more', interval):
            return False
        if self.options.force:
            # don't update the timestamp in force mode
            # to not perturb the schedule
            return True
        timestamp_d = os.path.dirname(timestamp_f)
        if not os.path.isdir(timestamp_d):
            os.makedirs(timestamp_d ,0755)
        with open(timestamp_f, 'w') as f:
            f.write(str(datetime.datetime.now())+'\n')
            f.close()
        return True

    def in_period(self, period):
        if len(period) == 0:
            return True
        if isinstance(period[0], list):
            r = False
            for p in period:
                 r |= self.in_period(p)
            return r
        elif not isinstance(period[0], unicode) or len(period) != 2 or \
             not isinstance(period[1], unicode):
            print >>sys.stderr, "malformed period: %s"%str(period)
            return False
        start_s, end_s = period
        try:
            start_t = time.strptime(start_s, "%H:%M")
            end_t = time.strptime(end_s, "%H:%M")
            start = start_t.tm_hour * 60 + start_t.tm_min
            end = end_t.tm_hour * 60 + end_t.tm_min
        except:
            print >>sys.stderr, "malformed time string: %s"%str(period)
            return False
        now = datetime.datetime.now()
        now_m = now.hour * 60 + now.minute
        if start <= end:
            if now_m >= start and now_m <= end:
                return True
        elif start > end:
            """
                  XXXXXXXXXXXXXXXXX
                  23h     0h      1h
            """
            if (now_m >= start and now_m <= 1440) or \
               (now_m >= 0 and now_m <= end):
                return True
        return False

    def in_days(self, days):
        now = datetime.datetime.now()
        today = now.strftime('%A').lower()
        if today in map(lambda x: x.lower(), days):
            return True
        return False

    def skip_action_period(self, section, option):
        if option is None:
            return False

        if self.config.has_section(section) and \
           self.config.has_option(section, 'period'):
            period_s = self.config.get(section, 'period')
        elif self.config.has_option('DEFAULT', option):
            period_s = self.config.get('DEFAULT', option)
        else:
            return False

        try:
            import json
            period = json.loads(period_s)
        except:
            print >>sys.stderr, "malformed parameter value: %s.period"%section
            return True

        if self.in_period(period):
            return False

        return True

    def skip_action_days(self, section, option):
        if option is None:
            return False

        if self.config.has_section(section) and \
           self.config.has_option(section, 'days'):
            days_s = self.config.get(section, 'days')
        elif self.config.has_option('DEFAULT', option):
            days_s = self.config.get('DEFAULT', option)
        else:
            return False

        try:
            import json
            days = json.loads(days_s)
        except:
            print >>sys.stderr, "malformed parameter value: %s.days"%section
            return True

        if self.in_days(days):
            return False

        return True

    def skip_action(self, section, option, fname,
                    cmdline_parm=None,
                    period_option=None,
                    days_option=None,
                    force=False):

        def err(msg):
            print '%s: skip:'%section, msg, '(--force to bypass)'

        if force:
            return False

        # check if we are in allowed period
        if self.skip_action_period(section, period_option):
            err('out of allowed periods')
            return True

        # check if we are in allowed days of week
        if self.skip_action_days(section, days_option):
            err('out of allowed days')
            return True

        # get interval from config file
        if self.config.has_section(section) and \
           self.config.has_option(section, 'interval'):
            interval = self.config.getint(section, 'interval')
        else:
            interval = self.config.getint('DEFAULT', option)

        # override with command line
        if cmdline_parm is not None:
            v = getattr(self.options, cmdline_parm)
            if v is not None:
                interval = v

        # do we need to run
        timestamp_f = os.path.join(os.path.dirname(__file__), '..', 'var', fname)
        if not self.options.force and not self.timestamp(timestamp_f, interval):
            err('last run < interval')
            return True

        return False

    def pushstats(self):
        if self.skip_action('stats', 'push_interval', 'last_stats_push',
                            period_option='push_period',
                            days_option='push_days',
                            force=self.options.force):
            return

        # get interval from config file
        if self.config.has_section('stats'):
            interval = self.config.getint('stats', 'push_interval')
        else:
            interval = self.config.getint('DEFAULT', 'push_interval')

        xmlrpcClient.push_stats(force=self.options.force,
                                stats_dir=self.options.stats_dir,
                                stats_start=self.options.stats_start,
                                stats_end=self.options.stats_end,
                                interval=2*interval)

    def pushpkg(self):
        if self.skip_action('packages', 'push_interval', 'last_pkg_push',
                            period_option='push_period',
                            days_option='push_days',
                            force=self.options.force):
            return

        xmlrpcClient.push_pkg()

    def pushpatch(self):
        if self.skip_action('patches', 'push_interval', 'last_patch_push',
                            period_option='push_period',
                            days_option='push_days',
                            force=self.options.force):
            return

        xmlrpcClient.push_patch()

    def pushasset(self):
        if self.skip_action('asset', 'push_interval', 'last_asset_push',
                            period_option='push_period',
                            days_option='push_days',
                            force=self.options.force):
            return

        xmlrpcClient.push_asset(self)

    def pushsym(self):
        if self.skip_action('sym', 'push_interval', 'last_sym_push',
                            period_option='push_period',
                            days_option='push_days',
                            force=self.options.force):
            return

        xmlrpcClient.push_sym()

    def syncservices(self):
        self.setup_sync_conf()
        if self.skip_action('sync', 'sync_interval', 'last_sync',
                            period_option='sync_period',
                            days_option='sync_days',
                            force=self.options.force):
            return

        if self.svcs is None:
            self.svcs = svcBuilder.build_services()
        for svc in self.svcs:
            svc.force = self.options.force
            svc.action('syncall')

    def updateservices(self):
        if self.svcs is None:
            self.svcs = svcBuilder.build_services()
        for svc in self.svcs:
            svc.action('presync')

    def pushservices(self):
        if self.skip_action('svcconf', 'push_interval', 'last_svcconf_push',
                            period_option='push_period',
                            days_option='push_days',
                            force=self.options.force):
            return

        if self.svcs is None:
            self.svcs = svcBuilder.build_services()
        for svc in self.svcs:
            svc.action('push')

    def prkey(self):
        from rcGlobalEnv import rcEnv
        m = __import__('hostid'+rcEnv.sysname)
        print m.hostid()

    def checks(self):
        if self.skip_action('checks', 'push_interval', 'last_checks_push',
                            period_option='push_period',
                            days_option='push_days',
                            force=self.options.force):
            return

        import checks
        if self.svcs is None:
            self.svcs = svcBuilder.build_services()
        c = checks.checks(self.svcs)
        c.do_checks()

    def compliance_check(self):
        if self.skip_action('compliance', 'comp_check_interval', 'last_comp_check',
                            period_option='comp_check_period',
                            days_option='comp_check_days',
                            force=self.options.force):
            return
        import compliance
        c = compliance.Compliance(self.options)
        c.do_checks()

    def compliance_fix(self):
        import compliance
        c = compliance.Compliance(self.options)
        c.do_fix()

    def compliance_fixable(self):
        import compliance
        c = compliance.Compliance(self.options)
        c.do_fixable()

    def compliance_show_moduleset(self):
        import compliance
        c = compliance.Compliance(self.options)
        c.do_show_moduleset()

    def compliance_attach_moduleset(self):
        import compliance
        c = compliance.Compliance(self.options)
        c.do_attach_moduleset()

    def compliance_detach_moduleset(self):
        import compliance
        c = compliance.Compliance(self.options)
        c.do_detach_moduleset()

    def compliance_show_ruleset(self):
        import compliance
        c = compliance.Compliance(self.options)
        c.do_show_ruleset()

    def compliance_attach_ruleset(self):
        import compliance
        c = compliance.Compliance(self.options)
        c.do_attach_ruleset()

    def compliance_detach_ruleset(self):
        import compliance
        c = compliance.Compliance(self.options)
        c.do_detach_ruleset()

    def compliance_list_ruleset(self):
        import compliance
        c = compliance.Compliance(self.options)
        c.do_list_rulesets()

    def compliance_list_moduleset(self):
        import compliance
        c = compliance.Compliance(self.options)
        c.do_list_modulesets()

    def delete(self):
        if self.options.param is None:
            print >>sys.stderr, "no parameter. set --param"
            return 1
        l = self.options.param.split('.')
        if len(l) != 2:
            print >>sys.stderr, "malformed parameter. format as 'section.key'"
            return 1
        section, option = l
        if not self.config.has_section(section):
            print >>sys.stderr, "section '%s' not found"%section
            return 1
        if not self.config.has_option(section, option):
            print >>sys.stderr, "option '%s' not found in section '%s'"%(option, section)
            return 1
        try:
            self.config.remove_option(section, option)
            self.write_config()
        except:
            return 1
        return 0

    def get(self):
        if self.options.param is None:
            print >>sys.stderr, "no parameter. set --param"
            return 1
        l = self.options.param.split('.')
        if len(l) != 2:
            print >>sys.stderr, "malformed parameter. format as 'section.key'"
            return 1
        section, option = l
        if not self.config.has_section(section):
            print >>sys.stderr, "section '%s' not found"%section
            return 1
        if not self.config.has_option(section, option):
            print >>sys.stderr, "option '%s' not found in section '%s'"%(option, section)
            return 1
        print self.config.get(section, option)
        return 0

    def set(self):
        if self.options.param is None:
            print >>sys.stderr, "no parameter. set --param"
            return 1
        if self.options.value is None:
            print >>sys.stderr, "no value. set --value"
            return 1
        l = self.options.param.split('.')
        if len(l) != 2:
            print >>sys.stderr, "malformed parameter. format as 'section.key'"
            return 1
        section, option = l
        if not self.config.has_section(section):
            self.config.add_section(section)
        if self.config.has_option(section, option) and \
           self.config.get(section, option) == self.options.value:
            return
        self.config.set(section, option, self.options.value)
        try:
            self.write_config()
        except:
            return 1
        return 0

if __name__ == "__main__" :
    for n in (Node,) :
        help(n)
070701000671f2000081a40000000000000000000000014d9d7e6e00000b3e000000b600010002ffffffffffffffff0000002800000000root/opt/opensvc/lib/rcIfconfigLinux.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

from subprocess import *

import rcIfconfig

class ifconfig(rcIfconfig.ifconfig):
    def parse(self, out):
        prev = ''
        prevprev = ''
        for w in out.split():
            if w == 'Link':
                i = rcIfconfig.interface(prev)
                self.intf.append(i)

                # defaults
                i.link_encap = ''
                i.scope = ''
                i.bcast = ''
                i.mask = ''
                i.mtu = ''
                i.ipaddr = ''
                i.ip6addr = []
                i.ip6mask = []
                i.hwaddr = ''
                i.flag_up = False
                i.flag_broadcast = False
                i.flag_running = False
                i.flag_multicast = False
                i.flag_loopback = False
            elif 'encap:' in w:
                (null, i.link_encap) = w.split(':')
            elif 'Scope:' in w:
                (null, i.scope) = w.split(':')
            elif 'Bcast:' in w:
                (null, i.bcast) = w.split(':')
            elif 'Mask:' in w:
                (null, i.mask) = w.split(':')
            elif 'MTU:' in w:
                (null, i.mtu) = w.split(':')

            if 'inet' == prev and 'addr:' in w:
                (null, i.ipaddr) = w.split(':')
            if 'inet6' == prevprev and 'addr:' == prev:
                (ip6addr, ip6mask) = w.split('/')
                i.ip6addr += [ip6addr]
                i.ip6mask += [ip6mask]
            if 'HWaddr' == prev:
                i.hwaddr = w
            if 'UP' == w:
                i.flag_up = True
            if 'BROADCAST' == w:
                i.flag_broadcast = True
            if 'RUNNING' == w:
                i.flag_running = True
            if 'MULTICAST' == w:
                i.flag_multicast = True
            if 'LOOPBACK' == w:
                i.flag_loopback = True

            prevprev = prev
            prev = w

    def __init__(self):
        self.intf = []
        out = Popen(['ifconfig', '-a'], stdout=PIPE).communicate()[0]
        self.parse(out)
  07070100067253000081a40000000000000000000000014d9d7e6e0000092a000000b600010002ffffffffffffffff0000002700000000root/opt/opensvc/lib/resVgLibvirtVm.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import re
import os
import rcExceptions as ex
import rcStatus
resVg = __import__("resDg")
from subprocess import *
from rcUtilities import qcall
from rcGlobalEnv import rcEnv
from subprocess import *

class Vg(resVg.Dg):
    def __init__(self, rid=None, name=None, type=None,
                 optional=False, disabled=False, tags=set([])):
        self.label = name
        resVg.Dg.__init__(self, rid=rid, name=name,
                          type='disk.vg',
                          optional=optional, disabled=disabled, tags=tags)

    def has_it(self):
        return True

    def is_up(self):
        return True

    def _status(self, verbose=False):
        return rcStatus.NA

    def do_start(self):
        pass

    def do_stop(self):
        pass

    def disklist(self):
        if self.disks != set():
            return self.disks

        self.disks = set()
        devps = set()

        from xml.etree.ElementTree import ElementTree, SubElement
        tree = ElementTree()
        tree.parse(self.svc.resources_by_id['container'].cf)
        for dev in tree.getiterator('disk'):
            s = dev.find('source')
            if s is None:
                 continue
            il = s.items()
            if len(il) != 1:
                 continue
            attr, devp = il[0]
            devps |= set([devp])

        try:
	    u = __import__('rcUtilities'+rcEnv.sysname)
            self.disks = u.devs_to_disks(self, devps)
        except:
            self.disks = devps

        return self.disks
  070701000671fc000081a40000000000000000000000014d9d7e6e0000097f000000b600010002ffffffffffffffff0000002700000000root/opt/opensvc/lib/rcMountsDarwin.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcMounts
from rcUtilities import *
from subprocess import Popen

def get_src_dir_dev(dev):
    """Given a directory path, return its hosting device
    """
    process = Popen(['df', '-l', dev], stdout=PIPE, stderr=STDOUT, close_fds=True)
    buff = process.communicate()
    out = buff[0]
    i = out.index('/')
    return out[i:].split()[0]

class Mounts(rcMounts.Mounts):

    def match_mount(self, i, dev, mnt):
        """Given a line of 'mount' output, returns True if (dev, mnt) matches
        this line. Returns False otherwize. Also care about weirdos like loops
        and binds, ...
        """
        if os.path.isdir(dev):
            is_bind = True
            src_dir_dev = get_src_dir_dev(dev)
        else:
            is_bind = False

        if i.mnt != mnt:
            return False
        if i.dev == dev:
            return True
        if is_bind and i.dev == src_dir_dev:
            return True
        return False

    def __init__(self):
        self.mounts = []
        (ret, out) = call(['mount'])
        for l in out.split('\n'):
            words = l.split()
            if len(words) < 4:
                return
            dev = words[0]
            mnt = words[2]
            opts = ' '.join(words[3:]).strip('(').strip(')').split(', ')
            type = opts[0]
            if len(opts) < 3:
                mnt_opt = ''
            else:
                mnt_opt = ','.join(opts[2:])
            m = rcMounts.Mount(dev, mnt, type, mnt_opt)
            self.mounts.append(m)

if __name__ == "__main__" :
    help(Mounts)
    for m in Mounts():
        print m
 0707010006722b000081a40000000000000000000000014d9d7e6e0000077e000000b600010002ffffffffffffffff0000002100000000root/opt/opensvc/lib/resIpAIX.py  #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.
"Module implement Linux specific ip management"

import resIp as Res
import rcExceptions as ex
from rcUtilitiesAIX import check_ping

class Ip(Res.Ip):
    def check_ping(self):
        return check_ping(self.addr)

    def arp_announce(self):
        return

    def startip_cmd(self):
        if ':' in self.addr:
            if '.' in self.mask:
                self.log.error("netmask parameter is mandatory for ipv6 adresses")
                raise ex.excError
            cmd = ['ifconfig', self.ipDev, 'inet6', 'alias', '/'.join([self.addr, self.mask])]
        else:
            cmd = ['ifconfig', self.ipDev, self.addr, 'netmask', self.mask, 'alias']
        return self.vcall(cmd)

    def stopip_cmd(self):
        if ':' in self.addr:
            cmd = ['ifconfig', self.ipDev, 'inet6', self.addr, 'delete']
        else:
            cmd = ['ifconfig', self.ipDev, self.addr, 'delete']
        return self.vcall(cmd)



if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

  07070100067255000081a40000000000000000000000014d9d7e6e00001045000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/resVgVeritas.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.
"""Module providing Veritas Volume group resources
"""

import resDg
import re
from rcUtilities import qcall

class Vg(resDg.Dg):
    """ basic Veritas Volume group resource
    """
    def __init__(self, rid=None, name=None, type=None,
                 optional=False, disabled=False, tags=set([]),
                 always_on=set([])):
        self.label = name
        resDg.Dg.__init__(self, rid=rid, name=name,
                          type='disk.vg',
                          always_on=always_on,
                          optional=optional, disabled=disabled, tags=tags)

    def has_it(self):
        """Returns True if the vg is present
        """
        ret = qcall( [ 'vxdg', 'list', self.name ] )
        if ret == 0 :
            return True
        else:
            return False

    def is_up(self):
        """Returns True if the vg is present and not disabled
        """
        if not self.has_it():
            return False
        cmd = [ 'vxprint', '-ng', self.name ]
        ret = qcall(cmd)
        if ret == 0 :
                return True
        else:
                return False

    def do_startvol(self):
        cmd = [ 'vxvol', '-g', self.name, '-f', 'startall' ]
        (ret, out) = self.vcall(cmd)
        return ret

    def do_stopvol(self):
        cmd = [ 'vxvol', '-g', self.name, '-f', 'stopall' ]
        (ret, out) = self.vcall(cmd)
        return ret

    def do_start(self):
        if self.is_up():
            self.log.info("%s is already up" % self.name)
            ret = self.do_startvol()
            if self == 0 :
                return 0
            else:
                return ret
        for flag in [ '-t', '-tC', '-tCf']:
            cmd = [ 'vxdg', flag, 'import', self.name ]
            (ret, out) = self.vcall(cmd)
            if ret == 0 :
                ret = self.do_startvol()
                return ret
        return ret

    def do_stop(self):
        if not self.is_up():
            self.log.info("%s is already down" % self.name)
            return 0
        ret = self.do_stopvol()
        cmd = [ 'vxdg', 'deport', self.name ]
        (ret, out) = self.vcall(cmd)
        return ret

    def disklist(self):
        """disklist() search vg disks from
        output of : vxdisk -g vgname -q  path

        disklist(self) update self.disks[]
        """
        if len(self.disks) > 0 :
            return self.disks

        disks = set([])
        cmd = [ 'vxdisk', '-g', self.name, '-q', 'list' ]
        (ret, out) = self.call(cmd, errlog=False)
        if ret != 0 :
            self.disks = disks
            return disks
        for line in out.split('\n'):
            disk = line.split(" ")[0]
            if disk != '' :
                if re.match('^.*s[0-9]$', disk) is None:
                    disk += "s2"
                disks.add("/dev/rdsk/" + disk )
       
        self.log.debug("found disks %s held by pool %s" % (disks, self.name))
        self.disks = disks

        return disks

if __name__ == "__main__":
    for c in (Pool,) :
        help(c)

    print """p=Vg("vzone1vg")"""
    p=Pool("vzone1vg")
    print "show p", p
    print """p.do_action("start")"""
    p.do_action("start")
    print """p.do_action("stop")"""
    p.do_action("stop")
   0707010006722e000081a40000000000000000000000014d9d7e6e00000791000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/resIpHP-UX.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.
"Module implement Linux specific ip management"

import resIp as Res
u = __import__('rcUtilitiesHP-UX')

class Ip(Res.Ip):
    def check_ping(self):
        return u.check_ping(self.addr)

    def arp_announce(self):
        """ arp_announce job is done by HP-UX ifconfig... """
        return

    def startip_cmd(self):
        if ':' in self.addr:
            cmd = ['ifconfig', self.ipDev, 'inet6', 'up']
            (ret, out) = self.vcall(cmd)
            if ret != 0:
                raise ex.excError
            cmd = ['ifconfig', self.stacked_dev, 'inet6', self.addr+'/'+self.mask, 'up']
        else:
            cmd = ['ifconfig', self.stacked_dev, self.addr, 'netmask', self.mask, 'up']
        return self.vcall(cmd)

    def stopip_cmd(self):
        if ':' in self.addr:
            cmd = ['ifconfig', self.stacked_dev, "inet6", "::"]
        else:
            cmd = ['ifconfig', self.stacked_dev, "0.0.0.0"]
        return self.vcall(cmd)



if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

   0707010006723e000081a40000000000000000000000014d9d7e6e00001597000000b600010002ffffffffffffffff0000002700000000root/opt/opensvc/lib/resMountDarwin.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import os

import rcMountsFreeBSD as rcMounts
import resMount as Res
from rcUtilities import qcall, protected_mount, getmount
from rcGlobalEnv import rcEnv
import rcExceptions as ex
from stat import *

def try_umount(self):
    cmd = ['umount', self.mountPoint]
    (ret, out) = self.vcall(cmd, err_to_warn=True)
    if ret == 0:
        return 0

    """ don't try to kill process using the source of a 
        protected bind mount
    """
    if protected_mount(self.mountPoint):
        return 1

    """ best effort kill of all processes that might block
        the umount operation. The priority is given to mass
        action reliability, ie don't contest oprator's will
    """
    cmd = ['sync']
    (ret, out) = self.vcall(cmd)

    for i in range(4):
        nb_killed = self.killfuser(self.mountPoint)
        self.log.info('umount %s'%self.mountPoint)
        cmd = ['umount', self.mountPoint]
        ret = qcall(cmd)
        if ret == 0 or nb_killed == 0:
            break

    if ret != 0:
        self.log.info("no more process using %s, yet umount fails. try forced umount."%self.mountPoint)
        cmd = ['umount', '-f', self.mountPoint]
        (ret, out) = self.vcall(cmd)

    return ret


class Mount(Res.Mount):
    """ define FreeBSD mount/umount doAction """
    def __init__(self, rid, mountPoint, device, fsType, mntOpt,
                 snap_size=None, always_on=set([]),
                 disabled=False, tags=set([]), optional=False):
        self.Mounts = None
        Res.Mount.__init__(self, rid, mountPoint, device, fsType, mntOpt,
                           snap_size, always_on,
                           disabled=disabled, tags=tags, optional=optional)
        self.fsck_h = {
            'ufs': {'bin': 'fsck', 'cmd': ['fsck', '-t', 'ufs', '-p', self.device]},
        }

    def killfuser(self, dir):
        cmd = ['fuser', '-kmc', dir]
        (ret, out) = self.vcall(cmd, err_to_info=True)

        """ return the number of process we sent signal to
        """
        l = out.split(':')
        if len(l) < 2:
            return 0
        return len(l[1].split())

    def is_up(self):
        self.Mounts = rcMounts.Mounts()
        return self.Mounts.has_mount(self.device, self.mountPoint)

    def realdev(self):
        dev = None
        try:
            mode = os.stat(self.device)[ST_MODE]
        except:
            self.log.debug("can not stat %s" % self.device)
            return None
        if S_ISCHR(mode):
            dev = self.device
        else:
            mnt = getmount(self.device)
            if self.Mounts is None:
                self.Mounts = rcMounts.Mounts()
            m = self.Mounts.has_param("mnt", mnt)
            if m is None:
                self.log.debug("can't find dev %(dev)s mounted in %(mnt)s in mnttab"%dict(mnt=mnt, dev=self.device))
                return None
            dev = m.dev

        return dev

    def disklist(self):
        dev = self.realdev()
        if dev is None:
            return set([])

        try:
            statinfo = os.stat(dev)
        except:
            self.log.error("can not stat %s" % dev)
            raise ex.excError

        return set([dev])

    def can_check_writable(self):
        return True

    def start(self):
        if self.Mounts is None:
            self.Mounts = rcMounts.Mounts()
        Res.Mount.start(self)
        if self.is_up() is True:
            self.log.info("fs(%s %s) is already mounted"%
                (self.device, self.mountPoint))
            return 0
        self.fsck()
        if not os.path.exists(self.mountPoint):
            os.makedirs(self.mountPoint, 0755)
        if self.fsType != "":
            fstype = ['-t', self.fsType]
        else:
            fstype = []
        if self.mntOpt != "":
            mntopt = ['-o', self.mntOpt]
        else:
            mntopt = []
        cmd = ['mount']+fstype+mntopt+[self.device, self.mountPoint]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError
        self.Mounts = None

    def stop(self):
        if self.Mounts is None:
            self.Mounts = rcMounts.Mounts()
        if self.is_up() is False:
            self.log.info("fs(%s %s) is already umounted"%
                    (self.device, self.mountPoint))
            return
        for i in range(3):
            ret = try_umount(self)
            if ret == 0: break
        if ret != 0:
            self.log.error('failed to umount %s'%self.mountPoint)
            raise ex.excError
        self.Mounts = None

if __name__ == "__main__":
    for c in (Mount,) :
        help(c)

 07070100067268000081a40000000000000000000000014d9d7e6e000005a0000000b600010002ffffffffffffffff0000001f00000000root/opt/opensvc/lib/svcXen.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import svc
import resContainerXen as xen
from rcGlobalEnv import rcEnv

class SvcXen(svc.Svc):
    """ Define Xen services"""

    def __init__(self, svcname, vmname=None, guestos=None, optional=False, disabled=False, tags=set([])):
        svc.Svc.__init__(self, svcname, optional=optional, disabled=disabled, tags=tags)
        if vmname is None:
            vmname = svcname
        self.vmname = vmname
        self.guestos = guestos
        self += xen.Xen(vmname)
        self.runmethod = rcEnv.rsh.split() + [vmname]


070701000671e8000081a40000000000000000000000014d9d7e6e00000d72000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/rcExceptions.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

class excError(Exception):
    """ Failed action
    """
    def __init__(self, value=""):
        self.value = value
    def __str__(self):
        return str(self.value)

class OptNotFound(Exception):
    """ Service config file option not found
    """

class excSignal(Exception):
    """ Termination signal received
    """

class excUndefined(Exception):
    """ Mandatory Undefined action exception
    """
    def __init__(self,action=None,className=None,func=None):
        self.action=action
        self.className=className
        self.func=func
    def __str__(self):
        return "Undefined mandatory Action %s for className %s in function %s" % \
                (self.action,self.className,self.func)

class syncNoNodesToSync(Exception):
    """ No nodes to sync => abort stacked syncs resource actions
    """

class syncNoFilesToSync(Exception):
    """ No files to sync => move on to the next stacked syncs resource actions
    """

class syncConfigSyntaxError(Exception):
    """ Bogus configuration syntax => abort all
    """

class syncNotSnapable(Exception):
    """ A dir/file specified as source of a sync with snap is not included in a 
        snapable resource mount => abort all
    """

class syncSnapExists(Exception):
    """ The snapshot already exists
    """

class syncSnapCreateError(Exception):
    """ Error in snapshot creation => clean up
    """

class syncSnapDestroyError(Exception):
    """ Error in snapshot destroy => clean up
    """

class syncSnapMountError(Exception):
    """ Error mounting fs => clean up
    """

class excAbortAction(Exception):
    """ Abort multi-resource action
    """

class excInitError(Exception):
    """ Resource initialisation error
    """

class excScsiPrNotsupported(Exception):
    """ Scsi persistent reservation is not supported
    """

class excNotAvailable(Exception):
    """ Not available
    """

class excNotSupported(Exception):
    """ Not supported
    """

class MissImpl(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

class IpDevDown(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

class IpConflict(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

class IpAlreadyUp(Exception):
    def __init__(self, value):
        self.value = value
    def __str__(self):
        return repr(self.value)

  07070100067201000081a40000000000000000000000014d9d7e6e000004d9000000b600010002ffffffffffffffff0000001f00000000root/opt/opensvc/lib/rcNode.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import sys
import re
from rcGlobalEnv import *
import logging
import rcExceptions as ex

def node_get_hostmode():
    import node
    n = node.Node()
    if n.config.has_section('node'):
        return n.config.get('node', 'host_mode')
    return n.config.get('DEFAULT', 'host_mode')

def discover_node():
	"""Fill rcEnv class with information from node discovery
	"""
	rcEnv.host_mode = node_get_hostmode()

   070701000671d7000081a40000000000000000000000014d9d7e6e0000059f000000b600010002ffffffffffffffff0000002200000000root/opt/opensvc/lib/loopSunOS.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import resources
from rcGlobalEnv import *
import rcStatus

class Loop(resources.Resource):
    def is_up(self):
        """Returns True if the volume group is present and activated
        """
        return True

    def start(self):
        pass

    def stop(self):
        pass

    def status(self, verbose=False):
        if self.is_up():
            return rcStatus.UP
        else:
            return rcStatus.DOWN

    def __init__(self, file, disabled=False, tags=set([]), optional=False):
        self.file = file
        resources.Resource.__init__(self, disabled=disabled, tags=tags, optional=optional)
 0707010006726b000081a40000000000000000000000014d9d7e6e00003846000000b600010002ffffffffffffffff0000002500000000root/opt/opensvc/lib/xmlrpcClient.py  #!/usr/bin/python
#
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from datetime import datetime, timedelta
import xmlrpclib
import os
from rcGlobalEnv import rcEnv
import rcStatus
import socket
import httplib

class TimeoutHTTP(httplib.HTTP):
   def __init__(self, host='', port=None, strict=None,
                timeout=socket._GLOBAL_DEFAULT_TIMEOUT):
       if port == 0:
           port = None
       self._setup(self._connection_class(host, port, strict, timeout))

class TimeoutTransport(xmlrpclib.Transport):
    def __init__(self, timeout=socket._GLOBAL_DEFAULT_TIMEOUT, *args, **kwargs):
        xmlrpclib.Transport.__init__(self, *args, **kwargs)
        self.timeout = timeout

    def make_connection(self, host):
        host, extra_headers, x509 = self.get_host_info(host)
        conn = TimeoutHTTP(host, timeout=self.timeout)
        return conn

class TimeoutServerProxy(xmlrpclib.ServerProxy):
    def __init__(self, uri, timeout=socket._GLOBAL_DEFAULT_TIMEOUT,
                 *args, **kwargs):
        kwargs['transport'] = TimeoutTransport(timeout=timeout,
                                               use_datetime=kwargs.get('use_datetime', 0))
        xmlrpclib.ServerProxy.__init__(self, uri, *args, **kwargs)

sysname, nodename, x, x, machine = os.uname()
hostId = __import__('hostid'+sysname)
hostid = hostId.hostid()

def xmlrpc_decorator_dummy(fn):
    def new(*args):
        pass
    return new

def xmlrpc_decorator(fn):
    def new(*args):
        try:
            return fn(*args)
        except (socket.error, xmlrpclib.ProtocolError):
            """ normal for collector communications disabled
                through 127.0.0.1 == dbopensvc
            """
            pass
        except socket.timeout:
            print "connection to collector timed out"
        except:
            import sys
            import traceback
            e = sys.exc_info()
            print e[0], e[1], traceback.print_tb(e[2])
    return new

try:
    a = socket.getaddrinfo(rcEnv.dbopensvc_host, None)
    if len(a) == 0:
        raise Exception
except:
    print("could not resolve %s to an ip address. disable collector updates."%rcEnv.dbopensvc)
    xmlrpc_decorator = xmlrpc_decorator_dummy

proxy = TimeoutServerProxy(rcEnv.dbopensvc, timeout=20)
try:
    proxy_methods = proxy.system.listMethods()
except:
    proxy_methods = []

comp_proxy = TimeoutServerProxy(rcEnv.dbcompliance, timeout=120)
try:
    comp_proxy_methods = comp_proxy.system.listMethods()
except:
    comp_proxy_methods = []

@xmlrpc_decorator
def begin_action(svc, action, begin):
    try:
        import version
        version = version.version
    except:
        version = "0";

    proxy.begin_action(
        ['svcname',
         'action',
         'hostname',
         'hostid',
         'version',
         'begin',],
        [repr(svc.svcname),
         repr(action),
         repr(rcEnv.nodename),
         repr(hostid),
         repr(version),
         repr(str(begin))]
    )

@xmlrpc_decorator
def end_action(svc, action, begin, end, logfile):
    err = 'ok'
    dateprev = None
    lines = open(logfile, 'r').read()
    pids = set([])

    """Example logfile line:
    2009-11-11 01:03:25,252;DISK.VG;INFO;unxtstsvc01_data is already up;10200;EOL
    """
    vars = ['svcname',
            'action',
            'hostname',
            'hostid',
            'pid',
            'begin',
            'end',
            'status_log',
            'status']
    vals = []
    for line in lines.split(';EOL\n'):
        if line.count(';') != 4:
            continue
        date = line.split(';')[0]

        """Push to database the previous line, so that begin and end
        date are available.
        """
        if dateprev is not None:
            res = res.lower()
            res = res.replace(svc.svcname+'.','')
            vals.append([svc.svcname,
                         res+' '+action,
                         rcEnv.nodename,
                         hostid,
                         pid,
                         dateprev,
                         date,
                         msg,
                         res_err])

        res_err = 'ok'
        (date, res, lvl, msg, pid) = line.split(';')

        # database overflow protection
        trim_lim = 10000
        trim_tag = ' <trimmed> '
        trim_head = int(trim_lim/2)
        trim_tail = trim_head-len(trim_tag)
        if len(msg) > trim_lim:
            msg = msg[:trim_head]+' <trimmed> '+msg[-trim_tail:]

        pids |= set([pid])
        if lvl is None or lvl == 'DEBUG':
            continue
        if lvl == 'ERROR':
            err = 'err'
            res_err = 'err'
        if lvl == 'WARNING' and err != 'err':
            err = 'warn'
        if lvl == 'WARNING' and res_err != 'err':
            res_err = 'warn'
        dateprev = date

    """Push the last log entry, using 'end' as end date
    """
    if dateprev is not None:
        res = res.lower()
        res = res.replace(svc.svcname+'.','')
        vals.append([svc.svcname,
                     res+' '+action,
                     rcEnv.nodename,
                     hostid,
                     pid,
                     dateprev,
                     date,
                     msg,
                     res_err])

    if len(vals) > 0:
        proxy.res_action_batch(vars, vals)

    """Complete the wrap-up database entry
    """

    """ If logfile is empty, default to current process pid
    """
    if len(pids) == 0:
        pids = set([os.getpid()])

    proxy.end_action(
        ['svcname',
         'action',
         'hostname',
         'hostid',
         'pid',
         'begin',
         'end',
         'time',
         'status'],
        [repr(svc.svcname),
         repr(action),
         repr(rcEnv.nodename),
         repr(hostid),
         repr(','.join(map(str, pids))),
         repr(str(begin)),
         repr(str(end)),
         repr(str(end-begin)),
         repr(str(err))]
    )

@xmlrpc_decorator
def svcmon_update_combo(g_vars, g_vals, r_vars, r_vals):
    if 'svcmon_update_combo' in proxy_methods:
        proxy.svcmon_update_combo(g_vars, g_vals, r_vars, r_vals)
    else:
        proxy.svcmon_update(g_vars, g_vals)
        proxy.resmon_update(r_vars, r_vals)

@xmlrpc_decorator
def push_service(svc):
    def envfile(svc):
        envfile = os.path.join(rcEnv.pathsvc, 'etc', svc+'.env')
        if not os.path.exists(envfile):
            return
        with open(envfile, 'r') as f:
            buff = ""
            for line in f.readlines():
                l = line.strip()
                if len(l) == 0:
                    continue
                if l[0] == '#' or l[0] == ';':
                    continue
                buff += line
            return buff
        return

    try:
        import version
        version = version.version
    except:
        version = "0";

    if hasattr(svc, "guestos"):
        guestos = svc.guestos
    else:
        guestos = ""

    vars = ['svc_hostid',
            'svc_name',
            'svc_vmname',
            'svc_cluster_type',
            'svc_flex_min_nodes',
            'svc_flex_max_nodes',
            'svc_flex_cpu_low_threshold',
            'svc_flex_cpu_high_threshold',
            'svc_type',
            'svc_nodes',
            'svc_drpnode',
            'svc_drpnodes',
            'svc_comment',
            'svc_drptype',
            'svc_autostart',
            'svc_app',
            'svc_containertype',
            'svc_envfile',
            'svc_version',
            'svc_drnoaction',
            'svc_guestos']

    vals = [repr(hostid),
            repr(svc.svcname),
            repr(svc.vmname),
            repr(svc.clustertype),
            repr(svc.flex_min_nodes),
            repr(svc.flex_max_nodes),
            repr(svc.flex_cpu_low_threshold),
            repr(svc.flex_cpu_high_threshold),
            repr(svc.svctype),
            repr(' '.join(svc.nodes)),
            repr(svc.drpnode),
            repr(' '.join(svc.drpnodes)),
            repr(svc.comment),
            repr(svc.drp_type),
            repr(' '.join(svc.autostart_node)),
            repr(svc.app),
            repr(svc.svcmode),
            repr(envfile(svc.svcname)),
            repr(version),
            repr(svc.drnoaction),
            repr(guestos)]

    if 'container' in svc.resources_by_id:
        container_info = svc.resources_by_id['container'].get_container_info()
        vars += ['svc_vcpus', 'svc_vmem']
        vals += [container_info['vcpus'],
                 container_info['vmem']]

    proxy.update_service(vars, vals)

@xmlrpc_decorator
def delete_services():
    proxy.delete_services(hostid)

@xmlrpc_decorator
def push_disks(svc):
    def disk_dg(dev, svc):
        for rset in svc.get_res_sets("disk.vg"):
            for vg in rset.resources:
                if vg.is_disabled():
                    continue
                if not vg.name in disklist_cache:
                    disklist_cache[vg.name] = vg.disklist()
                if dev in disklist_cache[vg.name]:
                    return vg.name
        return ""

    di = __import__('rcDiskInfo'+sysname)
    disks = di.diskInfo()
    disklist_cache = {}

    proxy.delete_disks(svc.svcname, rcEnv.nodename)

    for d in svc.disklist():
        if disks.disk_id(d) is None or disks.disk_id(d) == "":
            """ no point pushing to db an empty entry
            """
            continue
        proxy.register_disk(
            ['disk_id',
             'disk_svcname',
             'disk_size',
             'disk_vendor',
             'disk_model',
             'disk_dg',
             'disk_nodename'],
            [repr(disks.disk_id(d)),
             repr(svc.svcname),
             repr(disks.disk_size(d)),
             repr(disks.disk_vendor(d)),
             repr(disks.disk_model(d)),
             repr(disk_dg(d, svc)),
             repr(rcEnv.nodename)]
        )

@xmlrpc_decorator
def push_stats_fs_u(l):
    proxy.insert_stats_fs_u(l[0], l[1])

@xmlrpc_decorator
def push_pkg():
    p = __import__('rcPkg'+sysname)
    vars = ['pkg_nodename',
            'pkg_name',
            'pkg_version',
            'pkg_arch']
    vals = p.listpkg()
    proxy.delete_pkg(rcEnv.nodename)
    proxy.insert_pkg(vars, vals)

@xmlrpc_decorator
def push_patch():
    p = __import__('rcPkg'+sysname)
    vars = ['patch_nodename',
            'patch_num',
            'patch_rev']
    vals = p.listpatch()
    proxy.delete_patch(rcEnv.nodename)
    proxy.insert_patch(vars, vals)

def push_stats(force=False, interval=None, stats_dir=None, stats_start=None, stats_end=None):
    try:
        s = __import__('rcStats'+sysname)
    except ImportError:
        return
    sp = s.StatsProvider(interval=interval,
                         stats_dir=stats_dir,
                         stats_start=stats_start,
                         stats_end=stats_end)
    h = {}
    for stat in ['cpu', 'mem_u', 'proc', 'swap', 'block',
                 'blockdev', 'netdev', 'netdev_err']:
        h[stat] = sp.get(stat)
    import cPickle
    proxy.insert_stats(cPickle.dumps(h))

def push_asset(node):
    try:
        m = __import__('rcAsset'+sysname)
    except ImportError:
        print "pushasset methods not implemented on", sysname
        return
    if "update_asset" not in proxy_methods:
        print "'update_asset' method is not exported by the collector"
        return
    d = m.Asset(node).get_asset_dict()
    proxy.update_asset(d.keys(), d.values())

def push_sym():
    if 'update_sym_xml' not in proxy_methods:
	print "'update_sym_xml' method is not exported by the collector"
	return
    m = __import__('rcSymmetrix')
    try:
        syms = m.Syms()
    except:
        return
    for sym in syms:
        vals = []
        for key in sym.keys:
            vals.append(getattr(sym, 'get_'+key)())
        proxy = TimeoutServerProxy(rcEnv.dbopensvc, timeout=180)
        proxy.update_sym_xml(sym.sid, sym.keys, vals)

@xmlrpc_decorator
def push_all(svcs):
    proxy.delete_service_list([svc.svcname for svc in svcs])
    for svc in svcs:
        push_disks(svc)
        push_service(svc)

@xmlrpc_decorator
def push_checks(vars, vals):
    if "push_checks" not in proxy_methods:
        print "'push_checks' method is not exported by the collector"
        return
    proxy.push_checks(vars, vals)

@xmlrpc_decorator
def comp_get_moduleset_modules(moduleset):
    return comp_proxy.comp_get_moduleset_modules(moduleset)

@xmlrpc_decorator
def comp_get_moduleset():
    return comp_proxy.comp_get_moduleset(rcEnv.nodename)

@xmlrpc_decorator
def comp_attach_moduleset(moduleset):
    return comp_proxy.comp_attach_moduleset(rcEnv.nodename, moduleset)

@xmlrpc_decorator
def comp_detach_moduleset(moduleset):
    return comp_proxy.comp_detach_moduleset(rcEnv.nodename, moduleset)

@xmlrpc_decorator
def comp_get_ruleset():
    return comp_proxy.comp_get_ruleset(rcEnv.nodename)

@xmlrpc_decorator
def comp_get_dated_ruleset(date):
    return comp_proxy.comp_get_dated_ruleset(rcEnv.nodename, date)

@xmlrpc_decorator
def comp_attach_ruleset(ruleset):
    return comp_proxy.comp_attach_ruleset(rcEnv.nodename, ruleset)

@xmlrpc_decorator
def comp_detach_ruleset(ruleset):
    return comp_proxy.comp_detach_ruleset(rcEnv.nodename, ruleset)

@xmlrpc_decorator
def comp_list_ruleset(pattern='%'):
    return comp_proxy.comp_list_rulesets(pattern)

@xmlrpc_decorator
def comp_list_moduleset(pattern='%'):
    return comp_proxy.comp_list_modulesets(pattern)

@xmlrpc_decorator
def comp_log_action(vars, vals):
    return comp_proxy.comp_log_action(vars, vals)
  07070100067207000081a40000000000000000000000014d9d7e6e00000729000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/rcPkgLinux.py    #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
from rcUtilities import call, which
from rcGlobalEnv import rcEnv

def listpkg_dummy():
    print "pushpkg supported on this system"
    return []

def listpkg_rpm():
    (ret, out) = call(cmd, errlog=False, cache=True)
    lines = []
    for line in out.split('\n'):
        l = line.split()
        if len(l) != 3:
            continue
        x = [rcEnv.nodename] + l
        lines.append(x)
    return lines

def listpkg_deb():
    (ret, out) = call(cmd, errlog=False, cache=True)
    lines = []
    arch = ""
    for line in out.split('\n'):
        l = line.split()
        if len(l) < 4:
            continue
        if l[0] != "ii":
            continue
        x = [rcEnv.nodename] + l[1:3] + [arch]
        lines.append(x)
    return lines

if which('dpkg') is not None:
    cmd = ['dpkg', '-l']
    listpkg = listpkg_deb
elif which('rpm') is not None:
    cmd = ['rpm', '-qa', '--queryformat=%{n} %{v}-%{r} %{arch}\n']
    listpkg = listpkg_rpm
else:
    cmd = ['true']
    listpkg = listpkg_dummy

def listpatch():
    return [] 
   07070100067259000081a40000000000000000000000014d9d7e6e0000131a000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/snapJfs2AIX.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os

from rcGlobalEnv import rcEnv
from rcUtilities import which, qcall, protected_mount
import rcExceptions as ex
import snap

class Snap(snap.Snap):
    def lv_exists(self, device):
        device = device.split("/")[-1]
        ret = qcall(['lslv', device], cache=True)
        if ret == 0:
            return True
        return False

    def lv_info(self, device):
        device = device.split("/")[-1]
        (ret, buff) = self.call(['lslv', device], cache=True)
        if ret != 0:
            return (None, None, None)
        vg_name = None
        lv_name = None
        lv_size = 0
        prev = ''
        prevprev = ''
        pp_unit = ''
        pps = 0
        pp_size = 0
        for word in buff.split():
            if prev == "GROUP:":
                vg_name = word
            if prev == "VOLUME:":
                lv_name = word
            if prev == "SIZE:":
                pp_size = int(word)
            if prevprev == "SIZE:":
                pp_unit = word
            if prev == "PPs:" and prevprev != "STALE":
                pps = int(word)
            prevprev = prev
            prev = word

        if pps == 0 or pp_size == 0 or pp_unit == '' or vg_name is None:
            self.log.error("logical volume %s information fetching error"%device)
            print "pps = ", pps
            print "pp_size = ", pp_size
            print "pp_unit = ", pp_unit
            print "vg_name = ", vg_name
            raise ex.excError

        if pp_unit == 'megabyte(s)':
            mult = 1
        elif pp_unit == 'gigabyte(s)':
            mult = 1024
        elif pp_unit == 'terabyte(s)':
            mult = 1024*1024
        else:
            self.log.error("unexpected logical volume PP size unit: %s"%pp_unit)
            raise ex.excError

        return (vg_name, lv_name, pps*pp_size*mult)

    def snapcreate(self, m):
        snap_name = ''
        snap_mnt = ''
        (vg_name, lv_name, lv_size) = self.lv_info(m.device)
        if lv_name is None:
            self.log.error("can not snap %s: not a logical volume"%m.device)
            raise ex.syncNotSnapable
        if len(lv_name) > 12:
            self.log.error("can not snap lv with name >12 chars")
            raise ex.excError
        snap_name = 'sy_'+os.path.basename(lv_name)
        if self.lv_exists(os.path.join(vg_name, snap_name)):
            self.log.error("snap of %s already exists"%(lv_name))
            raise ex.syncSnapExists
        print lv_size
        print lv_size//10
        (ret, buff) = self.vcall(['mklv', '-t', 'jfs2', '-y', snap_name, vg_name, str(lv_size//10)+'M'])
        if ret != 0:
            raise ex.syncSnapCreateError
        snap_mnt = '/service/tmp/osvc_sync_'+os.path.basename(vg_name)+'_'+os.path.basename(lv_name)
        if not os.path.exists(snap_mnt):
            os.makedirs(snap_mnt, 0755)
        snap_dev = os.path.join(os.sep, 'dev', snap_name)
        (ret, buff) = self.vcall(['snapshot', '-o', 'snapfrom='+m.mountPoint, snap_dev])
        if ret != 0:
            raise ex.syncSnapMountError
        (ret, buff) = self.vcall(['mount', '-o', 'snapshot', snap_dev, snap_mnt])
        if ret != 0:
            raise ex.syncSnapMountError
        self.snaps[m.mountPoint] = dict(lv_name=lv_name,
                                        vg_name=vg_name,
                                        snap_name=snap_name,
                                        snap_mnt=snap_mnt,
                                        snap_dev=snap_dev)

    def snapdestroykey(self, s):
        if protected_mount(self.snaps[s]['snap_mnt']):
            self.log.error("the snapshot is no longer mounted in %s. panic."%self.snaps[s]['snap_mnt'])
            raise ex.excError

        """ fuser on HP-UX outs to stderr ...
        """
        cmd = ['fuser', '-c', '-x', '-k', self.snaps[s]['snap_mnt']]
        ret = qcall(cmd)

        cmd = ['umount', self.snaps[s]['snap_mnt']]
        (ret, out) = self.vcall(cmd)
        cmd = ['snapshot', '-d', self.snaps[s]['snap_dev']]
        (ret, buff) = self.vcall(cmd)

  070701000671fb000081a40000000000000000000000014d9d7e6e00000c87000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/rcMountsAIX.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcMounts
#import resLoopAIX as Res
from rcUtilities import *
from subprocess import Popen

def get_src_dir_dev(dev):
    """Given a directory path, return its hosting device
    """
    process = Popen(['df', dev], stdout=PIPE, stderr=STDOUT, close_fds=True)
    buff = process.communicate()
    out = buff[0]
    i = out.index('/')
    return out[i:].split()[0]

class Mounts(rcMounts.Mounts):
    def match_mount(self, i, dev, mnt):
        """Given a line of 'mount' output, returns True if (dev, mnt) matches
        this line. Returns False otherwize. Also care about weirdos like loops
        and binds, ...
        """
        if os.path.isdir(dev):
            is_bind = True
            src_dir_dev = get_src_dir_dev(dev)
        else:
            is_bind = False

        if i.mnt != mnt:
            return False
        if i.dev == dev:
            return True
#        if i.dev in Res.file_to_loop(dev):
#            return True
        if is_bind and i.dev == src_dir_dev:
            return True
        return False

    def __init__(self):
        self.mounts = []
        (ret, out) = call(['mount'])
        lines = out.split('\n')
        if len(lines) < 3:
            return
        for l in lines[2:]:
            if len(l) == 0:
                continue
            x = l.split()
            if x[0][0] == '/':
                dev, mnt, type, null, null, null, mnt_opt = l.split()
            else:
                node, dev, mnt, type, null, null, null, mnt_opt = l.split()
            m = rcMounts.Mount(dev, mnt, type, mnt_opt)
            self.mounts.append(m)

"""
  node       mounted        mounted over    vfs       date        options
-------- ---------------  ---------------  ------ ------------ ---------------
         /dev/hd4         /                jfs2   Jun 14 19:42 rw,log=/dev/hd8
         /dev/hd2         /usr             jfs2   Jun 14 19:42 rw,log=/dev/hd8
         /dev/hd9var      /var             jfs2   Jun 14 19:42 rw,log=/dev/hd8
         /dev/hd3         /tmp             jfs2   Jun 14 19:42 rw,log=/dev/hd8
         /dev/hd1         /home            jfs2   Jun 14 19:48 rw,log=/dev/hd8
         /proc            /proc            procfs Jun 14 19:48 rw
         /dev/hd10opt     /opt             jfs2   Jun 14 19:48 rw,log=/dev/hd8
"""

if __name__ == "__main__" :
    help(Mounts)
    for m in Mounts():
        print m
 070701000671d3000081a40000000000000000000000014d9d7e6e000004b3000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/hostidHP-UX.py   #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
from rcUtilities import which
from subprocess import *

def hostid():
    if which('getconf') is None:
        return '1'
    cmd = ['getconf', 'MACHINE_SERIAL']
    p = Popen(cmd, stderr=None, stdout=PIPE, close_fds=True)
    buff = p.communicate()
    sn = buff[0].split()[0]
    if p.returncode != 0:
        return '1'
    return str(hex(abs(sn.__hash__()))).replace('0x', '')
 070701000671f5000081a40000000000000000000000014d9d7e6e0000045e000000b600010002ffffffffffffffff0000002a00000000root/opt/opensvc/lib/rcIfconfigLinuxvz.py #
# Copyright (c) 2011 Christophe Varoqui <christophe.varoqui@opensvc.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcIfconfigLinux
from rcUtilities import call
import os
import rcExceptions as ex

class ifconfig(rcIfconfigLinux.ifconfig):
    def __init__(self, vmname):
        self.intf = []
        cmd = ['vzctl', 'exec', vmname, '/sbin/ifconfig', '-a']
        ret, out = call(cmd)
        if ret != 0:
            raise ex.excError
        self.parse(out)
  07070100067244000081a40000000000000000000000014d9d7e6e0000162e000000b600010002ffffffffffffffff0000002b00000000root/opt/opensvc/lib/resScsiReservHP-UX.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import resources as Res
import uuid
import re
import os
import time
import rcStatus
import rcExceptions as ex
from rcUtilities import which
from subprocess import *
import resScsiReserv

def mpath_to_path(disks):
    l = []
    for disk in disks:
        if "/dev/dsk" in disk:
            l.append(disk.replace("/dev/dsk", "/dev/rdsk"))
            continue
        if "/dev/disk" not in disk and "/dev/rdisk" not in disk:
            continue
        if not os.path.exists(disk):
            continue
        cmd = ['ioscan', '-F', '-m', 'dsf', disk]
        p = Popen(cmd, stderr=None, stdout=PIPE, close_fds=True)
        buff = p.communicate()
        ret = p.returncode
        if ret != 0:
            continue
        a = buff[0].split(':')
        if len(a) != 2:
            continue
        b = a[1].split()
        for d in b:
            l.append(d.replace("/dev/dsk", "/dev/rdsk"))
    return l
    
class ScsiReserv(resScsiReserv.ScsiReserv):
    def __init__(self, rid=None, disks=set([]),
                 disabled=False, tags=set([]), optional=False):
        resScsiReserv.ScsiReserv.__init__(self, rid=rid, disks=disks,
                                          disabled=disabled, tags=tags, optional=optional)
        self.prtype = 'wero'
        self.disks = mpath_to_path(disks)
        self.leg_mpath_disable()

    def scsireserv_supported(self):
        if which('scu') is None:
            return False
        return True

    def leg_mpath_disable(self):
        cmd = ['scsimgr', 'get_attr', '-p', '-a', 'leg_mpath_enable']
        p = Popen(cmd, stderr=None, stdout=PIPE, close_fds=True)
        buff = p.communicate()
        ret = p.returncode
        if ret != 0:
            self.log.error("can not fetch 'leg_mpath_enable' value")
            raise ex.excError
        if 'false' in buff[0]:
            return
        cmd = ['scsimgr', 'save_attr', '-a', 'leg_mpath_enable=false']
        self.log.info(' '.join(cmd))
        p = Popen(cmd, stderr=None, stdout=PIPE, close_fds=True)
        buff = p.communicate()
        ret = p.returncode
        if ret != 0:
            self.log.error("can not set 'leg_mpath_enable' value")
            raise ex.excError

    def ack_unit_attention(self, d):
        return 0

    def disk_registered(self, disk):
        cmd = [ 'scu', '-f', disk, 'show', 'keys' ]
        (ret, out) = self.call(cmd)
        if ret != 0:
            self.log.error("failed to read registrations for disk %s" % disk)
        if self.hostid in out:
            return True
        return False

    def disk_register(self, disk):
        cmd = [ 'scu', '-f', disk, 'preserve', 'register', 'skey', self.hostid ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            self.log.error("failed to register key %s with disk %s" % (self.hostid, disk))
        return ret

    def disk_unregister(self, disk):
        cmd = [ 'scu', '-f', disk, 'preserve', 'register', 'skey', '0', 'key', self.hostid ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            self.log.error("failed to unregister key %s with disk %s" % (self.hostid, disk))
        return ret

    def get_reservation_key(self, disk):
        cmd = [ 'scu', '-f', disk, 'show', 'reservation' ]
        (ret, out) = self.call(cmd)
        if ret != 0:
            self.log.error("failed to list reservation for disk %s" % disk)
        if 'Reservation Key' not in out:
            return None
        for line in out.split('\n'):
            if 'Reservation Key' in line:
                return line.split()[-1]
        raise Exception()

    def disk_reserved(self, disk):
        cmd = [ 'scu', '-f', disk, 'show', 'reservation' ]
        (ret, out) = self.call(cmd)
        if ret != 0:
            self.log.error("failed to read reservation for disk %s" % disk)
        if self.hostid in out:
            return True
        return False

    def disk_release(self, disk):
        cmd = [ 'scu', '-f', disk, 'preserve', 'release', 'key', self.hostid, 'type', self.prtype ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            self.log.error("failed to release disk %s" % disk)
        return ret

    def disk_reserve(self, disk):
        cmd = [ 'scu', '-f', disk, 'preserve', 'reserve', 'key', self.hostid, 'type', self.prtype ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            self.log.error("failed to reserve disk %s" % disk)
        return ret

    def disk_preempt_reservation(self, disk, oldkey):
        cmd = [ 'scu', '-f', disk, 'preserve', 'preempt', 'key', self.hostid, 'skey', oldkey, 'type', self.prtype ]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            self.log.error("failed to preempt reservation for disk %s" % disk)
        return ret

  070701000671ff000081a40000000000000000000000014d9d7e6e000008f8000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/rcMountsLinux.py #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcMounts
import resLoopLinux as Res
from rcUtilities import *
from subprocess import Popen

def get_src_dir_dev(dev):
    """Given a directory path, return its hosting device
    """
    process = Popen(['df', '-l', dev], stdout=PIPE, stderr=STDOUT, close_fds=True)
    buff = process.communicate()
    out = buff[0]
    i = out.index('/')
    return out[i:].split()[0]

class Mounts(rcMounts.Mounts):

    def match_mount(self, i, dev, mnt):
        """Given a line of 'mount' output, returns True if (dev, mnt) matches
        this line. Returns False otherwize. Also care about weirdos like loops
        and binds, ...
        """
        if os.path.isdir(dev):
            is_bind = True
            src_dir_dev = get_src_dir_dev(dev)
        else:
            is_bind = False

        if i.mnt != mnt:
            return False
        if i.dev == dev:
            return True
        if i.dev in Res.file_to_loop(dev):
            return True
        if is_bind and i.dev == src_dir_dev:
            return True
        return False

    def __init__(self):
        self.mounts = []
        (ret, out) = call(['mount'])
        for l in out.split('\n'):
            if len(l.split()) != 6:
                return
            dev, null, mnt, null, type, mnt_opt = l.split()
            m = rcMounts.Mount(dev, mnt, type, mnt_opt.strip('()'))
            self.mounts.append(m)

if __name__ == "__main__" :
    help(Mounts)
    for m in Mounts():
        print m
070701000671e3000081a40000000000000000000000014d9d7e6e00000378000000b600010002ffffffffffffffff0000002900000000root/opt/opensvc/lib/rcDiskInfoDarwin.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcDiskInfo

class diskInfo(rcDiskInfo.diskInfo):
    pass
070701000671cd000081a40000000000000000000000014d9d7e6e000007a2000000b600010002ffffffffffffffff0000002a00000000root/opt/opensvc/lib/checkVgUsageLinux.py #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import checks
from rcUtilities import justcall

class check(checks.check):
    chk_type = "vg_u"

    def find_svc(self, vgname):
        for svc in self.svcs:
            for rs in svc.get_res_sets('disk.vg'):
                for r in rs.resources:
                    if r.name == vgname:
                        return svc.svcname
        return ''

    def do_check(self):
        cmd = ['vgs', '--units', 'b', '--noheadings',
               '-o', 'vg_name,vg_size,vg_free']
        (out,err,ret) = justcall(cmd)
        if ret != 0:
            return self.undef
        lines = out.split('\n')
        if len(lines) < 1:
            return self.undef
        r = []
        for line in lines:
            l = line.split()
            if len(l) != 3:
                continue
            size = int(l[1].replace('B',''))
            free = int(l[2].replace('B',''))
            val = int(100*(size-free)/size)
            r.append({'chk_instance': l[0],
                      'chk_value': str(val),
                      'chk_svcname': self.find_svc(l[0]),
                     }
                    )
        return r
  07070100067234000081a40000000000000000000000014d9d7e6e0000066c000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/resIpSunOS.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.
"Module implement SunOS specific ip management"

import resIp as Res
from subprocess import *
from rcUtilitiesSunOS import check_ping

class Ip(Res.Ip):
    """ define ip SunOS start/stop doAction """

    def arp_announce(self):
	""" arp_announce job is done by SunOS ifconfig... """
        return

    def check_ping(self):
        return check_ping(self.addr, timeout=2)

    def startip_cmd(self):
        cmd=['ifconfig', self.stacked_dev, 'plumb', self.addr, \
            'netmask', '+', 'broadcast', '+', 'up']
        return self.vcall(cmd)

    def stopip_cmd(self):
        cmd = ['ifconfig', self.stacked_dev, 'unplumb']
        return self.vcall(cmd)

if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

07070100067239000081a40000000000000000000000014d9d7e6e0000072f000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/resLoop.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import resources as Res
from rcGlobalEnv import rcEnv

class Loop(Res.Resource):
    """ basic loopback device resource
    """
    def __init__(self, rid=None, loopFile=None, always_on=set([]),
                 optional=False, disabled=False, tags=set([])):
        Res.Resource.__init__(self, rid, "disk.loop",
                              optional=optional, disabled=disabled, tags=tags)
        self.loopFile = loopFile
        self.label = loopFile
        self.always_on = always_on

    def startstandby(self):
        if rcEnv.nodename in self.always_on:
            self.start()

    def __str__(self):
        return "%s loopfile=%s" % (Res.Resource.__str__(self),\
                                 self.loopFile)

if __name__ == "__main__":
    for c in (Loop,) :
        help(c)

    print """v1=vg("myvg")"""
    v=vg("myvg")
    print "show v", v
    print """v.do_action("start")"""
    v.do_action("start")

 0707010006722c000081a40000000000000000000000014d9d7e6e00000786000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/resIpDarwin.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.
"Module implement Linux specific ip management"

import resIp as Res
import rcExceptions as ex
from rcUtilitiesFreeBSD import check_ping

class Ip(Res.Ip):
    def check_ping(self):
        return check_ping(self.addr)

    def arp_announce(self):
        return

    def startip_cmd(self):
        if ':' in self.addr:
            if '.' in self.mask:
                self.log.error("netmask parameter is mandatory for ipv6 adresses")
                raise ex.excError
            cmd = ['ifconfig', self.ipDev, 'inet6', '/'.join([self.addr, self.mask]), 'add']
        else:
            cmd = ['ifconfig', self.ipDev, 'inet', self.addr, 'netmask', self.mask, 'add']
        return self.vcall(cmd)

    def stopip_cmd(self):
        if ':' in self.addr:
            cmd = ['ifconfig', self.ipDev, 'inet6', self.addr, 'delete']
        else:
            cmd = ['ifconfig', self.ipDev, 'inet', self.addr, 'delete']
        return self.vcall(cmd)



if __name__ == "__main__":
    for c in (Ip,) :
        help(c)

  07070100067264000081a40000000000000000000000014d9d7e6e000005cf000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/svcLdom.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

import svc
import resContainerLdom as ldom
import rcStatus
import rcExceptions as ex
from rcGlobalEnv import rcEnv

class SvcLdom(svc.Svc):
    """ Define ldom services"""

    def __init__(self, svcname, vmname=None, guestos=None, optional=False, disabled=False, tags=set([])):
        svc.Svc.__init__(self, svcname, optional=optional, disabled=disabled, tags=tags)
        if vmname is None:
            vmname = svcname
        self.vmname = vmname
        self.guestos = guestos
        self += ldom.Ldom(vmname)
        self.runmethod = rcEnv.rsh.split() + [vmname]

 070701000671e2000081a40000000000000000000000014d9d7e6e00000944000000b600010002ffffffffffffffff0000002600000000root/opt/opensvc/lib/rcDiskInfoAIX.py #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@opensvc.com>'
# Copyright (c) 2010 Cyril Galibern <cyril.galibern@opensvc.com>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

from rcUtilities import call
import rcDiskInfo

class diskInfo(rcDiskInfo.diskInfo):

    def __init__(self):
        self.h = {}

    def scan(self, lname):
        vid = 'unknown'
        pid = 'unknown'
        wwid = 'unknown'
        size = 'unknown'

        cmd = ['lscfg', '-vpl', lname]
        (ret, out) = call(cmd)

        for f in out.split('\n'):
            if "Manufacturer" in f:
                vid = f.split('.')[-1]
            if "Machine Type and Model" in f:
                pid = f.split('.')[-1]

        size = str(int(self.odmget(lname, 'size_in_mb'))//1024)
        wwid = self.odmget(lname, 'ww_name').replace('0x', '')

        self.h[lname] = dict(vid=vid, pid=pid, wwid=wwid, size=size)

    def odmget(self, lname, attr):
        cmd = ['odmget', '-q', 'name='+lname+' AND attribute='+attr, 'CuAt']
        (ret, out) = call(cmd)
        for f in out.split('\n'):
            if "value" not in f:
                continue
            return f.split(" = ")[-1].strip('"')
        return 'unknown'


    def devkey(self, dev):
        dev = dev.replace("/dev/", "")
        return dev

    def get(self, dev, type):
        if dev not in self.h:
            self.scan(dev)
        dev = self.devkey(dev)
        return self.h[dev][type]

    def disk_id(self, dev):
        return self.get(dev, 'wwid')

    def disk_vendor(self, dev):
        return self.get(dev, 'vid')

    def disk_model(self, dev):
        return self.get(dev, 'pid')

    def disk_size(self, dev):
        return self.get(dev, 'size')

070701000671d0000081a40000000000000000000000014d9d7e6e000006f4000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/lib/freezer.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import glob

def dummy():
    return

class Freezer:
    flag_dir = os.path.join(os.path.dirname(__file__), '..', 'var')
    base_flag = os.path.join(flag_dir, 'FROZEN')
    flag = base_flag

    def frozen(self):
        if os.path.exists(self.flag) or os.path.exists(self.base_flag):
            return True
        return False

    def freeze(self):
        open(self.flag, 'w').close() 

    def thaw(self):
        if self.flag != self.base_flag and os.path.exists(self.flag):
            os.unlink(self.flag)
            return
        for name in glob.glob(self.flag_dir + '/FROZEN*'):
            os.unlink(name)

    def __init__(self, name=''):
        if len(name) == 0:
            pass
        elif not os.path.exists(os.path.join(os.path.dirname(__file__), '..', 'etc', name)):
            self.freeze = dummy
            self.thaw = dummy
            self.frozen = dummy
        else:
            self.flag = self.flag + "." + name
0707010006724c000081a40000000000000000000000014d9d7e6e00000ae5000000b600010002ffffffffffffffff0000002d00000000root/opt/opensvc/lib/resSyncSymcloneLinux.py  #
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import logging

from rcGlobalEnv import rcEnv
from rcUtilities import which
import rcExceptions as ex
import rcStatus
import resources as Res
import time
import datetime
import resSyncSymclone as symclone

class syncSymclone(symclone.syncSymclone):
    def dev_rescan(self, dev):
        dev = dev.replace('/dev/', '')
        sysdev = "/sys/block/%s/device/rescan"%dev
        self.log.info("echo 1>%s"%sysdev)
        with open(sysdev, 'w') as s:
            s.write("1")

    def refresh_multipath(self, dev):
        cmd = ['multipath', '-v0', '-r', dev]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            raise ex.excError

    def dev_ready(self, dev):
        cmd = ['sg_turs', dev]
        (ret, out) = self.vcall(cmd)
        if ret != 0:
            return False
        return True

    def wait_for_dev_ready(self, dev):
        delay = 1
        timeout = 5
        for i in range(timeout/delay):
            if self.dev_ready(dev):
                return
            if i == 0:
                self.log.info("waiting for device %s to become ready (max %i secs)"%(dev,timeout))
            time.sleep(delay)
        self.log.error("timed out waiting for device %s to become ready (max %i secs)"%(dev,timeout))
        raise ex.excError

    def wait_for_devs_ready(self):
        for (symid, devid) in self.symld:
            dev = self.symld[symid, devid]['pdev']
            self.dev_rescan(dev)
            self.wait_for_dev_ready(dev)
            self.refresh_multipath(dev)

    def __init__(self, rid=None, symdg=None, symdevs=[], precopy_timeout=300,
                 sync_max_delay=1440, sync_min_delay=30,
                 optional=False, disabled=False, tags=set([]), internal=False):
        symclone.syncSymclone.__init__(self, rid, symdg, symdevs,
                                       precopy_timeout, sync_max_delay,
                                       sync_min_delay, optional=optional, disabled=disabled, tags=tags,
                                       internal)

   07070100067212000081a40000000000000000000000014d9d7e6e00001afd000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/rcUtilities.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os, sys
import select
import logging
from subprocess import *
from rcGlobalEnv import rcEnv

def fork(fn, kwargs):
    try:
        if os.fork() > 0:
            """ return to parent execution
            """
            return
    except:
        """ no dblogging will be done. too bad.
        """
        return

    """ separate the son from the father
    """
    os.chdir('/')
    os.setsid()
    os.umask(0)

    try:
        pid = os.fork()
        if pid > 0:
            os._exit(0)
    except:
        os._exit(1)

    fn(**kwargs)
    os._exit(0)

def check_privs():
    if os.getuid() != 0:
        print 'Insufficient privileges. Try:\n sudo ' + ' '.join(sys.argv)
        sys.exit(1)


def banner(text, ch='=', length=78):
    spaced_text = ' %s ' % text
    banner = spaced_text.center(length, ch)
    return banner

def is_exe(fpath):
    """Returns True if file path is executable, False otherwize
    does not follow symlink
    """
    return os.path.exists(fpath) and os.access(fpath, os.X_OK)

def which(program):
    """Returns True if program is in PATH and executable, False
    otherwize
    """
    fpath, fname = os.path.split(program)
    if fpath and is_exe(program):
        return program
    for path in os.environ["PATH"].split(os.pathsep):
        exe_file = os.path.join(path, program)
        if is_exe(exe_file):
            return exe_file
    return None

def justcall(argv=['/bin/false']):
    """subprosses call argv, return (stdout,stderr,returncode)
    """
    if which(argv[0]) is None:
        return ("", "", 1)
    process = Popen(argv, stdout=PIPE, stderr=PIPE, close_fds=True)
    (stdout, stderr)=process.communicate(input=None)
    return (stdout, stderr, process.returncode)

def empty_string(buff):
    b = buff.strip(' ').strip('\n')
    if len(b) == 0:
        return True
    return False

def call(argv=['/bin/false'],
         cache=False,      # serve/don't serve cmd output from cache
         log=None,         # callers should provide there own logger
                           # or we'll have to allocate a generic one

         info=False,       # False: log cmd as debug
                           # True:  log cmd as info

         outlog=False,     # False: discard stdout

         errlog=True,      # False: discard stderr
                           # True:  log stderr as err, warn or info
                           #        depending on err_to_warn and
                           #        err_to_info value

         outdebug=True,    # True:  log.debug cmd stdout
                           # False: skip log.debug stdout

         errdebug=True,    # True:  log.debug cmd stderr
                           # False: skip log.debug stderr
                           #        depending on err_to_warn and
                           #        err_to_info value
         err_to_warn=False,
         err_to_info=False):
    if log is None:
        log = logging.getLogger('CALL')
    if not argv or len(argv) == 0:
        return (0, '')
    if which(argv[0]) is None:
        log.error("%s does not exist or not in path or is not executable"%
                  argv[0])
        return (1, '')
    cmd = ' '.join(argv)
    if info:
        log.info(cmd)
    else:
        log.debug(cmd)
    if not hasattr(rcEnv, "call_cache"):
        rcEnv.call_cache = {}
    if not cache or cmd not in rcEnv.call_cache:
        if not cache:
            log.debug("caching for '%s' explicitely disabled"%cmd)
        elif cmd not in rcEnv.call_cache:
            log.debug("cache miss for '%s'"%cmd)
        process = Popen(argv, stdout=PIPE, stderr=PIPE, close_fds=True)
        buff = process.communicate()
        ret = process.returncode
        if ret == 0:
            log.debug("store '%s' output in cache"%cmd)
            rcEnv.call_cache[cmd] = buff
        elif cmd in rcEnv.call_cache:
            log.debug("discard '%s' output from cache because ret!=0"%cmd)
            del rcEnv.call_cache[cmd]
        else:
            log.debug("skip store '%s' output in cache because ret!=0"%cmd)
    else:
        log.debug("serve '%s' output from cache"%cmd)
        buff = rcEnv.call_cache[cmd]
        ret = 0
    if not empty_string(buff[1]):
        if err_to_info:
            log.info('stderr:\n' + buff[1])
        elif err_to_warn:
            log.warning('stderr:\n' + buff[1])
        elif errlog:
            if ret != 0:
                log.error('stderr:\n' + buff[1])
            else:
                log.warning('command succesful but stderr:\n' + buff[1])
        elif errdebug:
            log.debug('stderr:\n' + buff[1])
    if not empty_string(buff[0]):
        if outlog:
            if ret == 0:
                log.info('output:\n' + buff[0])
            else:
                log.error('command failed with stdout:\n' + buff[0])
        elif outdebug:
            log.debug('output:\n' + buff[0])

    return (ret, buff[0])

def qcall(argv=['/bin/false']) :
    """qcall Launch Popen it args disgarding output and stderr"""
    if not argv:
        return (0, '')
    process = Popen(argv, stdout=open('/dev/null'), stderr=open('/dev/null'), close_fds=True)
    process.wait()
    return process.returncode

def vcall(argv=['/bin/false'],
          log=None,
          err_to_warn=False,
          err_to_info=False ):
    return call(argv,
                log=log,
                info=True,
                outlog=True,
                err_to_warn=err_to_warn,
                err_to_info=err_to_info)

def getmount(path):
    path = os.path.abspath(path)
    while path != os.path.sep:
        if not os.path.islink(path) and os.path.ismount(path):
            return path
        path = os.path.abspath(os.path.join(path, os.pardir))
    return path

def protected_mount(path):
    if getmount(path) in ['/', '/usr', '/var', '/sys', '/proc', '/tmp', '/opt', '/dev', '/dev/pts', '/home', '/boot', '/dev/shm']:
        return True
    return False


if __name__ == "__main__":
    print "call(('id','-a'))"
    (r,output)=call(("/usr/bin/id","-a"))
    print "status: ",r,"output:",output

   070701000671f8000081a40000000000000000000000014d9d7e6e00000448000000b600010002ffffffffffffffff0000002d00000000root/opt/opensvc/lib/rcIfconfigWindowskvm.py  #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#

import rcExceptions as ex
from subprocess import *

rcIfconfig = __import__("rcIfconfig")
from rcGlobalEnv import rcEnv

class ifconfig(rcIfconfig.ifconfig):
    def __init__(self, hostname):
        self.intf = []

    def has_param(self, param, value):
        return 0

07070100067219000081a40000000000000000000000014d9d7e6e000008db000000b600010002ffffffffffffffff0000001e00000000root/opt/opensvc/lib/rcZfs.py #!/usr/bin/python2.6
#
# Copyright (c) 2010 Christophe Varoqui <christophe.varoqui@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
from rcUtilities import justcall, call
"""
"""

def dataset_exists(device, type):
    "return True if dataset exists else return False"
    (out, err, ret) = justcall('zfs get -H -o value type'.split()+[device])
    if ret == 0 and out.split('\n')[0] == type :
        return True
    else:
        return False

def zfs_getprop(dataset='undef_ds', propname='undef_prop'):
    cmd = [ 'zfs', 'get', '-Hp', '-o', 'value', propname, dataset ]
    (stdout, stderr, retcode) = justcall(cmd)
    if retcode == 0 :
        return stdout.split("\n")[0]
    else:
        return ""

def zfs_setprop(dataset='undef_ds', propname='undef_prop', propval='undef_val'):
    if zfs_getprop(dataset, propname) == propval :
        return True
    cmd = [ 'zfs', 'set', propname + '='+ propval, dataset ]
    print ' '.join(cmd)
    (retcode, stdout) = call(cmd)
    if retcode == 0 :
        return True
    else:
        return False

def a2pool_dataset(s):
    """return (pool,dataset) from mount point
       example: a2pool_dataset('/') => ('rpool','rpool/ROOT/opensolaris-b134')
                same with a2pool_dataset('rpool/ROOT/opensolaris-b134')
    """
    if len(s) == 0:
        return ("", "")
    ss = s
    if s[0] == '/':
        cmd = ['zfs', 'list', '-H',  '-o', 'name', s]
        (ret, out) = call(cmd)
        if ret != 0:
            return ("", "")
        ss = out.split('\n')[0]
    x = ss.split('/')
    if len(x) < 2:
        return (ss, ss)
    return (x[0], ss)
 0707010006725d000081a40000000000000000000000014d9d7e6e00008cb4000000b600010002ffffffffffffffff0000001c00000000root/opt/opensvc/lib/svc.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
# To change this template, choose Tools | Templates
# and open the template in the editor.

from resources import Resource, ResourceSet
from freezer import Freezer
import rcStatus
from rcGlobalEnv import rcEnv
from rcUtilities import fork
import rcExceptions as ex
import xmlrpcClient
import os
import signal
import lock
import rcLogger
import logging

def signal_handler(signum, frame):
    raise ex.excSignal

def fork_dblogger(self, action, begin, end, actionlogfile):
    kwargs = {'self': self,
              'action': action,
              'begin': begin,
              'end': end,
              'actionlogfile': actionlogfile}
    fork(dblogger, kwargs)

def dblogger(self, action, begin, end, actionlogfile):
    for rs in self.resSets:
        for r in rs.resources:
            r.log.setLevel(logging.CRITICAL)

    xmlrpcClient.end_action(self, action, begin, end, actionlogfile)
    g_vars, g_vals, r_vars, r_vals = self.svcmon_push_lists()
    xmlrpcClient.svcmon_update_combo(g_vars, g_vals, r_vars, r_vals)
    os.unlink(actionlogfile)
    try:
        logging.shutdown()
    except:
        pass


class Svc(Resource, Freezer):
    """Service class define a Service Resource
    It contain list of ResourceSet where each ResourceSets contain same resource
    type
    """

    def __init__(self, svcname=None, type="hosted", optional=False, disabled=False, tags=set([])):
        """usage : aSvc=Svc(type)"""
        self.disable_fork_dblogger = False
        self.svcname = svcname
        self.vmname = ""
        self.containerize = True
        self.hostid = rcEnv.nodename
        self.resSets = []
        self.type2resSets = {}
        self.disks = set([])
        self.force = False
        self.cluster = False
        self.parallel = False
        self.push_flag = os.path.join(rcEnv.pathvar, svcname+'.push')
        self.status_types = ["container.hpvm",
                             "container.kvm",
                             "container.xen",
                             "container.lxc",
                             "container.vz",
                             "container.zone",
                             "container.jail",
                             "container.ldom",
                             "container.vbox",
                             "disk.drbd",
                             "disk.loop",
                             "disk.scsireserv",
                             "disk.vg",
                             "disk.zpool",
                             "fs",
                             "ip",
                             "sync.rsync",
                             "sync.symclone",
                             "sync.evasnap",
                             "sync.dds",
                             "sync.zfs",
                             "sync.netapp",
                             "app",
                             "hb.openha",
                             "hb.linuxha"]
        Resource.__init__(self, type=type, optional=optional,
                          disabled=disabled, tags=tags)
        self.log = rcLogger.initLogger(self.svcname.upper())
        Freezer.__init__(self, svcname)
        self.scsirelease = self.prstop
        self.scsireserv = self.prstart
        self.scsicheckreserv = self.prstatus
        self.runmethod = []
        self.resources_by_id = {}
        self.rset_status_cache = None
        self.print_status_fmt = "%-14s %-8s %s"
        self.presync_done = False
        self.presnap_trigger = None
        self.postsnap_trigger = None
        self.lockfd = None

    def __cmp__(self, other):
        """order by service name
        """
        return cmp(self.svcname, other.svcname)

    def __iadd__(self, r):
        """svc+=aResourceSet
        svc+=aResource
        """
        if r.type in self.type2resSets:
            self.type2resSets[r.type] += r

        elif isinstance(r, ResourceSet):
            self.resSets.append(r)
            self.type2resSets[r.type] = r

        elif isinstance(r, Resource):
            R = ResourceSet(r.type, [r])
            self.__iadd__(R)

        else:
            # Error
            pass

        self.resources_by_id[r.rid] = r
        if r.rid in rcEnv.vt_supported:
            self.resources_by_id["container"] = r
        r.svc = self
        import logging
        r.log = logging.getLogger(str(self.svcname+'.'+str(r.rid)).upper())

        return self

    def svclock(self, action=None, timeout=30, delay=5):
        if action in ['push', 'print_status', 'status', 'freeze', 'frozen',
                      'thaw']:
            # no need to serialize this action
            return
        lockfile = os.path.join(rcEnv.pathlock, self.svcname)
        try:
            lockfd = lock.lock(timeout=timeout, delay=delay, lockfile=lockfile)
        except lock.lockTimeout:
            self.log.error("timed out waiting for lock")
            raise ex.excError
        except lock.lockNoLockFile:
            self.log.error("lock_nowait: set the 'lockfile' param")
            raise ex.excError
        except lock.lockCreateError:
            self.log.error("can not create lock file %s"%lockfile)
            raise ex.excError
        except lock.lockAcquire as e:
            self.log.warn("another action is currently running (pid=%s)"%e.pid)
            raise ex.excError
        except ex.excSignal:
            self.log.error("interrupted by signal")
            raise ex.excError
        except:
            self.log.error("unexpected locking error")
            import traceback
            traceback.print_exc()
            raise ex.excError
        if lockfd is not None:
            self.lockfd = lockfd

    def svcunlock(self):
        lock.unlock(self.lockfd)

    def setup_signal_handlers(self):
        signal.signal(signal.SIGINT, signal_handler)
        signal.signal(signal.SIGTERM, signal_handler)

    def get_res_sets(self, type):
         if not isinstance(type, list):
             l = [type]
         else:
             l = type
         rsets = []
         for t in l:
             rsets += [ r for r in self.resSets if r.type == t ]
         return rsets

    def has_res_set(self, type):
        if len(self.get_res_sets(type)) > 0:
            return True
        else:
            return False

    def all_set_action(self, action=None, tags=set([])):
        """Call action on each member of the subset of specified type
        """
        self.set_action(self.resSets, action=action, tags=tags)

    def sub_set_action(self, type=None, action=None, tags=set([])):
        """Call action on each member of the subset of specified type
        """
        self.set_action(self.get_res_sets(type), action=action, tags=tags)

    def need_snap_trigger(self, sets, action):
        if action not in ["syncnodes", "syncdrp", "syncresync", "syncupdate"]:
            return False
        for rs in sets:
            for r in rs.resources:
                """ avoid to run pre/post snap triggers when there is no
                    resource flagged for snap and on drpnodes
                """
                if hasattr(r, "snap") and r.snap is True and \
                   rcEnv.nodename in self.nodes:
                    return True
        return False

    def set_action(self, sets=[], action=None, tags=set([])):
        """ TODO: r.is_optional() not doing what's expected if r is a rset
        """
        blacklist_actions = ["status",
                   "print_status",
                   "group_status",
                   "presync",
                   "postsync"]
        ns = self.need_snap_trigger(sets, action)

        """ snapshots are created in pre_action and destroyed in post_action
            place presnap and postsnap triggers around pre_action
        """
        if ns and self.presnap_trigger is not None:
            (ret, out) = self.vcall(self.presnap_trigger)
            if ret != 0:
                raise ex.excError

        for r in sets:
            if action in blacklist_actions:
                break
            try:
                r.log.debug("start %s pre_action"%r.type)
                r.pre_action(r, action)
            except ex.excError:
                if r.is_optional():
                    pass
                else:
                    raise ex.excError
            except ex.excAbortAction:
                if r.is_optional():
                    pass
                else:
                    break
            except:
                self.save_exc()
                raise ex.excError

        if ns and self.postsnap_trigger is not None:
            (ret, out) = self.vcall(self.postsnap_trigger)
            if ret != 0:
                raise ex.excError

        for r in sets:
            self.log.debug('set_action: action=%s rset=%s'%(action, r.type))
            try:
                r.action(action, tags=tags)
            except ex.excError:
                if r.is_optional():
                    pass
                else:
                    raise ex.excError
            except ex.excAbortAction:
                if r.is_optional():
                    pass
                else:
                    break

        for r in sets:
            if action in blacklist_actions:
                break
            try:
                r.post_action(r, action)
            except ex.excError:
                if r.is_optional():
                    pass
                else:
                    raise ex.excError
            except ex.excAbortAction:
                if r.is_optional():
                    pass
                else:
                    break
            except:
                self.save_exc()
                raise ex.excError


    def __str__(self):
        output="Service %s available resources:" % (Resource.__str__(self))
        for k in self.type2resSets.keys() : output += " %s" % k
        output+="\n"
        for r in self.resSets:  output+= "  [%s]" % (r.__str__())
        return output

    def status(self):
        """aggregate status a service
        """
        ss = rcStatus.Status()
        for r in self.get_res_sets(self.status_types):
            if "sync." not in r.type:
                 ss += r.status()
            else:
                """ sync are expected to be up
                """
                s = r.status()
                if s == rcStatus.UP:
                    ss += rcStatus.UNDEF
                elif s in [rcStatus.NA, rcStatus.UNDEF, rcStatus.TODO]:
                    ss += s
                else:
                    ss += rcStatus.WARN
        if ss.status == rcStatus.STDBY_UP_WITH_UP:
            ss.status = rcStatus.UP
        elif ss.status == rcStatus.STDBY_UP_WITH_DOWN:
            ss.status = rcStatus.STDBY_UP
        return ss.status

    def print_status(self):
        """print each resource status for a service
        """
        from textwrap import wrap

        def print_res(e, fmt, pfx):
            rid, status, label, log = e
            print fmt%(rid, status, label)
            if len(log) > 0:
                print '\n'.join(wrap(log,
                                     initial_indent = pfx,
                                     subsequent_indent = pfx,
                                     width=78
                                    )
                               )

        fmt = "%-20s %-8s %s"
        print fmt%("overall", str(self.group_status()['overall']), "\n"),
        fmt = "|- %-17s %-8s %s"
        print fmt%("avail", str(self.group_status()['avail']), "\n"),

        l = []
        for rs in self.get_res_sets(self.status_types):
            for r in [_r for _r in rs.resources if not _r.rid.startswith('sync') and not _r.rid.startswith('hb')]:
                l.append(r.status_quad())
        last = len(l) - 1
        if last > 0:
            for i, e in enumerate(l):
                if i == last:
                    fmt = "|  '- %-14s %-8s %s"
                    pfx = "|     %-14s %-8s "%('','')
                    print_res(e, fmt, pfx)
                else:
                    fmt = "|  |- %-14s %-8s %s"
                    pfx = "|  |  %-14s %-8s "%('','')
                    print_res(e, fmt, pfx)

        fmt = "|- %-17s %-8s %s"
        print fmt%("sync", str(self.group_status()['sync']), "\n"),

        l = []
        for rs in self.get_res_sets(self.status_types):
            for r in [_r for _r in rs.resources if _r.rid.startswith('sync')]:
                l.append(r.status_quad())
        last = len(l) - 1
        if last > 0:
            for i, e in enumerate(l):
                if i == last:
                    fmt = "|  '- %-14s %-8s %s"
                    pfx = "|     %-14s %-8s "%('','')
                    print_res(e, fmt, pfx)
                else:
                    fmt = "|  |- %-14s %-8s %s"
                    pfx = "|  |  %-14s %-8s "%('','')
                    print_res(e, fmt, pfx)

        fmt = "'- %-17s %-8s %s"
        print fmt%("hb", str(self.group_status()['hb']), "\n"),

        l = []
        for rs in self.get_res_sets(self.status_types):
            for r in [_r for _r in rs.resources if _r.rid.startswith('hb')]:
                l.append(r.status_quad())
        last = len(l) - 1
        if last > 0:
            for i, e in enumerate(l):
                if i == last:
                    fmt = "   '- %-14s %-8s %s"
                    pfx = "      %-14s %-8s "%('','')
                    print_res(e, fmt, pfx)
                else:
                    fmt = "   |- %-14s %-8s %s"
                    pfx = "   |  %-14s %-8s "%('','')
                    print_res(e, fmt, pfx)

    def svcmon_push_lists(self, status=None):
        if status is None:
            status = self.group_status()

        if self.frozen():
            frozen = "1"
        else:
            frozen = "0"

        r_vars=["svcname",
                "nodename",
                "rid",
                "res_desc",
                "res_status",
                "updated",
                "res_log"]
        r_vals = []
        import datetime
        now = datetime.datetime.now()
        for rs in self.resSets:
            for r in rs.resources:
                r_vals.append([repr(self.svcname),
                             repr(rcEnv.nodename),
                             repr(r.rid),
                             repr(r.label),
                             repr(rcStatus.status_str(r.rstatus)),
                             repr(str(now)),
                             r.status_log_str])

        g_vars=["mon_svcname",
                "mon_svctype",
                "mon_nodname",
                "mon_nodtype",
                "mon_ipstatus",
                "mon_diskstatus",
                "mon_syncstatus",
                "mon_hbstatus",
                "mon_containerstatus",
                "mon_fsstatus",
                "mon_appstatus",
                "mon_availstatus",
                "mon_overallstatus",
                "mon_updated",
                "mon_prinodes",
                "mon_frozen"]
        g_vals=[self.svcname,
                self.svctype,
                rcEnv.nodename,
                rcEnv.host_mode,
                str(status["ip"]),
                str(status["disk"]),
                str(status["sync"]),
                str(status["hb"]),
                str(status["container"]),
                str(status["fs"]),
                str(status["app"]),
                str(status["avail"]),
                str(status["overall"]),
                str(now),
                ' '.join(self.nodes),
                frozen]
        return g_vars, g_vals, r_vars, r_vals

    def get_rset_status(self, groups):
        self.setup_environ()
        rset_status = {}
        for t in self.status_types:
            g = t.split('.')[0]
            if g not in groups:
                continue
            for rs in self.get_res_sets(t):
                rset_status[rs.type] = rs.status()
        return rset_status

    def group_status(self,
                     groups=set(["container", "ip", "disk", "fs", "sync", "app", "hb"]),
                     excluded_groups=set([])):
        from copy import copy
        """print each resource status for a service
        """
        status = {}
        groups = groups.copy() - excluded_groups
        rset_status = self.get_rset_status(groups)
        moregroups = groups | set(["overall", "avail"])

        # initialise status of each group
        for group in moregroups:
            status[group] = rcStatus.Status(rcStatus.NA)

        for t in [_t for _t in self.status_types if not _t.startswith('sync') and not _t.startswith('hb')]:
            group = t.split('.')[0]
            if group not in groups:
                continue
            for r in self.get_res_sets(t):
                s = rset_status[r.type]
                status[group] += s
                status["avail"] += s

        if status["avail"].status == rcStatus.STDBY_UP_WITH_UP:
            status["avail"].status = rcStatus.UP
            # now that we now the avail status we can promote
            # stdbyup to up
            for g in status:
                if status[g] == rcStatus.STDBY_UP:
                    status[g] = rcStatus.UP
        elif status["avail"].status == rcStatus.STDBY_UP_WITH_DOWN:
            status["avail"].status = rcStatus.STDBY_UP

        # overall status is avail + sync status
        # seed overall with avail
        status["overall"] = copy(status["avail"])

        for t in [_t for _t in self.status_types if _t.startswith('hb')]:
            if 'hb' not in groups:
                continue
            for r in self.get_res_sets(t):
                s = rset_status[r.type]
                status['hb'] += s
                status["overall"] += s

        for t in [_t for _t in self.status_types if _t.startswith('sync')]:
            if 'sync' not in groups:
                continue
            for r in self.get_res_sets(t):
                """ sync are expected to be up
                """
                s = rset_status[r.type]
                status['sync'] += s
                if s == rcStatus.UP:
                    status["overall"] += rcStatus.UNDEF
                elif s in [rcStatus.NA, rcStatus.UNDEF, rcStatus.TODO]:
                    status["overall"] += s
                else:
                    status["overall"] += rcStatus.WARN

        self.group_status_cache = status
        return status

    def disklist(self):
        """List all disks held by all resources of this service
        """
        disks = set()
        for rs in self.resSets:
            for r in rs.resources:
                if r.is_disabled():
                    continue
                disks |= r.disklist()
        self.log.debug("found disks %s held by service" % disks)
        return disks

    def boot(self):
        if rcEnv.nodename in self.autostart_node:
            self.start()
        else:
            self.cluster = True
            self.startstandby()

    def shutdown(self):
        # don't loose the action log on node shutdown
        self.disable_fork_dblogger = True
        self.force = True
        self.stop()

    def start(self):
        self.starthb()
        self.startip()
        self.mount()
        self.startcontainer()
        self.startapp()

    def stop(self):
        self.stophb()
        try:
            self.stopapp()
        except ex.excError:
            pass
        self.stopcontainer()
        self.umount()
        self.stopip()

    def cluster_mode_safety_net(self):
        if not self.has_res_set(['hb.openha', 'hb.linuxha']):
            return
        if not self.cluster:
            self.log.info("this service is managed by a clusterware, thus direct service manipulation is disabled. the --cluster option circumvent this safety net.")
            raise ex.excError

    def starthb(self):
        self.cluster_mode_safety_net()
        self.sub_set_action("hb.openha", "start")
        self.sub_set_action("hb.linuxha", "start")

    def stophb(self):
        self.cluster_mode_safety_net()
        self.sub_set_action("hb.openha", "stop")
        self.sub_set_action("hb.linuxha", "stop")

    def startdrbd(self):
        self.sub_set_action("disk.drbd", "start")

    def stopdrbd(self):
        self.sub_set_action("disk.drbd", "stop")

    def startloop(self):
        self.sub_set_action("disk.loop", "start")

    def stoploop(self):
        self.sub_set_action("disk.loop", "stop")

    def stopvg(self):
        self.sub_set_action("disk.vg", "stop")
        self.sub_set_action("disk.scsireserv", "stop")

    def startvg(self):
        self.sub_set_action("disk.scsireserv", "start")
        self.sub_set_action("disk.vg", "start")

    def startpool(self):
        self.sub_set_action("disk.scsireserv", "start")
        self.sub_set_action("disk.zpool", "start")

    def stoppool(self):
        self.sub_set_action("disk.zpool", "stop")
        self.sub_set_action("disk.scsireserv", "stop")

    def startdisk(self):
        self.sub_set_action("sync.netapp", "start")
        self.sub_set_action("sync.symclone", "start")
        self.sub_set_action("disk.loop", "start")
        self.sub_set_action("disk.scsireserv", "start")
        self.sub_set_action("disk.drbd", "start", tags=set(['prevg']))
        self.sub_set_action("disk.zpool", "start")
        self.sub_set_action("disk.vg", "start")
        self.sub_set_action("disk.drbd", "start", tags=set(['postvg']))

    def stopdisk(self):
        self.sub_set_action("disk.drbd", "stop", tags=set(['postvg']))
        self.sub_set_action("disk.vg", "stop")
        self.sub_set_action("disk.zpool", "stop")
        self.sub_set_action("disk.drbd", "stop", tags=set(['prevg']))
        self.sub_set_action("disk.scsireserv", "stop")
        self.sub_set_action("disk.loop", "stop")

    def startip(self):
        self.sub_set_action("ip", "start")

    def stopip(self):
        self.sub_set_action("ip", "stop")

    def mount(self):
        self.startdisk()
        self.sub_set_action("fs", "start")

    def umount(self):
        self.sub_set_action("fs", "stop")
        self.stopdisk()

    def startcontainer(self):
        self.sub_set_action("container.lxc", "start")
        self.sub_set_action("container.vz", "start")
        self.sub_set_action("container.jail", "start")
        self.sub_set_action("container.kvm", "start")
        self.sub_set_action("container.xen", "start")
        self.sub_set_action("container.hpvm", "start")
        self.sub_set_action("container.ldom", "start")
        self.sub_set_action("container.vbox", "start")
        self.refresh_ip_status()

    def refresh_ip_status(self):
        """ Used after start/stop container because the ip resource
            status change after its own start/stop
        """
        for rs in self.get_res_sets("ip"):
            for r in rs.resources:
                r.status(refresh=True)

    def stopcontainer(self):
        self.sub_set_action("container.vbox", "stop")
        self.sub_set_action("container.ldom", "stop")
        self.sub_set_action("container.hpvm", "stop")
        self.sub_set_action("container.xen", "stop")
        self.sub_set_action("container.kvm", "stop")
        self.sub_set_action("container.jail", "stop")
        self.sub_set_action("container.lxc", "stop")
        self.sub_set_action("container.vz", "stop")
        self.refresh_ip_status()

    def startapp(self):
        self.sub_set_action("app", "start")

    def stopapp(self):
        self.sub_set_action("app", "stop")

    def prstop(self):
        self.sub_set_action("disk.scsireserv", "scsirelease")

    def prstart(self):
        self.sub_set_action("disk.scsireserv", "scsireserv")

    def prstatus(self):
        self.sub_set_action("disk.scsireserv", "scsicheckreserv")

    def startstandby(self):
        self.sub_set_action("ip", "startstandby")
        self.sub_set_action("disk.loop", "startstandby")
        self.sub_set_action("disk.scsireserv", "startstandby")
        self.sub_set_action("disk.drbd", "startstandby", tags=set(['prevg']))
        self.sub_set_action("disk.vg", "startstandby")
        self.sub_set_action("disk.zpool", "startstandby")
        self.sub_set_action("disk.drbd", "startstandby", tags=set(['postvg']))
        self.sub_set_action("fs", "startstandby")
        self.sub_set_action("app", "startstandby")

    def postsync(self):
        """ action triggered by a remote master node after
            syncnodes and syncdrp. Typically make use of files
            received in var/
        """
        self.all_set_action("postsync")

    def remote_postsync(self):
	""" detach the remote exec of postsync because the
            waitlock timeout is long, and we ourselves still
            hold the service lock we want to release early.
	"""
	kwargs = {}
	fork(self._remote_postsync, kwargs)

    def _remote_postsync(self):
        """ action triggered by a remote master node after
            syncnodes and syncdrp. Typically make use of files
            received in var/.
            use a long waitlock timeout to give a chance to
            remote syncs to finish
        """
        for n in self.need_postsync:
            self.remote_action(n, 'postsync', waitlock=3600)

        self.need_postsync = set([])

    def remote_action(self, node, action, waitlock=60):
        rcmd = [os.path.join(rcEnv.pathetc, self.svcname),
                '--waitlock', str(waitlock), action]
        self.log.info("exec '%s' on node %s"%(' '.join(rcmd), node))
        cmd = rcEnv.rsh.split() + [node] + rcmd
        self.call(cmd)

    def presync(self):
        """ prepare files to send to slave nodes in var/.
            Each resource can prepare its own set of files.
        """
        self.need_postsync = set([])
        if self.presync_done:
            return
        self.all_set_action("presync")
        self.presync_done = True

    def syncnodes(self):
        self.presync()
        self.sub_set_action("sync.rsync", "syncnodes")
        self.sub_set_action("sync.zfs", "syncnodes")
        self.sub_set_action("sync.dds", "syncnodes")
        self.remote_postsync()

    def syncdrp(self):
        self.presync()
        self.sub_set_action("sync.rsync", "syncdrp")
        self.sub_set_action("sync.zfs", "syncdrp")
        self.sub_set_action("sync.dds", "syncdrp")
        self.remote_postsync()

    def syncswap(self):
        self.sub_set_action("sync.netapp", "syncswap")

    def syncresume(self):
        self.sub_set_action("sync.netapp", "syncresume")

    def syncquiesce(self):
        self.sub_set_action("sync.netapp", "syncquiesce")

    def resync(self):
        self.stop()
        self.syncresync()
        self.start()

    def syncresync(self):
        self.sub_set_action("sync.netapp", "syncresync")
        self.sub_set_action("sync.symclone", "syncresync")
        self.sub_set_action("sync.evasnap", "syncresync")
        self.sub_set_action("sync.dds", "syncresync")

    def syncbreak(self):
        self.sub_set_action("sync.netapp", "syncbreak")
        self.sub_set_action("sync.symclone", "syncbreak")

    def syncupdate(self):
        self.sub_set_action("sync.netapp", "syncupdate")
        self.sub_set_action("sync.dds", "syncupdate")
        self.sub_set_action("sync.zfs", "syncnodes")

    def syncfullsync(self):
        self.sub_set_action("sync.dds", "syncfullsync")
        self.sub_set_action("sync.zfs", "syncnodes")

    def syncverify(self):
        self.sub_set_action("sync.dds", "syncverify")

    def printsvc(self):
        print str(self)

    def can_sync(self, target=None):
        ret = False
        rtypes = ["sync.netapp", "sync.dds", "sync.zfs",
                  "sync.rsync", "sync.zfs"]
        for rt in rtypes:
            for rs in self.get_res_sets(rt):
                for r in rs.resources:
                    ret |= r.can_sync(target)
                    if ret: return True
        return False

    def syncall(self):
        try: self.syncnodes()
        except: pass
        try: self.syncdrp()
        except: pass
        try: self.syncupdate()
        except: pass

    def push(self):
        xmlrpcClient.push_all([self])
        import time
        with open(self.push_flag, 'w') as f:
            f.write(str(time.time()))

    def tag_match(self, rtags, keeptags):
        for tag in rtags:
            if tag in keeptags:
                return True
        return False

    def disable_resources(self, keeprid=[], keeptags=set([])):
        if len(keeprid) > 0:
            ridfilter = True
        else:
            ridfilter = False

        if len(keeptags) > 0:
            tagsfilter = True
        else:
            tagsfilter = False

        if not tagsfilter and not ridfilter:
            return

        for rs in self.resSets:
            for r in rs.resources:
                if ridfilter and r.rid in keeprid:
                    continue
                if tagsfilter and self.tag_match(r.tags, keeptags):
                    continue
                r.disable()

    def setup_environ(self):
        """ Those are available to startup scripts and triggers
        """
        os.environ['OPENSVC_SVCNAME'] = self.svcname
        for rs in self.resSets:
            for r in rs.resources:
                r.setup_environ()

    def action(self, action, rid=[], tags=set([]), waitlock=60):
        if self.svctype != 'PRD' and rcEnv.host_mode == 'PRD':
            self.log.error("Abort action for non PRD service on PRD node")
            raise ex.excError
        if self.frozen() and action not in ['thaw', 'status', 'frozen', 'push', 'print_status']:
            self.log.info("Abort action for frozen service")
            return
        self.setup_environ()
        self.setup_signal_handlers()
        self.disable_resources(keeprid=rid, keeptags=tags)
        if action in ["print_status", "status", "group_status"]:
            err = self.do_action(action, waitlock=waitlock)
        elif action in ["syncall", "syncdrp", "syncnodes", "syncupdate"]:
            if action == "syncall" or "syncupdate": kwargs = {}
            elif action == "syncnodes": kwargs = {'target': 'nodes'}
            elif action == "syncdrp": kwargs = {'target': 'drpnodes'}
            if self.can_sync(**kwargs):
                err = self.do_logged_action(action, waitlock=waitlock)
            else:
                err = 0
                self.log.debug("nothing to sync for the service for now")
        else:
            err = self.do_logged_action(action, waitlock=waitlock)
        if self.parallel:
            import sys
            sys.exit(err)
        else:
            return err

    def do_action(self, action, waitlock=60):
        """Trigger action
        """
        err = 0
        try:
            self.svclock(action, timeout=waitlock)
        except:
            return 1

        try:
            if hasattr(self, action):
                getattr(self, action)()
            else:
                self.log.error("unsupported action")
                err = 1
        except ex.excError:
            err = 1
        except ex.excSignal:
            self.log.error("interrupted by signal")
            err = 1
        except:
            err = 1
            self.save_exc()

        self.svcunlock()
        return err

    def save_exc(self):
        import traceback
        try:
            import tempfile
            import datetime
            now = str(datetime.datetime.now()).replace(' ', '-')
            f = tempfile.NamedTemporaryFile(dir=rcEnv.pathtmp,
                                            prefix='exc-'+now+'-')
            f.close()
            f = open(f.name, 'w')
            traceback.print_exc(file=f)
            self.log.error("unexpected error. stack saved in %s"%f.name)
            f.close()
        except:
            self.log.error("unexpected error")
            traceback.print_exc()

    def do_logged_action(self, action, waitlock=60):
        from datetime import datetime
        import tempfile
        import logging
        begin = datetime.now()

        """Provision a database entry to store action log later
        """
        xmlrpcClient.begin_action(self, action, begin)

        """Per action logfile to push to database at the end of the action
        """
        f = tempfile.NamedTemporaryFile(delete=False, dir=rcEnv.pathtmp, prefix=self.svcname+'.'+action)
        actionlogfile = f.name
        f.close()
        log = logging.getLogger()
        actionlogformatter = logging.Formatter("%(asctime)s;%(name)s;%(levelname)s;%(message)s;%(process)d;EOL")
        actionlogfilehandler = logging.FileHandler(actionlogfile)
        actionlogfilehandler.setFormatter(actionlogformatter)
        log.addHandler(actionlogfilehandler)

        err = self.do_action(action, waitlock=waitlock)

        """ Push result and logs to database
        """
        actionlogfilehandler.close()
        log.removeHandler(actionlogfilehandler)
        end = datetime.now()
        if self.disable_fork_dblogger:
            dblogger(self, action, begin, end, actionlogfile)
        else:
            fork_dblogger(self, action, begin, end, actionlogfile)
        return err

    def restart(self):
	""" stop then start service
        """
        self.stop()
        self.start()

    def switch(self):
	""" stop then start service
        """
        if not hasattr(self, "destination_node"):
            self.log.error("a destination node must be provided for the switch action")
            raise ex.excError
        if self.destination_node not in self.nodes:
            self.log.error("destination node %s is not in service node list"%self.destination_node)
            raise ex.excError
        self.stop()
	kwargs = {'node': self.destination_node, 'action': 'start'}
	fork(self.remote_action, kwargs)

    def collector_outdated(self):
        """ return True if the env file has changed since last push
            else return False
        """
        import datetime
        pathenv = os.path.join(rcEnv.pathetc, self.svcname+'.env')
        if not os.path.exists(self.push_flag):
            self.log.debug("no last push timestamp found")
            return True
        try:
            mtime = os.stat(pathenv).st_mtime
            f = open(self.push_flag)
            last_push = float(f.read())
            f.close()
        except:
            self.log.error("can not read timestamp from %s or %s"%(pathenv, self.push_flag))
            return True
        if mtime > last_push:
            self.log.debug("env file changed since last push")
            return True
        return False


if __name__ == "__main__" :
    for c in (Svc,) :
        help(c)
    print """s1=Svc("Zone")"""
    s1=Svc("Zone")
    print "s1=",s1
    print """s2=Svc("basic")"""
    s2=Svc("basic")
    print "s2=",s2
    print """s1+=Resource("ip")"""
    s1+=Resource("ip")
    print "s1=",s1
    print """s1+=Resource("ip")"""
    s1+=Resource("ip")
    print """s1+=Resource("fs")"""
    s1+=Resource("fs")
    print """s1+=Resource("fs")"""
    s1+=Resource("fs")
    print "s1=",s1

    print """s1.action("status")"""
    s1.action("status")
0707010006725e000081a40000000000000000000000014d9d7e6e0000ca5d000000b600010002ffffffffffffffff0000002300000000root/opt/opensvc/lib/svcBuilder.py    #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
import os
import sys
import ConfigParser
import logging
import re
import socket

from rcGlobalEnv import *
from rcNode import discover_node
from rcUtilities import *
import rcLogger
import resSyncRsync
import resSyncNetapp
import rcExceptions as ex

check_privs()

#
# file tree abstraction
#
rcEnv.pathsvc = os.path.realpath(os.path.join(os.path.dirname(__file__), '..'))
rcEnv.pathbin = os.path.join(rcEnv.pathsvc, 'bin')
rcEnv.pathetc = os.path.join(rcEnv.pathsvc, 'etc')
rcEnv.pathlib = os.path.join(rcEnv.pathsvc, 'lib')
rcEnv.pathlog = os.path.join(rcEnv.pathsvc, 'log')
rcEnv.pathtmp = os.path.join(rcEnv.pathsvc, 'tmp')
rcEnv.pathvar = os.path.join(rcEnv.pathsvc, 'var')
rcEnv.pathlock = os.path.join(rcEnv.pathvar, 'lock')
rcEnv.sysname, rcEnv.nodename, x, x, rcEnv.machine = os.uname()
rcEnv.nodename = socket.gethostname()

os.environ['LANG'] = 'C'
os.environ['PATH'] += ':/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin'

def conf_get(svc, conf, s, o, t, scope=False):
    if t == 'string':
        f = conf.get
    elif t == 'boolean':
        f = conf.getboolean
    elif t == 'integer':
        f = conf.getint
    else:
        raise Exception()

    if not scope:
        if conf.has_option(s, o):
            return f(s, o)
        else:
            raise ex.OptNotFound

    if conf.has_option(s, o+"@"+rcEnv.nodename):
        return f(s, o+"@"+rcEnv.nodename)
    elif conf.has_option(s, o+"@nodes") and \
         rcEnv.nodename in svc.nodes:
        return f(s, o+"@nodes")
    elif conf.has_option(s, o+"@drpnodes") and \
         rcEnv.nodename in svc.drpnodes:
        return f(s, o+"@drpnodes")
    elif conf.has_option(s, o):
        return f(s, o)
    else:
        raise ex.OptNotFound

def conf_get_string(svc, conf, s, o):
    return conf_get(svc, conf, s, o, 'string', scope=False)

def conf_get_string_scope(svc, conf, s, o):
    return conf_get(svc, conf, s, o, 'string', scope=True)

def conf_get_boolean(svc, conf, s, o):
    return conf_get(svc, conf, s, o, 'boolean', scope=False)

def conf_get_boolean_scope(svc, conf, s, o):
    return conf_get(svc, conf, s, o, 'boolean', scope=True)

def conf_get_int(svc, conf, s, o):
    return conf_get(svc, conf, s, o, 'integer', scope=False)

def conf_get_int_scope(svc, conf, s, o):
    return conf_get(svc, conf, s, o, 'integer', scope=True)

def svcmode_mod_name(svcmode=''):
    """Returns (moduleName, serviceClassName) implementing the class for
    a given service mode. For example:
    lxc    => ('svcLxc', 'SvcLxc')
    zone   => ('svcZone', 'SvcZone')
    hosted => ('svcHosted', 'SvcHosted')
    """
    if svcmode == 'lxc':
        return ('svcLxc', 'SvcLxc')
    elif svcmode == 'vz':
        return ('svcVz', 'SvcVz')
    elif svcmode == 'zone':
        return ('svcZone', 'SvcZone')
    elif svcmode == 'jail':
        return ('svcJail', 'SvcJail')
    elif svcmode == 'hosted':
        return ('svcHosted', 'SvcHosted')
    elif svcmode == 'hpvm':
        return ('svcHpVm', 'SvcHpVm')
    elif svcmode == 'ldom':
        return ('svcLdom', 'SvcLdom')
    elif svcmode == 'kvm':
        return ('svcKvm', 'SvcKvm')
    elif svcmode == 'xen':
        return ('svcXen', 'SvcXen')
    elif svcmode == 'vbox':
        return ('svcVbox', 'SvcVbox')
    raise

def get_tags(conf, section):
    if conf.has_option(section, 'tags'):
        return set(conf.get(section, "tags").split())
    return set([])

def get_optional(conf, section):
    if conf.has_option(section, 'optional'):
        return conf.getboolean(section, "optional")
    return False

def get_disabled(conf, section, svc):
    if conf.has_option(section, 'disable'):
        return conf.getboolean(section, "disable")
    nodes = set([])
    if conf.has_option(section, 'disable_on'):
        l = conf.get(section, "disable_on").split()
        for i in l:
            if i == 'nodes': nodes |= svc.nodes
            elif i == 'drpnodes': nodes |= svc.drpnodes
            else: nodes |= set([i])
    if rcEnv.nodename in nodes:
        return True
    return False

def need_scsireserv(svc, conf, section):
    """scsireserv = true can be set globally or in a specific
    resource section
    """
    r = False
    try:
        r = conf_get_boolean_scope(svc, conf, section, 'scsireserv')
    except ex.OptNotFound:
        defaults = conf.defaults()
        if 'scsireserv' in defaults:
            r = bool(defaults['scsireserv'])
    return r

def add_scsireserv(svc, resource, conf, section):
    if not need_scsireserv(svc, conf, section):
        return
    try:
        sr = __import__('resScsiReserv'+rcEnv.sysname)
    except ImportError:
        sr = __import__('resScsiReserv')

    kwargs = {}
    kwargs['rid'] = resource.rid
    kwargs['tags'] = resource.tags
    kwargs['disks'] = resource.disklist()
    kwargs['disabled'] = resource.is_disabled()
    kwargs['optional'] = resource.is_optional()

    r = sr.ScsiReserv(**kwargs)
    svc += r

def add_triggers(resource, conf, section):
    if conf.has_option(section, 'pre_stop'):
        resource.pre_stop = conf.get(section, 'pre_stop').split()
    if conf.has_option(section, 'pre_start'):
        resource.pre_start = conf.get(section, 'pre_start').split()
    if conf.has_option(section, 'pre_syncnodes'):
        resource.pre_syncnodes = conf.get(section, 'pre_syncnodes').split()
    if conf.has_option(section, 'pre_syncdrp'):
        resource.pre_syncdrp = conf.get(section, 'pre_syncdrp').split()
    if conf.has_option(section, 'post_stop'):
        resource.post_stop = conf.get(section, 'post_stop').split()
    if conf.has_option(section, 'post_start'):
        resource.post_start = conf.get(section, 'post_start').split()
    if conf.has_option(section, 'post_syncnodes'):
        resource.post_syncnodes = conf.get(section, 'post_syncnodes').split()
    if conf.has_option(section, 'post_syncdrp'):
        resource.post_syncdrp = conf.get(section, 'post_syncdrp').split()

def always_on_nodes_set(svc, conf, section):
    try:
        always_on_opt = conf.get(section, "always_on").split()
    except:
        always_on_opt = []
    always_on = set([])
    if 'nodes' in always_on_opt:
        always_on |= svc.nodes
    if 'drpnodes' in always_on_opt:
        always_on |= svc.drpnodes
    always_on |= set(always_on_opt) - set(['nodes', 'drpnodes'])
    return always_on

def get_sync_args(conf, s, svc):
    kwargs = {}
    defaults = conf.defaults()
    if conf.has_option(s, 'sync_max_delay'):
        kwargs['sync_max_delay'] = conf.getint(s, 'sync_max_delay')
    elif 'sync_max_delay' in defaults:
        kwargs['sync_max_delay'] = int(defaults['sync_max_delay'])

    if conf.has_option(s, 'sync_min_delay'):
        kwargs['sync_interval'] = conf.getint(s, 'sync_min_delay')
        svc.log.warn("sync_min_delay is deprecated. replace with sync_interval.")
    elif 'sync_min_delay' in defaults:
        kwargs['sync_interval'] = int(defaults['sync_min_delay'])
        svc.log.warn("sync_min_delay is deprecated. replace with sync_interval.")

    if conf.has_option(s, 'sync_interval'):
        kwargs['sync_interval'] = conf.getint(s, 'sync_interval')
    elif 'sync_interval' in defaults:
        kwargs['sync_interval'] = int(defaults['sync_interval'])
    elif 'sync_max_delay' in kwargs:
        kwargs['sync_interval'] = kwargs['sync_max_delay']

    import json

    try:
        if conf.has_option(s, 'sync_period'):
            kwargs['sync_period'] = json.loads(conf.get(s, 'sync_period'))
        elif conf.has_option('DEFAULT', 'sync_period'):
            kwargs['sync_period'] = json.loads(conf.get('DEFAULT', 'sync_period'))
    except ValueError:
        svc.log.error("malformed parameter value: %s.%s"%(s, 'sync_period'))

    try:
        if conf.has_option(s, 'sync_days'):
            kwargs['sync_days'] = json.loads(conf.get(s, 'sync_days'))
        elif conf.has_option('DEFAULT', 'sync_days'):
            kwargs['sync_days'] = json.loads(conf.get('DEFAULT', 'sync_days'))
    except ValueError:
        svc.log.error("malformed parameter value: %s.%s"%(s, 'sync_days'))

    return kwargs

def add_ips(svc, conf):
    """Parse the configuration file and add an ip object for each [ip#n]
    section. Ip objects are stored in a list in the service object.
    """
    for s in conf.sections():
        if re.match('ip#[0-9]', s, re.I) is None:
            continue

        kwargs = {}

        try:
            kwargs['ipName'] = conf_get_string_scope(svc, conf, s, 'ipname')
        except ex.OptNotFound:
            svc.log.error("nor ipname and ipname@%s defined in config file section %s"%(rcEnv.nodename, s))
            continue

        try:
            kwargs['ipDev'] = conf_get_string_scope(svc, conf, s, 'ipdev')
        except ex.OptNotFound:
            svc.log.debug('add_ips ipdev not found in ip section %s'%s)
            continue

        if hasattr(svc, "vmname"):
            vmname = svc.vmname
        else:
            vmname = svc.svcname
        try:
            kwargs['mask'] = conf_get_string_scope(svc, conf, s, 'netmask')
        except ex.OptNotFound:
            pass

        if svc.svcmode == 'lxc':
            ip = __import__('resIp'+rcEnv.sysname+'Lxc')
        elif svc.svcmode == 'vz':
            ip = __import__('resIp'+rcEnv.sysname+'Lxc')
        elif svc.svcmode  == 'kvm':
            ip = __import__('resIp'+'Kvm')
        elif svc.svcmode  == 'hpvm':
            ip = __import__('resIp'+'HpVm')
        elif svc.svcmode  == 'ldom':
            ip = __import__('resIp'+'Ldom')
        elif svc.svcmode  == 'zone':
            ip = __import__('resIp'+'Zone')
        elif svc.svcmode  == 'xen':
            ip = __import__('resIp'+'Xen')
        elif svc.svcmode  == 'vbox':
            ip = __import__('resIp'+'Vbox')
        else:
            ip = __import__('resIp'+rcEnv.sysname)
        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['always_on'] = always_on_nodes_set(svc, conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)
        r = ip.Ip(**kwargs)
        add_triggers(r, conf, s)
        svc += r

def add_drbds(svc, conf):
    """Parse the configuration file and add a drbd object for each [drbd#n]
    section. Drbd objects are stored in a list in the service object.
    """
    for s in conf.sections():
        if re.match('drbd#[0-9]', s, re.I) is None:
            continue

        kwargs = {}

        try:
            kwargs['res'] = conf_get_string(svc, conf, s, 'res')
        except ex.OptNotFound:
            svc.log.error("res must be set in section %s"%s)
            return

        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['always_on'] = always_on_nodes_set(svc, conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)
        drbd = __import__('resDrbd')
        r = drbd.Drbd(**kwargs)
        add_triggers(r, conf, s)
        svc += r

def add_vdisks(svc, conf):
    for s in conf.sections():
        if re.match('vdisk#[0-9]', s, re.I) is None:
            continue

        kwargs = {}
        devpath = {}

        for attr, val in conf.items(s):
            if 'path@' in attr:
                devpath[attr.replace('path@','')] = val

        if len(devpath) == 0:
            svc.log.error("path@node must be set in section %s"%s)
            return

        kwargs['devpath'] = devpath
        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['always_on'] = always_on_nodes_set(svc, conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)
        vdisk = __import__('resVdisk')
        r = vdisk.Vdisk(**kwargs)
        add_triggers(r, conf, s)
        svc += r

def add_hbs(svc, conf):
    for s in conf.sections():
        if re.match('hb#[0-9]', s, re.I) is None:
            continue

        if rcEnv.nodename in svc.drpnodes:
            # no heartbeat on DRP nodes
            return

        kwargs = {}

        try:
            hbtype = conf_get_string(svc, conf, s, 'type')
        except ex.OptNotFound:
            svc.log.error("type must be set in section %s"%s)
            return

        try:
            kwargs['name'] = conf_get_string(svc, conf, s, 'name')
        except ex.OptNotFound:
            if hbtype == 'openha':
                svc.log.error("name must be set in section %s"%s)
                return

        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['always_on'] = always_on_nodes_set(svc, conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)

        try:
            hb = __import__('resHb'+hbtype)
        except ImportError:
            svc.log.error("resHb%s is not implemented"%hbtype)
            continue

        r = hb.Hb(**kwargs)
        add_triggers(r, conf, s)
        svc += r

def add_loops(svc, conf):
    """Parse the configuration file and add a loop object for each [loop#n]
    section. Loop objects are stored in a list in the service object.
    """
    for s in conf.sections():
        if re.match('loop#[0-9]', s, re.I) is None:
            continue

        kwargs = {}

        try:
            kwargs['loopFile'] = conf_get_string_scope(svc, conf, s, 'file')
        except ex.OptNotFound:
            svc.log.error("file must be set in section %s"%s)
            return

        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['always_on'] = always_on_nodes_set(svc, conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)

        try:
            loop = __import__('resLoop'+rcEnv.sysname)
        except ImportError:
            svc.log.error("resLoop%s is not implemented"%rcEnv.sysname)
            continue

        r = loop.Loop(**kwargs)
        add_triggers(r, conf, s)
        svc += r

def add_vgs(svc, conf):
    """Parse the configuration file and add a vg object for each [vg#n]
    section. Vg objects are stored in a list in the service object.
    """
    for s in conf.sections():
        if re.match('vg#[0-9]', s, re.I) is None:
            continue

        kwargs = {}

        try:
            kwargs['name'] = conf_get_string_scope(svc, conf, s, 'vgname')
        except ex.OptNotFound:
            svc.log.error("vgname must be set in section %s"%s)
            return

        try:
            kwargs['dsf'] = conf_get_boolean_scope(svc, conf, s, 'dsf')
        except ex.OptNotFound:
            pass

        try:
            vgtype = conf_get_string_scope(svc, conf, s, 'vgtype')
        except ex.OptNotFound:
            vgtype = rcEnv.sysname

        kwargs['always_on'] = always_on_nodes_set(svc, conf, s)
        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)

        try:
            vg = __import__('resVg'+vgtype)
        except ImportError:
            svc.log.error("vg type %s is not implemented"%vgtype)
            continue

        r = vg.Vg(**kwargs)
        add_triggers(r, conf, s)
        svc += r
        add_scsireserv(svc, r, conf, s)

def add_vmdg(svc, conf):
    if not conf.has_section('vmdg'):
        return
    if svc.svcmode == 'hpvm':
        vg = __import__('resVgHpVm')
    elif svc.svcmode == 'ldom':
        vg = __import__('resVgLdom')
    elif svc.svcmode in rcEnv.vt_libvirt:
        vg = __import__('resVgLibvirtVm')
    else:
        return

    kwargs = {}
    kwargs['rid'] = 'vmdg'
    kwargs['tags'] = get_tags(conf, 'vmdg')
    kwargs['name'] = 'vmdg'
    kwargs['disabled'] = get_disabled(conf, 'vmdg', svc)
    kwargs['optional'] = get_optional(conf, 'vmdg')

    r = vg.Vg(**kwargs)
    add_triggers(r, conf, 'vmdg')
    svc += r
    add_scsireserv(svc, r, conf, 'vmdg')

def add_pools(svc, conf):
    """Parse the configuration file and add a pool object for each [pool#n]
    section. Pools objects are stored in a list in the service object.
    """
    for s in conf.sections():
        if re.match('pool#[0-9]', s, re.I) is None:
            continue

        kwargs = {}

        try:
            kwargs['name'] = conf_get_string_scope(svc, conf, s, 'poolname')
        except ex.OptNotFound:
            svc.log.error("poolname must be set in section %s"%s)
            continue

        pool = __import__('resVgZfs')

        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['always_on'] = always_on_nodes_set(svc, conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)

        r = pool.Pool(**kwargs)
        add_triggers(r, conf, s)
        svc += r
        add_scsireserv(svc, r, conf, s)

def add_filesystems(svc, conf):
    """Parse the configuration file and add a fs object for each [fs#n]
    section. Fs objects are stored in a list in the service object.
    """
    for s in conf.sections():
        if re.match('fs#[0-9]', s, re.I) is None:
            continue

        kwargs = {}

        try:
            kwargs['device'] = conf_get_string_scope(svc, conf, s, 'dev')
        except ex.OptNotFound:
            svc.log.error("dev must be set in section %s"%s)
            continue

        try:
            kwargs['mountPoint'] = conf_get_string_scope(svc, conf, s, 'mnt')
        except ex.OptNotFound:
            svc.log.error("mnt must be set in section %s"%s)
            continue

        if kwargs['mountPoint'][-1] == '/':
            """ Remove trailing / to not risk losing rsync src trailing /
                upon snap mountpoint substitution.
            """
            kwargs['mountPoint'] = kwargs['mountPoint'][0:-1]

        try:
            kwargs['fsType'] = conf_get_string_scope(svc, conf, s, 'type')
        except ex.OptNotFound:
            kwargs['fsType'] = ""

        try:
            kwargs['mntOpt'] = conf_get_string_scope(svc, conf, s, 'mnt_opt')
        except ex.OptNotFound:
            kwargs['mntOpt'] = ""

        try:
            kwargs['snap_size'] = conf_get_int_scope(svc, conf, s, 'snap_size')
        except ex.OptNotFound:
            pass

        if svc.svcmode == 'zone':
            try:
                globalfs = conf.getboolean(s, "globalfs")
            except:
                globalfs = False

            if globalfs is False:
                kwargs['mountPoint'] = os.path.realpath(svc.zone.zonepath+'/root/'+kwargs['mountPoint'])

        try:
            mount = __import__('resMount'+rcEnv.sysname)
        except ImportError:
            svc.log.error("resMount%s is not implemented"%rcEnv.sysname)
            continue

        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['always_on'] = always_on_nodes_set(svc, conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)

        r = mount.Mount(**kwargs)
        add_triggers(r, conf, s)
        svc += r
        add_scsireserv(svc, r, conf, s)

def add_mandatory_syncs(svc, conf):
    """Mandatory files to sync:
    1/ to all nodes: service definition
    2/ to drpnodes: system files to replace on the drpnode in case of startdrp
    """

    """1
    """
    kwargs = {}
    src = []
    src.append(os.path.join(rcEnv.pathetc, svc.svcname))
    src.append(os.path.join(rcEnv.pathetc, svc.svcname+'.env'))
    src.append(os.path.join(rcEnv.pathetc, svc.svcname+'.d'))
    localrc = os.path.join(rcEnv.pathetc, svc.svcname+'.dir')
    cluster = os.path.join(rcEnv.pathetc, svc.svcname+'.cluster')
    if os.path.exists(cluster):
        src.append(cluster)
    if os.path.exists(localrc):
        src.append(localrc)
    for rs in svc.resSets:
        for r in rs.resources:
            src += r.files_to_sync()
    dst = os.path.join("/")
    exclude = ['--exclude=*.core']
    targethash = {'nodes': svc.nodes, 'drpnodes': svc.drpnodes}
    kwargs['rid'] = "sync#i0"
    kwargs['src'] = src
    kwargs['dst'] = dst
    kwargs['options'] = ['-R']+exclude
    kwargs['target'] = targethash
    kwargs['internal'] = True
    kwargs.update(get_sync_args(conf, 'sync', svc))
    r = resSyncRsync.Rsync(**kwargs)
    svc += r

    """2
    """
    targethash = {'drpnodes': svc.drpnodes}
    """ Reparent all PRD backed-up file in drp_path/node on the drpnode
    """
    dst = os.path.join(rcEnv.drp_path, rcEnv.nodename)
    i = 0
    for src, exclude in rcEnv.drp_sync_files:
        """'-R' triggers rsync relative mode
        """
        kwargs = {}
        src = [ s for s in src if os.path.exists(s) ]
        if len(src) == 0:
            continue
        i += 1
        kwargs['rid'] = "sync#i"+str(i)
        kwargs['src'] = src
        kwargs['dst'] = dst
        kwargs['options'] = ['-R']+exclude
        kwargs['target'] = targethash
        kwargs['internal'] = True
        kwargs.update(get_sync_args(conf, 'sync', svc))
        r = resSyncRsync.Rsync(**kwargs)
        svc += r

def add_syncs(svc, conf):
    add_syncs_rsync(svc, conf)
    add_syncs_netapp(svc, conf)
    add_syncs_symclone(svc, conf)
    add_syncs_evasnap(svc, conf)
    add_syncs_dds(svc, conf)
    add_syncs_zfs(svc, conf)

def add_syncs_zfs(svc, conf):
    zfs = __import__('resSyncZfs')
    for s in conf.sections():
        if re.match('sync#[0-9]', s, re.I) is None:
            continue

        if not conf.has_option(s, 'type'):
            continue
        elif conf.get(s, 'type') != 'zfs':
            continue

        kwargs = {}

        try:
            kwargs['src'] = conf_get_string_scope(svc, conf, s, 'src')
        except ex.OptNotFound:
            svc.log.error("config file section %s must have src set" % s)
            continue

        try:
            kwargs['dst'] = conf_get_string_scope(svc, conf, s, 'dst')
        except ex.OptNotFound:
            svc.log.error("config file section %s must have dst set" % s)
            continue

        try:
            kwargs['target'] = conf_get_string_scope(svc, conf, s, 'dst').split()
        except ex.OptNotFound:
            svc.log.error("config file section %s must have target set" % s)
            continue

        try:
            kwargs['recursive'] = conf_get_boolean(svc, conf, s, 'recursive')
        except ex.OptNotFound:
            pass

        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)
        kwargs.update(get_sync_args(conf, s, svc))
        r = zfs.SyncZfs(**kwargs)
        add_triggers(r, conf, s)
        svc += r

def add_syncs_dds(svc, conf):
    dds = __import__('resSyncDds')
    for s in conf.sections():
        if re.match('sync#[0-9]', s, re.I) is None:
            continue

        if not conf.has_option(s, 'type'):
            continue
        elif conf.get(s, 'type') != 'dds':
            continue

        kwargs = {}

        try:
            kwargs['src'] = conf_get_string_scope(svc, conf, s, 'src')
        except ex.OptNotFound:
            svc.log.error("config file section %s must have src set" % s)
            continue

        try:
            kwargs['dst'] = conf_get_string_scope(svc, conf, s, 'dst')
        except ex.OptNotFound:
            kwargs['dst'] = conf.get(s, 'src')

        try:
            kwargs['target'] = conf_get_string_scope(svc, conf, s, 'target').split()
        except ex.OptNotFound:
            svc.log.error("config file section %s must have target set" % s)
            continue

        try:
            kwargs['sender'] = conf_get_string(svc, conf, s, 'sender')
        except ex.OptNotFound:
            pass

        try:
            kwargs['snap_size'] = conf_get_int_scope(svc, conf, s, 'snap_size')
        except ex.OptNotFound:
            pass

        try:
            kwargs['delta_store'] = conf_get_string_scope(svc, conf, s, 'delta_store')
        except ex.OptNotFound:
            pass

        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)
        kwargs.update(get_sync_args(conf, s, svc))
        r = dds.syncDds(**kwargs)
        add_triggers(r, conf, s)
        svc += r

def add_syncs_evasnap(svc, conf):
    try:
        sc = __import__('resSyncEvasnap'+rcEnv.sysname)
    except:
        sc = __import__('resSyncEvasnap')
    for s in conf.sections():
        if re.match('sync#[0-9]', s, re.I) is None:
            continue

        if not conf.has_option(s, 'type'):
            continue
        elif conf.get(s, 'type') != 'evasnap':
            continue

        kwargs = {}

        try:
            kwargs['eva_name'] = conf_get_string(svc, conf, s, 'eva_name')
        except ex.OptNotFound:
            svc.log.error("config file section %s must have eva_name set" % s)
            continue

        import json
        pairs = []
        if 'pairs' in conf.options(s):
            pairs = json.loads(conf.get(s, 'pairs'))
        if len(pairs) == 0:
            svc.log.error("config file section %s must have pairs set" % s)
            continue
        else:
            kwargs['pairs'] = pairs

        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)
        kwargs.update(get_sync_args(conf, s, svc))
        r = sc.syncEvasnap(**kwargs)
        add_triggers(r, conf, s)
        svc += r

def add_syncs_symclone(svc, conf):
    try:
        sc = __import__('resSyncSymclone'+rcEnv.sysname)
    except:
        sc = __import__('resSyncSymclone')
    for s in conf.sections():
        if re.match('sync#[0-9]', s, re.I) is None:
            continue

        if not conf.has_option(s, 'type'):
            continue
        elif conf.get(s, 'type') != 'symclone':
            continue

        kwargs = {}

        try:
            kwargs['symdg'] = conf_get_string(svc, conf, s, 'symdg')
        except ex.OptNotFound:
            svc.log.error("config file section %s must have symdg set" % s)
            continue

        try:
            kwargs['symdevs'] = conf_get_string_scope(svc, conf, s, 'symdevs').split()
        except ex.OptNotFound:
            svc.log.error("config file section %s must have symdevs set" % s)
            continue

        try:
            kwargs['precopy_timeout'] = conf_get_int(svc, conf, s, 'precopy_timeout')
        except ex.OptNotFound:
            pass

        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)
        kwargs.update(get_sync_args(conf, s, svc))
        r = sc.syncSymclone(**kwargs)
        add_triggers(r, conf, s)
        svc += r

def add_syncs_netapp(svc, conf):
    for s in conf.sections():
        if re.match('sync#[0-9]', s, re.I) is None:
            continue

        kwargs = {}

        if not conf.has_option(s, 'type'):
            continue
        elif conf.get(s, 'type') != 'netapp':
            continue

        try:
            kwargs['path'] = conf_get_string_scope(svc, conf, s, 'path')
        except ex.OptNotFound:
            svc.log.error("config file section %s must have path set" % s)
            continue

        try:
            kwargs['user'] = conf_get_string_scope(svc, conf, s, 'user')
        except ex.OptNotFound:
            svc.log.error("config file section %s must have user set" % s)
            continue

        filers = {}
        if 'filer' in conf.options(s):
            for n in svc.nodes | svc.drpnodes:
                filers[n] = conf.get(s, 'filer')
        if 'filer@nodes' in conf.options(s):
            for n in svc.nodes:
                filers[n] = conf.get(s, 'filer@nodes')
        if 'filer@drpnodes' in conf.options(s):
            for n in svc.nodes:
                filers[n] = conf.get(s, 'filer@drpnodes')
        for o in conf.options(s):
            if 'filer@' not in o:
                continue
            (filer, node) = o.split('@')
            if node in ('nodes', 'drpnodes'):
                continue
            filers[node] = conf.get(s, o)
        if rcEnv.nodename not in filers:
            svc.log.error("config file section %s must have filer@%s set" %(s, rcEnv.nodename))

        kwargs['filers'] = filers
        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)
        kwargs.update(get_sync_args(conf, s, svc))

        r = resSyncNetapp.syncNetapp(**kwargs)
        add_triggers(r, conf, s)
        svc += r

def add_syncs_rsync(svc, conf):
    """Add mandatory node-to-nodes and node-to-drpnode synchronizations, plus
    the those described in the config file.
    """
    add_mandatory_syncs(svc, conf)

    for s in conf.sections():
        if re.match('sync#[0-9]', s, re.I) is None:
            continue

        if conf.has_option(s, 'type') and \
           conf.get(s, 'type') != 'rsync':
            continue

        if not conf.has_option(s, 'src') or \
           not conf.has_option(s, 'dst'):
            svc.log.error("config file section %s must have src and dst set" % s)
            return

        options = []
        kwargs = {}
        kwargs['src'] = conf.get(s, "src").split()
        kwargs['dst'] = conf.get(s, "dst")

        if conf.has_option(s, 'dstfs'):
            kwargs['dstfs'] = conf.get(s, 'dstfs')

        if conf.has_option(s, 'options'):
            options += conf.get(s, 'options').split()
        if conf.has_option(s, 'exclude'):
            # for backward compat (use options keyword now)
            options += conf.get(s, 'exclude').split()
        kwargs['options'] = options

        if conf.has_option(s, 'snap'):
            kwargs['snap'] = conf.getboolean(s, 'snap')

        if conf.has_option(s, 'target'):
            target = conf.get(s, 'target').split()
        else:
            target = []

        if conf.has_option(s, 'bwlimit'):
            kwargs['bwlimit'] = conf.get(s, 'bwlimit')

        targethash = {}
        if 'nodes' in target: targethash['nodes'] = svc.nodes
        if 'drpnodes' in target: targethash['drpnodes'] = svc.drpnodes
        kwargs['target'] = targethash
        kwargs['rid'] = s
        kwargs['tags'] = get_tags(conf, s)
        kwargs['disabled'] = get_disabled(conf, s, svc)
        kwargs['optional'] = get_optional(conf, s)
        kwargs.update(get_sync_args(conf, s, svc))

        r = resSyncRsync.Rsync(**kwargs)
        add_triggers(r, conf, s)
        svc += r

def add_apps(svc, conf):
    if svc.svcmode in rcEnv.vt_supported:
        resApp = __import__('resAppVm')
    else:
        resApp = __import__('resApp')

    r = resApp.Apps(runmethod=svc.runmethod)
    svc += r

def setup_logging():
    """Setup logging to stream + logfile, and logfile rotation
    class Logger instance name: 'log'
    """
    global log
    log = rcLogger.initLogger('INIT')

def build(name):
    """build(name) is in charge of Svc creation
    it return None if service Name is not managed by local node
    else it return new Svc instance
    """
    svcconf = os.path.join(rcEnv.pathetc, name) + '.env'
    svcinitd = os.path.join(rcEnv.pathetc, name) + '.d'
    logfile = os.path.join(rcEnv.pathlog, name) + '.log'
    rcEnv.logfile = logfile

    setup_logging()

    #
    # node discovery is hidden in a separate module to
    # keep it separate from the framework stuff
    #
    discover_node()

    #
    # parse service configuration file
    # class RawConfigParser instance name: 'conf'
    #
    svcmode = "hosted"
    conf = None
    kwargs = {'svcname': name}
    if os.path.isfile(svcconf):
        conf = ConfigParser.RawConfigParser()
        conf.read(svcconf)
        defaults = conf.defaults()
        if "mode" in defaults:
            svcmode = defaults["mode"]
        if "vm_name" in defaults:
            if svcmode not in rcEnv.vt_supported:
                log.error("can not set 'vm_name' with '%s' mode in %s env"%(svcmode, name))
                return None
            vmname = defaults["vm_name"]
            kwargs['vmname'] = vmname
        if "guest_os" in defaults and \
           len(defaults["guest_os"]) > 0:
            if svcmode not in rcEnv.vt_supported:
                log.error("can not set 'guest_os' with '%s' mode in %s env"%(svcmode, name))
                return None
            guestos = defaults["guest_os"]
            kwargs['guestos'] = guestos
        elif svcmode in rcEnv.vt_supported:
            guestos = rcEnv.sysname
            kwargs['guestos'] = guestos
        if svcmode == 'jail':
            if not "jailroot" in defaults:
                log.error("jailroot parameter is mandatory for jail mode")
                return None
            jailroot = defaults["jailroot"]
            if not os.path.exists(jailroot):
                log.error("jailroot %s does not exist"%jailroot)
                return None
            kwargs['jailroot'] = jailroot

    #
    # dynamically import the module matching the service mode
    # and instanciate a service
    #
    log.debug('service mode = ' + svcmode)
    mod , svc_class_name = svcmode_mod_name(svcmode)
    svcMod = __import__(mod)
    svc = getattr(svcMod, svc_class_name)(**kwargs)
    svc.svcmode = svcmode
    if "presnap_trigger" in defaults:
        svc.presnap_trigger = defaults["presnap_trigger"].split()
    if "postsnap_trigger" in defaults:
        svc.postsnap_trigger = defaults["postsnap_trigger"].split()

    #
    # containerization options
    #
    if "containerize" in defaults:
        svc.containerize = bool(defaults["containerize"])
    if "container_cpus" in defaults:
        svc.container_cpus = defaults["container_cpus"]
    if "container_cpu_shares" in defaults:
        svc.container_cpu_shares = defaults["container_cpu_shares"]
    if "container_mems" in defaults:
        svc.container_mems = defaults["container_mems"]
    if "container_mem_limit" in defaults:
        svc.container_mem_limit = defaults["container_mem_limit"]
    if "container_vmem_limit" in defaults:
        svc.container_vmem_limit = defaults["container_vmem_limit"]

    #
    # Store useful properties
    #
    svc.logfile = logfile
    svc.conf = svcconf
    svc.initd = svcinitd

    #
    # Setup service properties from config file content
    #

    if "nodes" in defaults:
        svc.nodes = set(defaults["nodes"].split())
        svc.nodes -= set([''])
    else:
        svc.nodes = set([])

    if "drpnodes" in defaults:
        svc.drpnodes = set(defaults["drpnodes"].split())
        svc.drpnodes -= set([''])
    else:
        svc.drpnodes = set([])

    if "drpnode" in defaults:
        svc.drpnode = defaults["drpnode"]
        svc.drpnodes |= set([svc.drpnode])
        svc.drpnodes -= set([''])
    else:
        svc.drpnode = ''

    """ prune not managed service
    """
    if rcEnv.nodename not in svc.nodes | svc.drpnodes:
        svc.log.error('service %s not managed here' % name)
        del(svc)
        return None

    if "cluster_type" in defaults:
        svc.clustertype = defaults["cluster_type"]
    else:
        svc.clustertype = 'failover'
    allowed_clustertype = ['failover', 'allactive', 'flex', 'autoflex']
    if svc.clustertype not in allowed_clustertype:
        svc.log.error("invalid cluster type '%s'. allowed: %s"%(svc.svcname, svc.clustertype, ', '.join(allowed_clustertype)))
        del(svc)
        return None

    if "flex_primary" in defaults:
        svc.flex_primary = defaults["flex_primary"]
    else:
        svc.flex_primary = ''

    if "flex_min_nodes" in defaults:
        svc.flex_min_nodes = int(defaults["flex_min_nodes"])
    else:
        svc.flex_min_nodes = 1
    if svc.flex_min_nodes < 1:
        svc.log.error("invalid flex_min_nodes '%d' (<1)."%svc.flex_min_nodes)
        del(svc)
        return None
    nb_nodes = len(svc.nodes)
    if nb_nodes > 0 and svc.flex_min_nodes > nb_nodes:
        svc.log.error("invalid flex_min_nodes '%d' (>%d nb of nodes)."%(svc.flex_min_nodes, nb_nodes))
        del(svc)
        return None

    if "flex_max_nodes" in defaults:
        svc.flex_max_nodes = int(defaults["flex_max_nodes"])
    else:
        svc.flex_max_nodes = 0
    if svc.flex_max_nodes < 0:
        svc.log.error("invalid flex_max_nodes '%d' (<0)."%svc.flex_max_nodes)
        del(svc)
        return None

    if "flex_cpu_low_threshold" in defaults:
        svc.flex_cpu_low_threshold = int(defaults["flex_cpu_low_threshold"])
    else:
        svc.flex_cpu_low_threshold = 10
    if svc.flex_cpu_low_threshold < 0:
        svc.log.error("invalid flex_cpu_low_threshold '%d' (<0)."%svc.flex_cpu_low_threshold)
        del(svc)
        return None
    if svc.flex_cpu_low_threshold > 100:
        svc.log.error("invalid flex_cpu_low_threshold '%d' (>100)."%svc.flex_cpu_low_threshold)
        del(svc)
        return None

    if "flex_cpu_high_threshold" in defaults:
        svc.flex_cpu_high_threshold = int(defaults["flex_cpu_high_threshold"])
    else:
        svc.flex_cpu_high_threshold = 90
    if svc.flex_cpu_high_threshold < 0:
        svc.log.error("invalid flex_cpu_high_threshold '%d' (<0)."%svc.flex_cpu_high_threshold)
        del(svc)
        return None
    if svc.flex_cpu_high_threshold > 100:
        svc.log.error("invalid flex_cpu_high_threshold '%d' (>100)."%svc.flex_cpu_high_threshold)
        del(svc)
        return None

    if "service_type" in defaults:
        svc.svctype = defaults["service_type"]
    else:
        svc.svctype = ''

    if svc.svctype not in rcEnv.allowed_svctype:
        svc.log.error('service %s type %s is not a known service type (%s)'%(svc.svcname, svc.svctype, ', '.join(allowed_svctype)))
        del(svc)
        return None

    """ prune service whose service type does not match host mode
    """
    if svc.svctype != 'PRD' and rcEnv.host_mode == 'PRD':
        svc.log.error('service %s type %s is not allowed to run on this node (host mode %s)' % (svc.svcname, svc.svctype, rcEnv.host_mode))
        del(svc)
        return None

    if "autostart_node" in defaults:
        svc.autostart_node = defaults["autostart_node"].split()
    else:
        svc.autostart_node = []

    if "drp_type" in defaults:
        svc.drp_type = defaults["drp_type"]
    else:
        svc.drp_type = ''

    if "comment" in defaults:
        svc.comment = defaults["comment"]
    else:
        svc.comment = ''

    if "app" in defaults:
        svc.app = defaults["app"]
    else:
        svc.app = ''

    if "drnoaction" in defaults:
        svc.drnoaction = defaults["drnoaction"]
    else:
        svc.drnoaction = False

    if "bwlimit" in defaults:
        svc.bwlimit = defaults["bwlimit"]
    else:
        svc.bwlimit = None

    #
    # instanciate resources
    #
    try:
        add_hbs(svc, conf)
        add_ips(svc, conf)
        add_drbds(svc, conf)
        add_loops(svc, conf)
        add_vdisks(svc, conf)
        add_vgs(svc, conf)
        add_vmdg(svc, conf)
        add_pools(svc, conf)
        add_filesystems(svc, conf)
        add_apps(svc, conf)
        add_syncs(svc, conf)
    except ex.excInitError:
        return None

    return svc

def is_service(f):
    svcmgr = os.path.join(rcEnv.pathsvc, 'bin', 'svcmgr')
    if os.path.realpath(f) != os.path.realpath(svcmgr):
        return False
    if not os.path.exists(f + '.env'):
        return False
    return True

def list_services():
    if not os.path.exists(rcEnv.pathetc):
        print "create dir %s"%rcEnv.pathetc
        os.makedirs(rcEnv.pathetc)
    s = []
    for name in os.listdir(rcEnv.pathetc):
        if not is_service(os.path.join(rcEnv.pathetc, name)):
            continue
        s.append(name)
    return s

def build_services(status=None, svcnames=[],
                   onlyprimary=False, onlysecondary=False):
    """returns a list of all services of status matching the specified status.
    If no status is specified, returns all services
    """
    services = {}
    for name in list_services():
        if len(svcnames) > 0 and name not in svcnames:
            continue
        fix_default_section([name])
        try:
            svc = build(name)
        except (ex.excError, ex.excInitError, ex.excAbortAction):
            continue
        except:
            import traceback
            traceback.print_exc()
            continue
        if svc is None :
            continue
        if status is not None and svc.status() != status:
            continue
        if onlyprimary and rcEnv.nodename not in svc.autostart_node:
            continue
        if onlysecondary and rcEnv.nodename in svc.autostart_node:
            continue
        services[svc.svcname] = svc
        if svc.collector_outdated():
            svc.action('push')
    return [ s for n ,s in sorted(services.items()) ]

def toggle_one(svcname, rids=[], disable=True):
    if len(svcname) == 0:
        print >>sys.stderr, "service name must not be empty"
        return 1
    if svcname not in list_services():
        print >>sys.stderr, "service", svcname, "does not exist"
        return 1
    envfile = os.path.join(rcEnv.pathetc, svcname+'.env')
    conf = ConfigParser.RawConfigParser()
    conf.read(envfile)
    for rid in rids:
        if not conf.has_section(rid):
            print >>sys.stderr, "service", svcname, "has not resource", rid
            continue
        conf.set(rid, "disable", disable)
    try:
       f = open(envfile, 'w')
    except:
        print >>sys.stderr, "failed to open", envfile, "for writing"
        return 1
    conf.write(f)
    return 0

def disable_one(svcname, rids=[]):
    return toggle_one(svcname, rids, disable=True)

def disable(svcnames, rid=[]):
    fix_default_section(svcnames)
    if len(rid) == 0:
        print "no resource flagged for disabling"
        return 0
    r = 0
    for svcname in svcnames:
        r |= disable_one(svcname, rid)
    return r

def enable_one(svcname, rids=[]):
    return toggle_one(svcname, rids, disable=False)

def enable(svcnames, rid=[]):
    fix_default_section(svcnames)
    if len(rid) == 0:
        print "no resource flagged for enabling"
        return 0
    r = 0
    for svcname in svcnames:
        r |= enable_one(svcname, rid)
    return r

def delete_one(svcname, rids=[]):
    if len(svcname) == 0:
        print >>sys.stderr, "service name must not be empty"
        return 1
    if svcname not in list_services():
        print >>sys.stderr, "service", svcname, "does not exist"
        return 0
    envfile = os.path.join(rcEnv.pathetc, svcname+'.env')
    conf = ConfigParser.RawConfigParser()
    conf.read(envfile)
    for rid in rids:
        if not conf.has_section(rid):
            print >>sys.stderr, "service", svcname, "has not resource", rid
            continue
        conf.remove_section(rid)
    try:
       f = open(envfile, 'w')
    except:
        print >>sys.stderr, "failed to open", envfile, "for writing"
        return 1
    conf.write(f)
    return 0

def delete(svcnames, rid=[]):
    fix_default_section(svcnames)
    if len(rid) == 0:
        print "no resource flagged for deletion"
        return 0
    r = 0
    for svcname in svcnames:
        r |= delete_one(svcname, rid)
    return r

def create(svcname, resources=[], interactive=False):
    if not isinstance(svcname, list):
        print >>sys.stderr, "ouch, svcname should be a list object"
        return 1
    if len(svcname) != 1:
        print >>sys.stderr, "you must specify a single service name with the 'create' action"
        return 1
    svcname = svcname[0]
    if len(svcname) == 0:
        print >>sys.stderr, "service name must not be empty"
        return 1
    if svcname in list_services():
        print >>sys.stderr, "service", svcname, "already exists"
        return 1
    envfile = os.path.join(rcEnv.pathetc, svcname+'.env')
    if os.path.exists(envfile):
        print >>sys.stderr, envfile, "already exists"
        return 1
    try:
       f = open(envfile, 'w')
    except:
        print >>sys.stderr, "failed to open", envfile, "for writing"
        return 1

    defaults = {}
    sections = {}
    rtypes = {}

    import json
    for r in resources:
        try:
            d = json.loads(r)
        except:
            print >>sys.stderr, "can not parse resource:", r
            return 1
        if 'rid' in d:
            section = d['rid']
            if '#' not in section:
                print >>sys.stderr, section, "must be formatted as 'rtype#n'"
                return 1
            l = section.split('#')
            if len(l) != 2:
                print >>sys.stderr, section, "must be formatted as 'rtype#n'"
                return 1
            rtype = l[1]
            if rtype in rtypes:
                rtypes[rtype] += 1
            else:
                rtypes[rtype] = 0
            del(d['rid'])
            if section in sections:
                sections[section].update(d)
            else:
                sections[section] = d
        elif 'rtype' in d:
            if 'rid' in d:
               del(d['rid'])
            rtype = d['rtype']
            if rtype in rtypes:
                section = '%s#%d'%(rtype, rtypes[rtype])
                rtypes[rtype] += 1
            else:
                section = '%s#0'%rtype
                rtypes[rtype] = 1
            if section in sections:
                sections[section].update(d)
            else:
                sections[section] = d
        else:
            defaults.update(d)

    from svcDict import KeyDict, MissKeyNoDefault, KeyInvalidValue
    try:
        keys = KeyDict()
        defaults.update(keys.update('DEFAULT', defaults))
        for section, d in sections.items():
            sections[section].update(keys.update(section, d))
    except (MissKeyNoDefault, KeyInvalidValue):
        if not interactive:
            return 1

    try:
        if interactive:
            defaults, sections = keys.form(defaults, sections)
    except KeyboardInterrupt:
        sys.stderr.write("Abort\n")
        return 1

    conf = ConfigParser.RawConfigParser(defaults)
    for section, d in sections.items():
        conf.add_section(section)
        for key, val in d.items():
            if key == 'rtype':
                continue
            conf.set(section, key, val)

    conf.write(f)

    os.chdir(rcEnv.pathetc)
    if os.path.exists(svcname) and not os.path.islink(svcname):
        os.unlink(svcname)
    if not os.path.exists(svcname):
        os.symlink(os.path.join('..', 'bin', 'svcmgr'), svcname)
    initdir = svcname+'.dir'
    if not os.path.exists(initdir):
        os.makedirs(initdir)
    if not os.path.islink(svcname+'.d') and os.path.exists(svcname+'.d'):
        os.unlink(svcname+'.d')
    if not os.path.exists(svcname+'.d'):
        os.symlink(initdir, svcname+'.d')

def update(svcname, resources=[], interactive=False):
    fix_default_section(svcname)
    if not isinstance(svcname, list):
        print >>sys.stderr, "ouch, svcname should be a list object"
        return 1
    if len(svcname) != 1:
        print >>sys.stderr, "you must specify a single service name with the 'create' action"
        return 1
    svcname = svcname[0]
    if len(svcname) == 0:
        print >>sys.stderr, "service name must not be empty"
        return 1
    if svcname not in list_services():
        print >>sys.stderr, "service", svcname, "does not exist"
        return 1
    envfile = os.path.join(rcEnv.pathetc, svcname+'.env')
    sections = {}
    rtypes = {}
    conf = ConfigParser.RawConfigParser()
    conf.read(envfile)
    defaults = conf.defaults()
    for section in conf.sections():
        sections[section] = {}
        for o, v in conf.items(section):
            if o in defaults.keys() + ['rtype']:
                continue
            sections[section][o] = v

    import json
    for r in resources:
        try:
            d = json.loads(r)
        except:
            print >>sys.stderr, "can not parse resource:", r
            return 1
        if 'rid' in d:
            section = d['rid']
            if '#' not in section:
                print >>sys.stderr, section, "must be formatted as 'rtype#n'"
                return 1
            l = section.split('#')
            if len(l) != 2:
                print >>sys.stderr, section, "must be formatted as 'rtype#n'"
                return 1
            rtype = l[0]
            if rtype in rtypes:
                rtypes[rtype] += 1
            else:
                rtypes[rtype] = 0
            del(d['rid'])
            if section in sections:
                sections[section].update(d)
            else:
                sections[section] = d
        elif 'rtype' in d:
            print >>sys.stderr, section, "'rtype' can not be used with the 'update' command"
            return 1
        else:
            defaults.update(d)

    conf = ConfigParser.RawConfigParser(defaults)
    for section, d in sections.items():
        conf.add_section(section)
        for key, val in d.items():
            conf.set(section, key, val)

    try:
        f = open(envfile, 'w')
    except:
        print >>sys.stderr, "failed to open", envfile, "for writing"
        return 1

    conf.write(f)

    os.chdir(rcEnv.pathetc)
    if not os.path.islink(svcname):
        os.unlink(svcname)
    if not os.path.exists(svcname):
        os.symlink(os.path.join('..', 'bin', 'svcmgr'), svcname)
    initdir = svcname+'.dir'
    if not os.path.exists(initdir):
        os.makedirs(initdir)
    if not os.path.islink(svcname+'.d'):
        os.unlink(svcname+'.d')
    if not os.path.exists(svcname+'.d'):
        os.symlink(initdir, svcname+'.d')

def _fix_default_section(svcname):
    """ [default] section is not returned by ConfigParser.defaults()
        [DEFAULT] is. Just replace when this occurs.
    """
    envfile = os.path.join(rcEnv.pathetc, svcname+'.env')
    if not os.path.exists(envfile):
        # nothing to fix
        return
    try:
        f = open(envfile, 'r')
    except:
        print >>sys.stderr, "failed to open", envfile, "for reading"
        return 1
    found = False
    lines = []
    for line in f.readlines():
        if line.startswith('[default]'):
            line = '[DEFAULT]\n'
            found = True
        lines.append(line)
    f.close()
    if found:
        try:
            f = open(envfile, 'w')
        except:
            print >>sys.stderr, "failed to open", envfile, "for writing"
            return 1
        f.write(''.join(lines))
        f.close()

def fix_default_section(svcnames):
    for svcname in svcnames:
        _fix_default_section(svcname)
   070701000671ea000081a40000000000000000000000014d9d7e6e0000161f000000b600010002ffffffffffffffff0000002400000000root/opt/opensvc/lib/rcGlobalEnv.py   #
# Copyright (c) 2009 Christophe Varoqui <christophe.varoqui@free.fr>'
# Copyright (c) 2009 Cyril Galibern <cyril.galibern@free.fr>'
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#
"""module rcGlobalEnv module define rcEnv class
   rcEnv class attribute may be updated with rcLocalEnv module if present
   rcLocalEnv module is not provided with opensvc and allow customers to
   redefine following vars:
       o dbopensvc_host
       o dbopensvc_port
       o rsh
       o rcp
   rcLocalEnv.py may be installed into path_opensvc/lib
"""
import sys
import os
from rcFunctions import update_cl_attr

class rcEnv:
    """Class to store globals
    """

    allowed_svctype = ['PRD', 'PPRD', 'REC', 'INT', 'DEV', 'TST', 'TMP']
    platform = sys.platform

    """program used to execute remote command on other nodes or virtual hosts
    """
    if platform == "sunos5" :
        if os.path.exists('/usr/local/bin/ssh'):
            rsh = "/usr/local/bin/ssh -o StrictHostKeyChecking=no -o ForwardX11=no -o BatchMode=yes -o ConnectTimeout=10"
            rcp = "/usr/local/bin/scp -o StrictHostKeyChecking=no -o ForwardX11=no -o BatchMode=yes -o ConnectTimeout=10"
        else:
            rsh = "/usr/bin/ssh -o StrictHostKeyChecking=no -o ForwardX11=no -o BatchMode=yes -n"
            rcp = "/usr/bin/scp -o StrictHostKeyChecking=no -o ForwardX11=no -o BatchMode=yes"
    else :
        rsh = "/usr/bin/ssh -o StrictHostKeyChecking=no -o ForwardX11=no -o BatchMode=yes -o ConnectTimeout=10"
        rcp = "/usr/bin/scp -o StrictHostKeyChecking=no -o ForwardX11=no -o BatchMode=yes -o ConnectTimeout=10"

    """Database sink for node and service configurations and status collection.
    """
    dbopensvc_host = "dbopensvc"
    dbopensvc_port = "8000"
    dbopensvc_app = "feed"

    """EZ-HA defines. EZ-HA does heartbeat, stonith, automatic service failover

    ez_last_chance == True:
        check_up_script_gen.sh will try a ping + RSH other node before stonith
    ez_startapp_bg == True:
        startapp in background if EZ-HA take-over is succesful
    """
    ez_path = "/usr/local/cluster"
    ez_path_services = ez_path + "/conf/services"
    ez_last_chance = True
    ez_startapp_bg = True

    """Directory on DRP node where to store the PRD nodes files necessary
    for takeover.
    """
    drp_path = "/opt/opensvc/var/cache/"
    drp_sync_excludes = [
        '--exclude="/spice"',
        '--exclude="/dbadm"',
        '--exclude="*.dmp"',
        '--exclude="*.dbf"',
        '--exclude="*.rdo"',
        '--exclude="*.log"',
        '--exclude="*.Z"',
        '--exclude="*.gz"',
        '--exclude="*.tgz"',
        '--exclude="*.tar"',
        '--exclude="*.tmp"',
        '--exclude="/oracle/ficimp"',
        '--exclude="/oracle/tmp"',
        '--exclude="/oracle/LOG/*"',
        '--exclude="/oracle/product/*/network/log/listener*.log"',
    ]
    drp_sync_etc_solaris = [
        "/etc/inet",
        "/etc/inetd.conf",
        "/etc/defaultdomain",
        "/etc/lp",
        "/etc/printers.conf",
        "/etc/system",
        "/etc/auto_master",
        "/etc/auto_home",
        "/etc/hosts.equiv",
        "/etc/pam.conf",
        "/etc/cron.d",
    ]
    drp_sync_etc_linux = [
        # linux
        "/etc/xinetd.d",
        "/etc/xinetd.conf",
        "/etc/sysconfig",
        "/etc/cups",
        "/etc/auto.master",
        "/etc/auto.misc",
        "/etc/listener.ora",
        "/etc/oratab",
        "/etc/sqlnet.ora",
        "/etc/tnsnames.ora",
        "/etc/yp.conf",
        "/etc/pam.d",
        "/etc/cron.allow",
        "/etc/cron.deny",
    ]
    drp_sync_etc_common = [
        # common
        "/etc/shadow",
        "/etc/passwd",
        "/etc/group",
        "/etc/syslog.conf",
        "/etc/services",
        "/etc/hosts",
        "/etc/nsswitch.conf",
        "/etc/sudoers",
        "/etc/project",
        "/etc/user_attr",
        "/etc/ssh",
        "/etc/centrifydc",
        "/etc/krb5*",
        "/etc/sudoers",
    ]
    drp_sync_misc = [
        "/var/centrifydc",
        "/var/opt/oracle",
        "/var/spool/cron",
        "/var/spool/cron/crontabs",
        "/var/yp/binding",
        "/usr/local/oraenv", "/usr/local/coraenv", "/usr/local/dbhome",
        "/usr/local/etc/sudoers",
    ]
    drp_sync_files = [
        [drp_sync_etc_solaris + drp_sync_etc_linux + drp_sync_etc_common + drp_sync_misc, []],
        [["/home/oracle", "/home/sybase", "/opt/oracle", "/opt/sybase"], drp_sync_excludes],
    ]

    vt_libvirt = ['kvm', 'lxc', 'xen']
    vt_vm = ['ldom', 'hpvm', 'kvm', 'xen', 'vbox']
    vt_container = ['zone', 'lxc', 'jail', 'vz']
    vt_supported = vt_vm + vt_container


    def set_db_url(self):
        self.__class__.dbopensvc = "http://%s:%s/%s/default/call/xmlrpc"%(self.dbopensvc_host, self.dbopensvc_port, self.dbopensvc_app)
        self.__class__.dbcompliance = "http://%s:%s/init/compliance/call/xmlrpc"%(self.dbopensvc_host, self.dbopensvc_port)

update_cl_attr(cl=rcEnv, module="rcLocalEnv")
rcEnv().set_db_url()
 07070100067277000041ed0000000000000000000000034d9d945500000000000000b600010002ffffffffffffffff0000001500000000root/opt/opensvc/var  07070100067278000041ed0000000000000000000000024d9d945500000000000000b600010002ffffffffffffffff0000002000000000root/opt/opensvc/var/compliance   0707010006727b000081ed0000000000000000000000014d9d7e6e000019a8000000b600010002ffffffffffffffff0000003900000000root/opt/opensvc/var/compliance/50-com.opensvc.sys.files  #!/opt/opensvc/bin/python
""" 
Verify file content. The collector provides the format with
wildcards. The module replace the wildcards with contextual
values.

The variable format is json-serialized:

{
  "path": "/some/path/to/file",
  "fmt": "root@corp.com		%%HOSTNAME%%@corp.com"
}

Wildcards:
%%ENV:VARNAME%%		Any environment variable value
%%HOSTNAME%%		Hostname
%%SHORT_HOSTNAME%%	Short hostname

"""

import os
import sys
import json
import stat
import re
import urllib
import tempfile
import pwd
import grp
from subprocess import *

RET_OK = 0
RET_ERR = 1
RET_NA = 2

RET = RET_OK

PREFIX = 'OSVC_COMP_FILES_'

_usr = {}
_grp = {}

sysname, nodename, x, x, machine = os.uname()

def parse_fmt(d):
    fmt = d['fmt']
    p = re.compile('%%ENV:.+%%')
    for m in p.findall(fmt):
        s = m.strip("%").replace('ENV:', '')
        if s in os.environ:
            v = os.environ[s]
        elif 'OSVC_COMP_'+s in os.environ:
            v = os.environ['OSVC_COMP_'+s]
        else:
            print >>sys.stderr, s, 'is not an env variable'
            RET = RET_ERR
            return []
        fmt = fmt.replace(m, v)
    fmt = fmt.replace('%%HOSTNAME%%', nodename)
    fmt = fmt.replace('%%SHORT_HOSTNAME%%', nodename.split('.')[0])
    d['fmt'] = fmt
    return [d]

def parse_ref(d):
    f = tempfile.NamedTemporaryFile()
    tmpf = f.name
    fname, headers = urllib.urlretrieve(d['ref'], tmpf)
    if 'invalid file' in headers.values():
        print >>sys.stderr, d['ref'], "not found on collector"
        return RET_ERR
    d['fmt'] = f.read()
    f.close()
    return parse_fmt(d)

def add_file(v):
    d = json.loads(v)
    if 'path' not in d:
        print >>sys.stderr, 'path should be in the dict:', os.environ[k]
        RET = RET_ERR
        return []
    if 'fmt' not in d and 'ref' not in d:
        print >>sys.stderr, 'fmt or ref should be in the dict:', os.environ[k]
        RET = RET_ERR
        return []
    if 'fmt' in d and 'ref' in d:
        print >>sys.stderr, 'fmt and ref are exclusive:', os.environ[k]
        RET = RET_ERR
        return []
    if 'fmt' in d:
        return parse_fmt(d)
    if 'ref' in d:
        return parse_ref(d)

files = []

for k in [ key for key in os.environ if key.startswith(PREFIX)]:
    try:
        files += add_file(os.environ[k])
    except ValueError:
        print >>sys.stderr, 'failed to parse variable', os.environ[k]

if len(files) == 0:
    print "no applicable variable found in rulesets", PREFIX
    sys.exit(RET_NA)

   
def fixable():
    return RET_NA

def check_file_fmt(f, verbose=False):
    if verbose:
        cmd = ['diff', '-u', f['path'], '-']
    else:
        cmd = ['diff', '-q', f['path'], '-']
    p = Popen(cmd, stdin=PIPE)
    out, err = p.communicate(input=f['fmt'])
    return p.returncode

def check_file_mode(f, verbose=False):
    if 'mode' not in f:
        return RET_OK
    try:
        mode = oct(stat.S_IMODE(os.stat(f['path']).st_mode))
    except:
        if verbose: print >>sys.stderr, f['path'], 'can not stat file'
        return RET_ERR
    mode = str(mode).lstrip("0")
    if mode != f['mode']:
        if verbose: print >>sys.stderr, f['path'], 'mode should be %s but is %s'%(f['mode'], mode)
        return RET_ERR
    return RET_OK

def get_uid(uid):
    if uid in _usr:
        return _usr[uid]
    tuid = uid
    if isinstance(uid, (str, unicode)):
        try:
            info=pwd.getpwnam(uid)
            tuid = info[2]
            _usr[uid] = tuid
        except:
            pass
    return tuid

def get_gid(gid):
    if gid in _grp:
        return _grp[gid]
    tgid = gid
    if isinstance(gid, (str, unicode)):
        try:
            info=grp.getgrnam(gid)
            tgid = info[2]
            _grp[gid] = tgid
        except:
            pass
    return tgid

def check_file_uid(f, verbose=False):
    if 'uid' not in f:
        return RET_OK
    tuid = get_uid(f['uid'])
    uid = os.stat(f['path']).st_uid
    if uid != tuid:
        if verbose: print >>sys.stderr, f['path'], 'uid should be %s but is %s'%(tuid, str(uid))
        return RET_ERR
    return RET_OK

def check_file_gid(f, verbose=False):
    if 'gid' not in f:
        return RET_OK
    tgid = get_gid(f['gid'])
    gid = os.stat(f['path']).st_gid
    if gid != tgid:
        if verbose: print >>sys.stderr, f['path'], 'gid should be %s but is %s'%(tgid, str(gid))
        return RET_ERR
    return RET_OK

def check_file(f, verbose=False):
    if not os.path.exists(f['path']):
        print >>sys.stderr, f['path'], "does not exist"
        return RET_ERR
    r = 0
    r |= check_file_fmt(f, verbose)
    r |= check_file_mode(f, verbose)
    r |= check_file_uid(f, verbose)
    r |= check_file_gid(f, verbose)
    return r

def fix_file_mode(f):
    if 'mode' not in f:
        return RET_OK
    if check_file_mode(f) == RET_OK:
        return RET_OK
    try:
        print "set %s mode to %s"%(f['path'], f['mode'])
        os.chmod(f['path'], int(f['mode'], 8))
    except:
        return RET_ERR
    return RET_OK

def fix_file_owner(f):
    uid = -1
    gid = -1

    if 'uid' not in f and 'gid' not in f:
        return RET_OK
    if 'uid' in f and check_file_uid(f) != RET_OK:
        uid = get_uid(f['uid'])
    if 'gid' in f and check_file_gid(f) != RET_OK:
        gid = get_uid(f['gid'])
    if uid == -1 and gid == -1:
        return RET_OK
    try:
        print "set %s ownership to %d:%d"%(f['path'], uid, gid)
        os.chown(f['path'], uid, gid)
    except:
        return RET_ERR
    return RET_OK

def fix_file_fmt(f):
    if check_file_fmt(f) == RET_OK:
        return RET_OK
    d = os.path.dirname(f['path'])
    if not os.path.exists(d):
       os.makedirs(d)
       os.chown(d, f['uid'], f['gid'])
    try:
        with open(f['path'], 'w') as fi:
            fi.write(f['fmt'])
    except:
        return RET_ERR
    return RET_OK

def check():
    r = 0
    for f in files:
        r |= check_file(f, verbose=True)
    return r

def fix():
    r = 0
    for f in files:
        r |= fix_file_fmt(f)
        r |= fix_file_mode(f)
        r |= fix_file_owner(f)
    return r

#
# Main
#
if len(sys.argv) != 2:
    print >>sys.stderr, "need argument"
    sys.exit(RET_ERR)
try:
    if sys.argv[1] == 'check':
        RET = check()
    elif sys.argv[1] == 'fix':
        RET = fix()
    elif sys.argv[1] == 'fixable':
        RET = fixable()
    else:
        print >>sys.stderr, "unsupported argument '%s'"%sys.argv[1]
        RET = RET_ERR
except:
    import traceback
    traceback.print_exc()
    sys.exit(RET_ERR)

sys.exit(RET)
07070100067279000081ed0000000000000000000000014d9d7e6e00001024000000b600010002ffffffffffffffff0000003900000000root/opt/opensvc/var/compliance/49-com.opensvc.sys.group  #!/opt/opensvc/bin/python
""" 
module use OSVC_COMP_GROUP_... vars
which define {'groupname':{'propname':'propval',... }, ...}

example: 
{"tibco":{"gid":1000,"members":"tibco,tibadm",},
 "tibco1":{"gid":1001,"members":"tibco",},
}

supported dictionnary keys:
- gid

dictionnary keys used by another module:
- members
"""

import os
import sys
import json
import grp
from subprocess import Popen 

RET_OK = 0
RET_ERR = 1
RET_NA = 2

RET = RET_ERR

PREFIX = 'OSVC_COMP_GROUP_'

grt = {
    'gid': 'gr_gid',
}

groupmod_p = {
    'gid': '-g',
}

sysname, nodename, x, x, machine = os.uname()

if sysname not in ['SunOS', 'Linux']:
    print 'module not supported on', sysname
    sys.exit(RET_NA)

groups = {}
for k in [ key for key in os.environ if key.startswith(PREFIX)]:
    try:
        groups.update(json.loads(os.environ[k]))
    except ValueError:
        print 'group syntax error on var[', k, '] = ',os.environ[k]

if len(groups) == 0:
    print "no applicable variable found in rulesets",PREFIX
    sys.exit(RET_NA)

def fixable():
    return RET_NA

def fix_item(group, item, target):
    if item in groupmod_p:
        cmd = ['groupmod', groupmod_p[item], str(target), group]
        print ' '.join(cmd)
        p = Popen(cmd)
        out, err = p.communicate()
        r = p.returncode    
        if r == 0:
            return RET_OK
        else:
            return RET_ERR
    else:
        print >>sys.stderr, 'no fix implemented for', item
        return RET_ERR

def check_item(group, item, target, current, verbose=False):
    if target == current:
        if verbose:
            print 'OK: group:', group, item+':', current
        return RET_OK
    else:
        if verbose:
            print >>sys.stderr, 'group:', group, item+':', current, 'target:', target
        return RET_ERR 

def try_create_group(props):
    #   
    # don't try to create group if passwd db is not 'files'
    # beware: 'files' db is the implicit default
    #   
    if 'db' in props and props['db'] != 'files':
        return False
    if set(grt.keys()) <= set(props.keys()):
        return True
    return False

def check_group(group, props):
    r = 0
    try:
        groupinfo = grp.getgrnam(group)
    except KeyError:
        if try_create_group(props):
            print >>sys.stderr, 'group', group, 'does not exist'
            return RET_ERR
        else:
            print 'group', group, 'does not exist and not enough info to create it'
            return RET_OK
    for prop in grt:
        if prop in props:
            r |= check_item(group, prop, props[prop], getattr(groupinfo, grt[prop]), verbose=True)
    return r

def create_group(group, props):
    cmd = ['groupadd']
    for item in grt:
        cmd += [groupmod_p[item], str(props[item])]
    cmd += [group]
    print ' '.join(cmd)
    p = Popen(cmd)
    out, err = p.communicate()
    r = p.returncode    
    if r == 0:
        return RET_OK
    else:
        return RET_ERR

def fix_group(group, props):
    r = 0
    try:
        groupinfo = grp.getgrnam(group)
    except KeyError:
        if try_create_group(props):
            return create_group(group, props)
        else:
            print 'group', group, 'does not exist'
            return RET_OK
    for prop in grt:
        if prop in props and \
           check_item(group, prop, props[prop], getattr(groupinfo, grt[prop])) != RET_OK:
            r |= fix_item(group, prop, props[prop])
    return r

def check():
    r = 0
    for group, props in groups.items():
        r |= check_group(group, props)
    return r

def fix():
    r = 0
    for group, props in groups.items():
        r |= fix_group(group, props)
    return r

#
# Main
#
if len(sys.argv) != 2:
    print >>sys.stderr, "need argument"
    sys.exit(RET_ERR)
try:
    if sys.argv[1] == 'check':
        RET = check()
    elif sys.argv[1] == 'fix':
        RET = fix()
    elif sys.argv[1] == 'fixable':
        RET = fixable()
    else:
        print >>sys.stderr, "unsupported argument '%s'"%sys.argv[1]
        RET = RET_ERR
except:
    import traceback
    traceback.print_exc()
    sys.exit(RET_ERR)

sys.exit(RET)
0707010006727a000081ed0000000000000000000000014d9d7e6e0000185c000000b600010002ffffffffffffffff0000003800000000root/opt/opensvc/var/compliance/50-com.opensvc.sys.cron   #!/opt/opensvc/bin/python

import os
import sys
import shutil
import glob
from subprocess import *

RET_OK = 0
RET_ERR = 1
RET_NA = 2

RET = 1
prefix = 'OSVC_COMP_CRON_ENTRY_'
ce = []

sysname, nodename, x, x, machine = os.uname()

class Unfixable(Exception):
     def __init__(self, s):
         self.s = s
     def __str__(self):
         return self.s

class ComplianceError(Exception):
     def __init__(self, s):
         self.s = s
     def __str__(self):
         return self.s

if sysname == 'SunOS' :
    crontab_locs = [
        '/var/spool/cron/crontabs'
    ]
else:
    crontab_locs = [
        '/etc/cron.d',
        '/var/spool/cron/crontabs',
        '/var/spool/cron',
        '/var/cron/tabs',
    ]

for k in os.environ:
    if k[:len(prefix)] == prefix:
        e = os.environ[k].split(':')
        if len(e) < 5:
            print >>sys.stderr, "malformed variable %s. format: action:user:sched:cmd:[file]"%k
            continue
        if e[0] not in ('add', 'del'):
            print >>sys.stderr, "unsupported action in variable %s. set 'add' or 'del'"%k
            continue
        if len(e[2].split()) != 5:
            print >>sys.stderr, "malformed schedule in variable %s"%k
            continue
        ce += [{
                'var': k,
                'action': e[0],
                'user': e[1],
                'sched': e[2],
                'cmd': e[3],
                'file': e[4],
               }]

if len(ce) == 0:
    print "no applicable variable found in rulesets"
    sys.exit(2)


def activate_cron(cron_file):
    """ Activate changes (actually only needed on HP-UX)
    """
    if '/var/spool/' in cron_file:
        print "tell crond about the change"
        cmd = ['crontab', cron_file]
        process = Popen(cmd, stdout=PIPE, stderr=PIPE, close_fds=True)
        buff = process.communicate()

def fixable_cron():
    r = RET_OK
    for e in ce:
        try:
            _fixable_cron(e)
        except ComplianceError, e:
            print >>sys.stderr, str(e)
            r = RET_ERR
        except Unfixable, e:
            print >>sys.stderr, str(e)
            return r
    return r

def fix_cron():
    r = RET_OK
    for e in ce:
        try:
            if e['action'] == 'add':
                _add_cron(e)
            elif e['action'] == 'del':
                _del_cron(e)
        except ComplianceError, e:
            print >>sys.stderr, str(e)
            r = RET_ERR
        except Unfixable, e:
            print >>sys.stderr, str(e)
            return r
    return r

def check_cron():
    r = RET_OK
    for e in ce:
        try:
            _check_cron(e)
        except ComplianceError, e:
            print >>sys.stderr, str(e)
            r = RET_ERR
        except Unfixable, e:
            print >>sys.stderr, str(e)
            return r
    return r

def get_cron_file(e):
    """ order of preference
    """
    cron_file = None
    for loc in crontab_locs:
        if not os.path.exists(loc):
            continue
        if loc == '/etc/cron.d':
             cron_file = os.path.join(loc, e['file'])
        else:
             cron_file = os.path.join(loc, e['user'])
        break
    return cron_file

def format_entry(cron_file, e):
    if 'cron.d' in cron_file:
        s = ' '.join([e['sched'], e['user'], e['cmd']])
    else:
        s = ' '.join([e['sched'], e['cmd']])
    return s

def _fixable_cron(e):
    cron_file = get_cron_file(e)

    if cron_file is None:
        raise Unfixable("no crontab usual location found (%s)"%str(crontab_locs))

def _check_cron(e):
    cron_file = get_cron_file(e)

    if cron_file is None:
        raise Unfixable("no crontab usual location found (%s)"%str(crontab_locs))

    s = format_entry(cron_file, e)

    if not os.path.exists(cron_file):
        raise ComplianceError("cron entry not found '%s' in '%s'"%(s, cron_file))

    with open(cron_file, 'r') as f:
        new = f.readlines()
        found = False
        for line in new:
            if s == line[:-1]:
                 found = True
                 break
        if not found and e['action'] == 'add':
            raise ComplianceError("wanted cron entry not found: '%s' in '%s'"%(s, cron_file))
        if found and e['action'] == 'del':
            raise ComplianceError("unwanted cron entry found: '%s' in '%s'"%(s, cron_file))

def _del_cron(e):
    cron_file = get_cron_file(e)

    if cron_file is None:
        raise Unfixable("no crontab usual location found (%s)"%str(crontab_locs))

    s = format_entry(cron_file, e)

    if not os.path.exists(cron_file):
        return

    new = []
    with open(cron_file, 'r') as f:
        lines = f.readlines()
        for line in lines:
            if s == line[:-1]:
                print "delete entry '%s' from '%s'"%(s, cron_file)
                continue
            new.append(line)

    if len(new) == 0:
        print 'deleted last entry of %s. delete file too.'%cron_file
        os.unlink(cron_file)
    else:
        with open(cron_file, 'w') as f:
            f.write(''.join(new))
        activate_cron(cron_file)

def _add_cron(e):
    cron_file = get_cron_file(e)

    if cron_file is None:
        raise Unfixable("no crontab usual location found (%s)"%str(crontab_locs))

    s = format_entry(cron_file, e)

    new = False
    if os.path.exists(cron_file):
        with open(cron_file, 'r') as f:
            new = f.readlines()
            found = False
            for line in new:
                if s == line[:-1]:
                    found = True
                    break
            if not found:
                new.append(s+'\n')
    else:
        new = [s+'\n']

    if not new:
        raise ComplianceError("problem preparing the new crontab '%s'"%cron_file)
 
    print "add entry '%s' to '%s'"%(s, cron_file)
    with open(cron_file, 'w') as f:
        f.write(''.join(new))
    activate_cron(cron_file)

#
# Main
#
if len(sys.argv) != 2:
    print >>sys.stderr, "need argument"
    sys.exit(1)

if sys.argv[1] == 'check':
    sys.exit(check_cron())
elif sys.argv[1] == 'fix':
    sys.exit(fix_cron())
elif sys.argv[1] == 'fixable':
    sys.exit(fixable_cron())
else:
    print >>sys.stderr, "unsupported argument '%s'"%sys.argv[1]
    sys.exit(RET_ERR)
0707010006727d000081ed0000000000000000000000014d9d7e6e00001085000000b600010002ffffffffffffffff0000003800000000root/opt/opensvc/var/compliance/50-com.opensvc.sys.user   #!/opt/opensvc/bin/python
""" 
module use OSVC_COMP_USER_... vars
which define {'username':{'propname':'propval',... }, ...}

example: 
{"tibco":{"shell":"/bin/ksh","gecos":"agecos",},
 "tibco1":{"shell":"/bin/tcsh","gecos":"another gecos",},
}

supported dictionnary keys:
- uid
- gid
- gecos
- homedir
- shell
"""

import os
import sys
import json
import pwd
from subprocess import Popen, list2cmdline

RET_OK = 0
RET_ERR = 1
RET_NA = 2

RET = RET_ERR

PREFIX = 'OSVC_COMP_USER_'

pwt = {
    'shell': 'pw_shell',
    'homedir': 'pw_dir',
    'uid': 'pw_uid',
    'gid': 'pw_gid',
    'gecos': 'pw_gecos',
}

usermod_p = {
    'shell': '-s',
    'homedir': '-m -d',
    'uid': '-u',
    'gid': '-g',
    'gecos': '-c',
}

sysname, nodename, x, x, machine = os.uname()

if sysname not in ['SunOS', 'Linux']:
    print 'module not supported on', sysname
    sys.exit(RET_NA)

users = {}
for k in [ key for key in os.environ if key.startswith(PREFIX)]:
    try:
        users.update(json.loads(os.environ[k]))
    except ValueError:
        print 'user syntax error on var[', k, '] = ',os.environ[k]

if len(users) == 0:
    print "no applicable variable found in rulesets",PREFIX
    sys.exit(RET_NA)

def fixable():
    return RET_NA

def fix_item(user, item, target):
    cmd = ['usermod'] + usermod_p[item].split() + [str(target), user]
    print list2cmdline(cmd)
    p = Popen(cmd)
    out, err = p.communicate()
    r = p.returncode    
    if r == 0:
        return RET_OK
    else:
        return RET_ERR

def check_item(user, item, target, current, verbose=False):
    if target == current:
        if verbose:
            print 'OK: user:', user, item+':', current
        return RET_OK
    else:
        if verbose:
            print >>sys.stderr, 'user:', user, item+':', current, 'target:', target
        return RET_ERR 

def check_user(user, props):
    r = 0
    try:
        userinfo=pwd.getpwnam(user)
    except KeyError:
        if try_create_user(props):
            print >>sys.stderr, 'user', user, 'does not exist'
            return RET_ERR
        else:
            print 'user', user, 'does not exist and not enough info to create it'
            return RET_OK
    for prop in pwt:
        if prop in props:
            r |= check_item(user, prop, props[prop], getattr(userinfo, pwt[prop]), verbose=True)
    return r

def try_create_user(props):
    #
    # don't try to create user if passwd db is not 'files'
    # beware: 'files' db is the implicit default
    #
    if 'db' in props and props['db'] != 'files':
        return False
    if set(pwt.keys()) <= set(props.keys()):
        return True
    return False

def create_user(user, props):
    cmd = ['useradd']
    for item in pwt:
        prop = str(props[item])
        if len(prop) == 0:
            continue
        cmd = cmd + usermod_p[item].split() + [prop]
    cmd += [user]
    print list2cmdline(cmd)
    p = Popen(cmd)
    out, err = p.communicate()
    r = p.returncode    
    if r == 0:
        return RET_OK
    else:
        return RET_ERR

def fix_user(user, props):
    r = 0
    try:
        userinfo=pwd.getpwnam(user)
    except KeyError:
        if try_create_user(props):
            return create_user(user, props)
        else:
            print 'user', user, 'does not exist and not enough info to create it'
            return RET_OK
    for prop in pwt:
        if prop in props and \
           check_item(user, prop, props[prop], getattr(userinfo, pwt[prop])) != RET_OK:
            r |= fix_item(user, prop, props[prop])
    return r

def check():
    r = 0
    for user, props in users.items():
        r |= check_user(user, props)
    return r

def fix():
    r = 0
    for user, props in users.items():
        r |= fix_user(user, props)
    return r

#
# Main
#
if len(sys.argv) != 2:
    print >>sys.stderr, "need argument"
    sys.exit(RET_ERR)
try:
    if sys.argv[1] == 'check':
        RET = check()
    elif sys.argv[1] == 'fix':
        RET = fix()
    elif sys.argv[1] == 'fixable':
        RET = fixable()
    else:
        print >>sys.stderr, "unsupported argument '%s'"%sys.argv[1]
        RET = RET_ERR
except:
    import traceback
    traceback.print_exc()
    sys.exit(RET_ERR)
sys.exit(RET)
   0707010006727c000081ed0000000000000000000000014d9d7e6e00000c26000000b600010002ffffffffffffffff0000003c00000000root/opt/opensvc/var/compliance/50-com.opensvc.sys.packages   #!/opt/opensvc/bin/python
""" 
module use OSVC_COMP_PACKAGES_... vars
which define ['pkg1', 'pkg2', ...]
"""

import os
import sys
import json
import pwd
from subprocess import *

RET_OK = 0
RET_ERR = 1
RET_NA = 2

RET = RET_ERR

PREFIX = 'OSVC_COMP_PACKAGES_'

sysname, nodename, x, x, machine = os.uname()

if sysname not in ['Linux']:
    print 'module not supported on', sysname
    sys.exit(RET_NA)

packages = []
for k in [ key for key in os.environ if key.startswith(PREFIX)]:
    try:
        packages += json.loads(os.environ[k])
    except ValueError:
        print >>sys.stderr, 'failed to concatenate', os.environ[k], 'to package list'

if len(packages) == 0:
    print "no applicable variable found in rulesets", PREFIX
    sys.exit(RET_NA)

def rpm_get_installed_packages():
    p = Popen(['rpm', '-qa', '--qf', '%{n}\n'], stdout=PIPE)
    (out, err) = p.communicate()
    if p.returncode != 0:
        print >>sys.stderr, 'can not fetch installed packages list'
        return []
    return out.split('\n')

def deb_get_installed_packages():
    p = Popen(['dpkg', '-l'], stdout=PIPE)
    (out, err) = p.communicate()
    if p.returncode != 0:
        print >>sys.stderr, 'can not fetch installed packages list'
        return []
    l = []
    for line in out.split('\n'):
        if not line.startswith('ii'):
            continue
        l.append(line.split()[1])
    return l

def yum_fix_pkg(pkg):
    if check_pkg(pkg, verbose=False) == RET_OK:
        return RET_OK
    r = call(['yum', 'install', '-y', pkg])
    if r != 0:
        return RET_ERR
    return RET_OK

def apt_fix_pkg(pkg):
    if check_pkg(pkg, verbose=False) == RET_OK:
        return RET_OK
    r = call(['apt-get', 'install', '-y', pkg])
    if r != 0:
        return RET_ERR
    return RET_OK

vendor = os.environ['OSVC_COMP_NODES_OS_VENDOR']
if vendor == 'Debian':
    get_installed_packages = deb_get_installed_packages
    fix_pkg = apt_fix_pkg
elif vendor in ['CentOS', 'Redhat']:
    get_installed_packages = rpm_get_installed_packages
    fix_pkg = yum_fix_pkg
else:
    print >>sys.stderr, vendor, "not supported"
    sys.exit(RET_ERR)

installed_packages = get_installed_packages()

def fixable():
    return RET_NA

def check_pkg(pkg, verbose=True):
    if not pkg in installed_packages:
        if verbose:
            print >>sys.stderr, 'package', pkg, 'is not installed'
        return RET_ERR
    if verbose:
        print 'package', pkg, 'is installed'
    return RET_OK

def check():
    r = 0
    for pkg in packages:
        r |= check_pkg(pkg)
    return r

def fix():
    r = 0
    for pkg in packages:
        r |= fix_pkg(pkg)
    return r

#
# Main
#
if len(sys.argv) != 2:
    print >>sys.stderr, "need argument"
    sys.exit(RET_ERR)
try:
    if sys.argv[1] == 'check':
        RET = check()
    elif sys.argv[1] == 'fix':
        RET = fix()
    elif sys.argv[1] == 'fixable':
        RET = fixable()
    else:
        print >>sys.stderr, "unsupported argument '%s'"%sys.argv[1]
        RET = RET_ERR
except:
    import traceback
    traceback.print_exc()
    sys.exit(RET_ERR)
sys.exit(RET)
  0707010006727e000081ed0000000000000000000000014d9d7e6e00001089000000b600010002ffffffffffffffff0000004400000000root/opt/opensvc/var/compliance/51-com.opensvc.sys.group.membership   #!/opt/opensvc/bin/python
""" 
module use OSVC_COMP_GROUP_... vars
which define {'groupname':{'propname':'propval',... }, ...}

example: 
{"tibco":{"gid":1000,"members":"tibco,tibadm",},
 "tibco1":{"gid":1001,"members":"tibco",},
}

supported dictionnary keys:
- members

dictionnary keys used by another module:
- gid
"""

import os
import sys
import json
import grp
from subprocess import Popen 

RET_OK = 0
RET_ERR = 1
RET_NA = 2

RET = RET_ERR

PREFIX = 'OSVC_COMP_GROUP_'

grt = {
    'members': 'gr_mem',
}

groupmod_p = {}

sysname, nodename, x, x, machine = os.uname()

if sysname not in ['SunOS', 'Linux']:
    print 'module not supported on', sysname
    sys.exit(RET_NA)

#
# initialize a hash to store all group membership
# of users
#
member_of = {}
for group in grp.getgrall():
    for user in group.gr_mem:
        if user in member_of:
            member_of[user].append(group.gr_name)
        else:
            member_of[user] = [group.gr_name]

groups = {}
for k in [ key for key in os.environ if key.startswith(PREFIX)]:
    try:
        groups.update(json.loads(os.environ[k]))
    except ValueError:
        print 'group syntax error on var[', k, '] = ',os.environ[k]

if len(groups) == 0:
    print "no applicable variable found in rulesets",PREFIX
    sys.exit(RET_NA)

def fixable():
    return RET_NA

def del_member(group, user):
    if user not in member_of:
        return 0
    g = set(member_of[user]) - set([group])
    g = ','.join(g)
    return fix_member(g, user)

def add_member(group, user):
    if user in member_of:
        g = set(member_of[user]) | set([group])
        g = ','.join(g)
    else:
        g = group
    return fix_member(g, user)

def fix_member(g, user):
    cmd = ['usermod', '-G', g, user]
    print ' '.join(cmd)
    p = Popen(cmd)
    out, err = p.communicate()
    r = p.returncode    
    if r == 0:
        return RET_OK
    else:
        return RET_ERR

def fix_members(group, target):
    r = 0
    for user in target:
        if user in member_of and group in member_of[user]:
            continue
        r += add_member(group, user)
    for user in [u for u in member_of if group in member_of[u] and u not in target]:
        r += del_member(group, user)
    return r

def fix_item(group, item, target):
    if item == 'members':
        return fix_members(group, target)
    else:
        print >>sys.stderr, 'no fix implemented for', item
        return RET_ERR

def check_item(group, item, target, current, verbose=False):
    if (isinstance(current, list) and set(target) == set(current)) or target == current:
        if verbose:
            print 'OK: group:', group, item+':', current
        return RET_OK
    else:
        if verbose:
            print >>sys.stderr, 'group:', group, item+':', current, 'target:', target
        return RET_ERR 

def check_group(group, props):
    r = 0
    try:
        groupinfo = grp.getgrnam(group)
    except KeyError:
        print 'group', group, 'does not exist'
        return RET_OK
    for prop in grt:
        if prop in props:
            r |= check_item(group, prop, props[prop], getattr(groupinfo, grt[prop]), verbose=True)
    return r

def fix_group(group, props):
    r = 0
    try:
        groupinfo = grp.getgrnam(group)
    except KeyError:
        print 'group', group, 'does not exist'
        return RET_OK
    for prop in grt:
        if prop in props and \
           check_item(group, prop, props[prop], getattr(groupinfo, grt[prop])) != RET_OK:
            r |= fix_item(group, prop, props[prop])
    return r

def check():
    r = 0
    for group, props in groups.items():
        r |= check_group(group, props)
    return r

def fix():
    r = 0
    for group, props in groups.items():
        r |= fix_group(group, props)
    return r

#
# Main
#
if len(sys.argv) != 2:
    print >>sys.stderr, "need argument"
    sys.exit(RET_ERR)
try:
    if sys.argv[1] == 'check':
        RET = check()
    elif sys.argv[1] == 'fix':
        RET = fix()
    elif sys.argv[1] == 'fixable':
        RET = fixable()
    else:
        print >>sys.stderr, "unsupported argument '%s'"%sys.argv[1]
        RET = RET_ERR
except:
    import traceback
    traceback.print_exc()
    sys.exit(RET_ERR)

sys.exit(RET)
   07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000b00000000TRAILER!!!                                                                        