From d76e854b14c6627b449585488472470bdfa070bd Mon Sep 17 00:00:00 2001 From: geos_one Date: Fri, 5 Feb 2010 18:22:49 +0000 Subject: [PATCH] app-admin/mmc-agent: update userquota plugin git-svn-id: https://svn.disconnected-by-peer.at/svn/linamh/trunk/mds@1939 6952d904-891a-0410-993b-d76249ca496b --- app-admin/mmc-agent/ChangeLog | 4 + app-admin/mmc-agent/Manifest | 5 +- .../files/mmc-agent-2.3.2-userquota-2.patch | 1100 +++++++++++++++++ .../mmc-agent/mmc-agent-2.3.2_p798.ebuild | 2 +- 4 files changed, 1108 insertions(+), 3 deletions(-) create mode 100644 app-admin/mmc-agent/files/mmc-agent-2.3.2-userquota-2.patch diff --git a/app-admin/mmc-agent/ChangeLog b/app-admin/mmc-agent/ChangeLog index 1b07184..9271553 100644 --- a/app-admin/mmc-agent/ChangeLog +++ b/app-admin/mmc-agent/ChangeLog @@ -2,6 +2,10 @@ # Copyright 1999-2010 Gentoo Foundation; Distributed under the GPL v2 # $Header: $ + 05 Feb 2010; Mario Fetka + mmc-agent-2.3.2_p798.ebuild, +files/mmc-agent-2.3.2-userquota-2.patch: + update userquota plugin + 02 Feb 2010; Mario Fetka +files/mmc-agent-2.3.2-bulkimport-2.patch: Bump bulkimport patch diff --git a/app-admin/mmc-agent/Manifest b/app-admin/mmc-agent/Manifest index 6c3dcbc..4778a65 100644 --- a/app-admin/mmc-agent/Manifest +++ b/app-admin/mmc-agent/Manifest @@ -5,6 +5,7 @@ AUX mmc-agent-2.3.2-powerdns-1.patch 37711 RMD160 dfade7296129ea3a302fad701845d0 AUX mmc-agent-2.3.2-powerdns-2.patch 38803 RMD160 ecde3d096a278446fbe0f866d6165f5940d53fb2 SHA1 d4518fc05dd57aadb4f05689e9675aa6b96d451b SHA256 33f4d1bd8e6509833bae5eec194c67371cb471c2c25d6978979057af2d67464a AUX mmc-agent-2.3.2-printing-1.patch 33371 RMD160 f7064ec4dfc2e923c522f01190ca5d4f7d493d43 SHA1 ca9219b982e210bd92c85db8f982e1a3c6b9d48b SHA256 97dc50bb286361286e5451d2e85ea9b9d8609a2f92c3f3ca3836e9bcbcd1c931 AUX mmc-agent-2.3.2-userquota-1.patch 28599 RMD160 4f2695794b23d666f8b00769452359700c1cd63a SHA1 88515db08641e0ac0dfef2ea71ea0f223d75bfbe SHA256 3397c6c3642826fefc0314572abf59bfd01a455f1c6048478b38a6e7eb0094cb +AUX mmc-agent-2.3.2-userquota-2.patch 48077 RMD160 76de23a7b625d58f5d1af0f0217470a5829f1d41 SHA1 a10b39598129bf68be78f068bc68e1aca2f84c2c SHA256 779093f7c77c3b418fad7e4d9b5a30996e5f05005959aaf26413b6a4139a3c06 AUX mmc-agent.initd 438 RMD160 d7dc64366782ab0d6fe4347d6a169b88a4e03a49 SHA1 e4ae8808678161237703bbb63b144899c9a544c9 SHA256 922d0bacad3eda749f8807e3ae5c183f636fa93e0d41d7079e570c58ebccb879 DIST mmc-agent-2.3.2-798.tar.gz 122211 RMD160 2630890c80e3e9fdf2d3510659e00692b1d487cb SHA1 914d3ce64f5e49abe1558eab23fa316b8a8ce3ec SHA256 411bb2a8475dda2f08450cae40812f35a5d426047cccd1a560881d41d621c55c DIST mmc-agent-2.3.2.tar.gz 120949 RMD160 871b3b7766d69019de392e42ebf25a216d217c71 SHA1 1e7c634243c00c6b214f24c3467315d31a444215 SHA256 0ac8ff97818c58008cadb3c6b08dba39e42b078fea9d392fda649e036eabaea2 @@ -12,6 +13,6 @@ EBUILD mmc-agent-2.3.2-r1.ebuild 1635 RMD160 774f66ecfc207a8c86dadc010f8d9d04b50 EBUILD mmc-agent-2.3.2-r2.ebuild 1557 RMD160 fd12dd7afc50f7d37dd4d9e0291ec2509cc057ba SHA1 cfa7d9721d4b45a52499c481c99e1449844eeb3b SHA256 1ed12652595fc95f9f98be38721899ae6d811746fd7854687911243dd1d59d6d EBUILD mmc-agent-2.3.2-r3.ebuild 1557 RMD160 2a6e73ba6a2981f4e010fbb05af6439d39e096ad SHA1 35a64b2ec82aef8c5907c11861e7c53cefa0bf76 SHA256 d62618c640f6cf9c531c2a12780046fe1a53ea59712cd8964225a1c436ef4e25 EBUILD mmc-agent-2.3.2-r4.ebuild 1616 RMD160 d8b85301b0c72e1be4f1655ec7fe16b2e338203f SHA1 7d2623589b14a75042f3c6f06dd766b16dc3af42 SHA256 8461d4fc8aba2670dce89d65932d18afa6e85e00aee72c1a134fa14f7496d2c4 -EBUILD mmc-agent-2.3.2_p798.ebuild 1894 RMD160 95d5ea87f389dafff627f9d1e1bcf5dab75a54bb SHA1 a7c8dbdfeb402d02b2f3a9b30deb54dfc933f9d9 SHA256 b6bb3e3660a7ab116f078a5d21bfcb4a322389933484326e4cf5316a10521ca4 -MISC ChangeLog 2267 RMD160 184d398e1948322f06c5a7768ad80b6f869b77f6 SHA1 ebcda0f6faa897aa0dbdbaeee02b2cea13649cbb SHA256 5e0dbc56104c5c7d3341c8fb36e3d1fcf316cc8b2eb99eff0cc3223e96092c79 +EBUILD mmc-agent-2.3.2_p798.ebuild 1894 RMD160 f04527729e2b9579b5816b1e748100aaafa2e12a SHA1 0f633a44d31ce64fc0fffa78a70967601896daeb SHA256 349bf92c07cce748d23fdd149addafbc5399584fa5ba8c2feb2ed1f643aab0f9 +MISC ChangeLog 2418 RMD160 422a18db3d77f876e8f7703722ca036f33cf13af SHA1 2477e6fc6ad2818cead4eaf650026c05aabc9c16 SHA256 17af993dbae9ae7e3d900287114af403b1b827a914f7b674829dd37c3b9b27e1 MISC metadata.xml 170 RMD160 645927a396fdc21cdeb089fe42c5397332420ea6 SHA1 ac7f48a14fec325926f9ce1be8fbf1f311b4f2e4 SHA256 d797a2ec6f9dc516c9f9c1a758ee87ad3e8c43101b5dc76c2f872d5bd4639b42 diff --git a/app-admin/mmc-agent/files/mmc-agent-2.3.2-userquota-2.patch b/app-admin/mmc-agent/files/mmc-agent-2.3.2-userquota-2.patch new file mode 100644 index 0000000..734d1a7 --- /dev/null +++ b/app-admin/mmc-agent/files/mmc-agent-2.3.2-userquota-2.patch @@ -0,0 +1,1100 @@ +Submitted By: Mario Fetka (geos_one) (mario dot fetka at gmail dot com) +Date: 2010-02-05 +Initial Package Version: 2.3.2 +Origin: https://ml.mandriva.net/wws/arc/mds-devel/2010-02/msg00004.html +Upstream Status: unknown +Description: add userquota plugin and add support for large groups quota change (ldap timeout) + +diff -Naur mmc-agent-2.3.2.orig/conf/plugins/userquota.ini mmc-agent-2.3.2/conf/plugins/userquota.ini +--- mmc-agent-2.3.2.orig/conf/plugins/userquota.ini 1970-01-01 00:00:00.000000000 +0000 ++++ mmc-agent-2.3.2/conf/plugins/userquota.ini 2010-01-15 06:19:24.000000000 +0000 +@@ -0,0 +1,19 @@ ++[main] ++disable = 0 ++ ++[diskquota] ++enable = 1 ++# block size found using dumpe2fs -h /dev/vda1 | awk '/Block size:/ { print $3 }' ++ ++# devicemap format: device:blocksize:displayname, ... ++devicemap = /dev/vda1:4096:Test Root,/dev/mapper/home:4096:Home dir ++softquotablocks = 0.95 ++softquotainodes = 0.95 ++inodesperblock = 1.60 ++ ++setquotascript = echo /usr/sbin/setquota $uid $softblocks $blocks $softinodes $inodes $devicepath ++delquotascript = echo /usr/sbin/setquota $uid 0 0 0 0 $devicepath ++ ++[networkquota] ++enable = 1 ++networkmap = Internet:0.0.0.0/0:any +diff -Naur mmc-agent-2.3.2.orig/contrib/ldap/quota.schema mmc-agent-2.3.2/contrib/ldap/quota.schema +--- mmc-agent-2.3.2.orig/contrib/ldap/quota.schema 1970-01-01 00:00:00.000000000 +0000 ++++ mmc-agent-2.3.2/contrib/ldap/quota.schema 2010-01-25 02:16:23.000000000 +0000 +@@ -0,0 +1,30 @@ ++## ++## schema file for Unix Quotas ++## Schema for storing Unix Quotas in LDAP ++## OIDs are owned by Cogent Innovators, LLC ++## ++## 1.3.6.1.4.1.19937.1.1.x - attributetypes ++## 1.3.6.1.4.1.19937.1.2.x - objectclasses ++## ++ ++attributetype ( 1.3.6.1.4.1.19937.1.1.1 NAME 'quota' ++ DESC 'Quotas (FileSystem:BlocksSoft,BlocksHard,InodesSoft,InodesHard)' ++ EQUALITY caseIgnoreIA5Match ++ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} ) ++ ++attributetype ( 1.3.6.1.4.1.19937.1.1.2 NAME 'networkquota' ++ DESC 'Network Quotas (network,protocol,bytes)' ++ EQUALITY caseIgnoreIA5Match ++ SYNTAX 1.3.6.1.4.1.1466.115.121.1.26{255} ) ++ ++objectclass ( 1.3.6.1.4.1.19937.1.2.1 NAME 'systemQuotas' SUP posixAccount AUXILIARY ++ DESC 'System Quotas' ++ MUST ( uid ) ++ MAY ( quota $ networkquota )) ++ ++objectclass ( 1.3.6.1.4.1.19937.1.2.2 NAME 'defaultQuotas' ++ DESC 'Quota defaults to apply to members of a group' ++ SUP top AUXILIARY ++ MUST ( cn ) ++ MAY ( quota $ networkquota )) ++ +diff -Naur mmc-agent-2.3.2.orig/contrib/userquota/README mmc-agent-2.3.2/contrib/userquota/README +--- mmc-agent-2.3.2.orig/contrib/userquota/README 1970-01-01 00:00:00.000000000 +0000 ++++ mmc-agent-2.3.2/contrib/userquota/README 2010-02-04 01:42:11.000000000 +0000 +@@ -0,0 +1,71 @@ ++# (c) 2009 OSS - Glen Ogilvie ++# License: GPLv2 or above ++# Version: 0.0.3 ++ ++Description: Mandriva Directory Server plugin to store disk and network quotas in OpenLDAP and manage them ++using MDS. It provides multiple quotas for both, mapped from the configuration file. It also supports turning ++off either disk or network quotas if you only wish to quota one of them. ++ ++This plugin also supports setting quotas for all the members of a group. This can be done by browsing to the ++group list in MDS and using the edit group action. It also allows you to set quotas per individual, although these ++are reset when you perform a group action. ++ ++When quotas are set for a member of the group, the object classes of that member will be updated to include the systemQuotas schema. ++The group will also have an additional object class added to store the defaults for that group. ++ ++New members of the group do not currently get the group default quotas assigned but may do in the future. ++ ++ ++Installation: ++cp ./etc/mmc/plugins/userquota.ini /etc/mmc/plugins/ ++cp -r ./mmc-python/plugins/userquota /usr/lib64/python2.6/site-packages/mmc/plugins/ ++cp -r ./mmc-web/modules/userquota /usr/share/mmc/modules/ ++cp ./etc/openldap/schema/quota.schema /etc/openldap/schema ++ ++Edit: /etc/openldap/schema/local.schema ++insert line: include /etc/openldap/schema/quota.schema ++restart slapd. ++ ++Patches: ++These patches are against python-ldap-2.3.9-1mdv2010.0 and mmc-agent-2.3.2-8.2mdv2010.0) ++ ++To resolve an ldap connection issue I had, the following files needed to be patched to use the ReconnectLDAPObject. ++ ++/usr/lib64/python2.6/site-packages/mmc/plugins/base/__init__.py (use ReconnectLDAPObject and change ".modify_s(" to ".modify_ext_s(" ++/usr/lib64/python2.6/site-packages/ldap/ldapobject.py (add pass exception after self.reconnect(self._uri)) ++ ++These changes are included in: ++patches/mmc-python-base_userquota_ldap.patch ++patches/ldapobject.patch ++ ++cd /usr/lib64/python2.6 ++patch -p0 < ~/userquota/patches/ldapobject.patch ++patch -p0 < ~/userquota/patches/patches/mmc-python-base_userquota_ldap.patch ++ ++For both of these, I have sent an email to the mmc-devel mailing list to discuss options, as would rather not have to patch these files. ++ ++ ++Configuration: ++Edit: /etc/mmc/plugins/userquota.ini ++ ++Configuration options: diskquota ++devicemap ++ - This maps your physical device that will have the quota applied to a nice human readable name and also includes the block size of the disk ++ used for calculation of megabytes. ++ ++softquotablocks, softquotainodes, inodesperblock ++ - multipliers for the values passed to the quota command. ++ ++setquotascript, delquotascript ++ - system command to run.. Note that in example, these are echo statements so they do nothing ++ ++Configuration options: networkquota ++networkmap ++ - this maps the name of a network to a subnet and protocol. How the subnet and protocol are processed is up to whatever is reading the network ++ - quota values from each user. In my case, a custom script will read these and use them with TC for rate limiting. ++ ++Documentation: ++See: mmc-web/modules/userquota/help/doc.txt ++ ++Bugs: ++The connection the LDAP server may get disconnected sometimes. The code works around this by using the reconnection ldap class for python. +diff -Naur mmc-agent-2.3.2.orig/contrib/userquota/networkquota_example/applyTCrules.py mmc-agent-2.3.2/contrib/userquota/networkquota_example/applyTCrules.py +--- mmc-agent-2.3.2.orig/contrib/userquota/networkquota_example/applyTCrules.py 1970-01-01 00:00:00.000000000 +0000 ++++ mmc-agent-2.3.2/contrib/userquota/networkquota_example/applyTCrules.py 2010-02-04 01:57:16.000000000 +0000 +@@ -0,0 +1,156 @@ ++#!/usr/bin/python ++# -*- coding: utf-8; -*- ++# Example to apply network quotas from ldap to tc traffic shaping rules. ++# ++# (c) 2009 Open Systems Specilists - Glen Ogilvie ++# ++# 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, see . ++ ++ ++# EXAMPLE ONLY: You will need to modify this to suit your network. ++# ++import ldap ++import subprocess ++import re ++import warnings ++ ++# hide DepercationWarning when importing MySQLdb ++with warnings.catch_warnings(): ++ warnings.simplefilter("ignore", DeprecationWarning) ++ import MySQLdb ++ ++uri = "ldap://localhost:389" ++base = "ou=People,dc=example,dc=com" ++scope = ldap.SCOPE_SUBTREE ++filterstr = "(objectClass=systemQuotas)" ++attrlist = ['uid', 'networkquota', 'uidNumber'] ++query = """select sum(bytes_in + bytes_out) as bytes, username from ++ulog where username is not null and bytes_in is not null and bytes_out is not null ++group by username;""" ++ ++# Test command to get tc filters. ++tcfilterlist = "cat tcexample.txt" ++tcapplycmd = "./tcruleadd.sh %s %x" # args: uid, uid in hex ++tcremovecmd = "./tcruledel.sh %s %x" ++ ++ ++ ++def getBytes(username, network): ++ user = False ++ for dn, record in res: ++ if "networkquota" in record: ++# print record["uid"][0] ++ if record["uid"][0] == username: ++ user = True ++ for q in record["networkquota"]: ++ if q.split(',')[0] == network: ++ return q.split(',')[1] ++ ++ if not user: ++ raise NameError("username: %s not in ldap" % username) ++ raise NameError("Getbytes function failed to find matching networkquota attribute value %s record for user: %s" % (network, username)) ++ ++def getUid(username): ++ for dn, record in res: ++ if record["uid"][0] == username: ++ return record["uidNumber"][0] ++ return False ++ ++def hasQuota(username): ++ q = False ++ for dn, record in res: ++ if "networkquota" in record: ++ if record["uid"][0] == username: ++ q = True ++ return q ++ ++def processNetworkQuotas(username, actualbytes): ++ if not hasQuota(username): ++ print "User: %s does not have a network quota set in ldap" % (username) ++ removeRateLimiting(username) ++ return False ++ ++ network = "Internet:0.0.0.0/0:any" ++ quotabytes = getBytes(username, network) ++ print "User: %s has used %s of %s bytes for network: %s" % (username, actualbytes, quotabytes , network) ++ if int(actualbytes) > int(quotabytes): ++ print "%s is over the limit by %d bytes" % (username, (int(actualbytes) - int(quotabytes))) ++ applyRateLimiting(username) ++ else: ++ removeRateLimiting(username) ++ ++ ++def applyRateLimiting(username): ++ if (isRateLimited(username)): ++ print "User: %s already rate limited" % (username) ++ return True ++ print "Rate limiting user: %s (%s)" % (username, getUid(username)) ++ uid = (getUid(username)) ++ print "CMD: " + tcapplycmd % (uid, int(uid)) ++ subprocess.Popen(tcapplycmd % (uid, int(uid)), shell=True) ++ return True ++ ++def removeRateLimiting(username): ++ if (isRateLimited(username)): ++ print "removing quota for: " + username ++ uid = (getUid(username)) ++ print "CMD: " + tcremovecmd % (uid, int(uid)) ++ subprocess.Popen(tcremovecmd % (uid, int(uid)), shell=True) ++ return True ++ return False ++ ++def isRateLimited(username): ++ print "Checking if user: %s (%s) is rate limited" % (username, getUid(username)) ++ # python regex ++ p = re.compile('filter parent 1: protocol ip pref 1 fw handle 0x([0-9A-Fa-f]+) classid 1:[0-9A-Fa-f]+') ++ for r in tcrules: ++# print "rule: " + r ++ m = p.match(r) ++ if m: ++ uid = int(m.groups()[0], 16) ++# print "match found" + str(uid) ++# print "uid from username" + getUid(username) ++ if uid == int(getUid(username)): ++ print "matching rule found " + r ++ return True ++ return False ++# connect to ldap ++l = ldap.initialize(uri) ++res = l.search_s(base, scope, filterstr, attrlist) ++print "\nLDAP Search results" ++for dn, record in res: ++ if "networkquota" in record: ++# print "Processing: " + repr(dn) ++ print "%-15s: %s" % (record["uid"], record["networkquota"]) ++# print repr(record) ++l.unbind() ++ ++ ++# do this only once, instead of every time function is called. Read existing TC rules. ++tcproc = subprocess.Popen(tcfilterlist, shell=True, stdout=subprocess.PIPE) ++tcrules = tcproc.communicate()[0].split("\n") ++ ++# connect to Mysql ++db = MySQLdb.connect(passwd="passwd", db="nufw", host="laptop", user="root", port=13306) ++c = db.cursor(MySQLdb.cursors.DictCursor) ++ ++#query = """select bytes_in + bytes_out as bytes, username from ++#ulog where username is not null and bytes_in is not null and bytes_out is not null;""" ++ ++c.execute(query) ++print "\nMysql Results:" ++results = c.fetchall() ++for x in results: ++ print "%(username)-15s: %(bytes)s\n" % x ++ processNetworkQuotas(x["username"], x["bytes"]) +diff -Naur mmc-agent-2.3.2.orig/contrib/userquota/networkquota_example/setup.txt mmc-agent-2.3.2/contrib/userquota/networkquota_example/setup.txt +--- mmc-agent-2.3.2.orig/contrib/userquota/networkquota_example/setup.txt 1970-01-01 00:00:00.000000000 +0000 ++++ mmc-agent-2.3.2/contrib/userquota/networkquota_example/setup.txt 2010-02-04 01:50:02.000000000 +0000 +@@ -0,0 +1,10 @@ ++# remove the existing classless qdisc ++tc qdisc del dev eth1 root ++ ++# print status ++tc -s qdisc ls dev eth1 ++ ++# add new root qdisc ++tc qdisc add dev eth1 root handle 1: htb default 1 ++ ++ +diff -Naur mmc-agent-2.3.2.orig/contrib/userquota/networkquota_example/tcruleadd.sh mmc-agent-2.3.2/contrib/userquota/networkquota_example/tcruleadd.sh +--- mmc-agent-2.3.2.orig/contrib/userquota/networkquota_example/tcruleadd.sh 1970-01-01 00:00:00.000000000 +0000 ++++ mmc-agent-2.3.2/contrib/userquota/networkquota_example/tcruleadd.sh 2010-02-04 01:59:10.000000000 +0000 +@@ -0,0 +1,10 @@ ++#!/bin/bash ++# (c) 2009 Open Systems Specilists - Glen Ogilvie. License: GPL ++# Examle apply shell script ++USERID=$1 ++# class id is Userid in hex. ++CLASSID=$2 ++RATE="20kbps burst 5k" ++tc class add dev eth1 parent 1: classid 1:$CLASSID htb rate $RATE ++tc qdisc add dev eth1 parent 1:$CLASSID handle $CLASSID: sfq perturb 10 ++tc filter add dev eth1 parent 1: protocol ip prio 1 handle $USERID fw flowid 1:$CLASSID +diff -Naur mmc-agent-2.3.2.orig/contrib/userquota/networkquota_example/tcruledel.sh mmc-agent-2.3.2/contrib/userquota/networkquota_example/tcruledel.sh +--- mmc-agent-2.3.2.orig/contrib/userquota/networkquota_example/tcruledel.sh 1970-01-01 00:00:00.000000000 +0000 ++++ mmc-agent-2.3.2/contrib/userquota/networkquota_example/tcruledel.sh 2010-02-04 01:58:59.000000000 +0000 +@@ -0,0 +1,11 @@ ++#!/bin/bash ++# (c) 2009 Open Systems Specilists - Glen Ogilvie. License: GPL ++# Examle remove shell script ++USERID=$1 ++# class id is Userid in hex. ++CLASSID=$2 ++RATE="20kbps burst 5k" ++tc filter del dev eth1 parent 1: protocol ip prio 1 handle $USERID fw flowid 1:$CLASSID ++tc qdisc del dev eth1 parent 1:$CLASSID handle $CLASSID: sfq perturb 10 ++tc class del dev eth1 parent 1: classid 1:$CLASSID htb rate $RATE ++ +diff -Naur mmc-agent-2.3.2.orig/mmc/plugins/base/__init__.py mmc-agent-2.3.2/mmc/plugins/base/__init__.py +--- mmc-agent-2.3.2.orig/mmc/plugins/base/__init__.py 2010-02-05 18:08:26.095049411 +0000 ++++ mmc-agent-2.3.2/mmc/plugins/base/__init__.py 2010-02-05 18:14:08.567292865 +0000 +@@ -665,9 +665,8 @@ + if self.config.has_section(USERDEFAULT): + for option in self.config.options(USERDEFAULT): + self.userDefault["base"][option] = self.config.get(USERDEFAULT, option) +- +- self.l = ldap.open(self.ldapHost) +- ++# self.l = ldap.open(self.ldapHost) ++ self.l = ldap.ldapobject.ReconnectLDAPObject("ldap://%s:389" % self.ldapHost, retry_max=5, retry_delay=10) + # you should set this to ldap.VERSION2 if you're using a v2 directory + self.l.protocol_version = ldap.VERSION3 + +@@ -715,7 +714,7 @@ + new = old.copy() + new["loginShell"] = "/bin/bash" # FIXME: should not be hardcoded but put in a conf file + modlist = ldap.modlist.modifyModlist(old, new) +- self.l.modify_s(dn, modlist) ++ self.l.modify_ext_s(dn, modlist) + return 0 + + def disableUser(self, login): +@@ -731,7 +730,7 @@ + new = old.copy() + new["loginShell"] = "/bin/false" # FIXME: should not be hardcoded but put in a conf file + modlist = ldap.modlist.modifyModlist(old, new) +- self.l.modify_s(dn, modlist) ++ self.l.modify_ext_s(dn, modlist) + return 0 + + def isEnabled(self, login): +@@ -983,7 +982,7 @@ + cngroup = cngroup.encode("utf-8") + uiduser = uiduser.encode("utf-8") + try: +- self.l.modify_s('cn=' + cngroup + ',' + self.baseGroupsDN, [(ldap.MOD_DELETE, 'memberUid', uiduser)]) ++ self.l.modify_ext_s('cn=' + cngroup + ',' + self.baseGroupsDN, [(ldap.MOD_DELETE, 'memberUid', uiduser)]) + except ldap.NO_SUCH_ATTRIBUTE: + # There are no member in this group + pass +@@ -1086,7 +1085,7 @@ + cngroup = cngroup.encode("utf-8") + uiduser = uiduser.encode("utf-8") + try: +- self.l.modify_s('cn=' + cngroup + ',' + base, [(ldap.MOD_ADD, 'memberUid', uiduser)]) ++ self.l.modify_ext_s('cn=' + cngroup + ',' + base, [(ldap.MOD_ADD, 'memberUid', uiduser)]) + except ldap.TYPE_OR_VALUE_EXISTS: + # Try to add a the user to one of his/her group + # Can be safely ignored +@@ -1113,11 +1112,11 @@ + elif isinstance(attrVal, xmlrpclib.Binary): + # Needed for binary string coming from XMLRPC + attrVal = str(attrVal) +- self.l.modify_s('uid='+uid+','+ self.baseUsersDN, [(ldap.MOD_REPLACE,attr,attrVal)]) ++ self.l.modify_ext_s('uid='+uid+','+ self.baseUsersDN, [(ldap.MOD_REPLACE,attr,attrVal)]) + else: + # Remove the attribute because its value is empty + try: +- self.l.modify_s('uid='+uid+','+ self.baseUsersDN, [(ldap.MOD_DELETE,attr, None)]) ++ self.l.modify_ext_s('uid='+uid+','+ self.baseUsersDN, [(ldap.MOD_DELETE,attr, None)]) + except ldap.NO_SUCH_ATTRIBUTE: + # The attribute has been already deleted + pass +@@ -1138,10 +1137,10 @@ + group = group.encode("utf-8") + if attrVal: + attrVal = str(attrVal.encode("utf-8")) +- self.l.modify_s('cn=' + group + ','+ self.baseGroupsDN, [(ldap.MOD_REPLACE,attr,attrVal)]) ++ self.l.modify_ext_s('cn=' + group + ','+ self.baseGroupsDN, [(ldap.MOD_REPLACE,attr,attrVal)]) + else: +- self.l.modify_s('cn=' + group + ','+ self.baseGroupsDN, [(ldap.MOD_REPLACE,attr,'rien')]) +- self.l.modify_s('cn=' + group + ','+ self.baseGroupsDN, [(ldap.MOD_DELETE,attr,'rien')]) ++ self.l.modify_ext_s('cn=' + group + ','+ self.baseGroupsDN, [(ldap.MOD_REPLACE,attr,'rien')]) ++ self.l.modify_ext_s('cn=' + group + ','+ self.baseGroupsDN, [(ldap.MOD_DELETE,attr,'rien')]) + return 0 + + def changeUserPasswd(self, uid, passwd): +@@ -1158,7 +1157,7 @@ + self.l.passwd_s('uid=' + uid + ',' + self.baseUsersDN, None, str(passwd)) + else: + userpassword = self._generatePassword(passwd) +- self.l.modify_s('uid=' + uid + ',' + self.baseUsersDN, [(ldap.MOD_REPLACE, "userPassword", userpassword)]) ++ self.l.modify_ext_s('uid=' + uid + ',' + self.baseUsersDN, [(ldap.MOD_REPLACE, "userPassword", userpassword)]) + # Run ChangeUserPassword hook + self.runHook("base.changeuserpassword", uid, passwd) + +@@ -1628,7 +1627,7 @@ + + # Apply modification + mlist = ldap.modlist.modifyModlist(attrs, newattrs) +- self.l.modify_s(cn, mlist) ++ self.l.modify_ext_s(cn, mlist) + + def removeGroupObjectClass(self, group, className): + # Create LDAP path +@@ -1654,7 +1653,7 @@ + + # Apply modification + mlist = ldap.modlist.modifyModlist(attrs, newattrs) +- self.l.modify_s(cn, mlist) ++ self.l.modify_ext_s(cn, mlist) + + def getAttrToDelete(self, dn, className): + """retrieve all attributes to delete wich correspond to param schema""" +@@ -1921,7 +1920,7 @@ + """ + dn = "uid=" + uid + "," + self.l.baseUsersDN + try: +- self.l.l.modify_s( self._getGpoDN(gpoName), [(ldap.MOD_ADD, 'member', dn)]) ++ self.l.l.modify_ext_s( self._getGpoDN(gpoName), [(ldap.MOD_ADD, 'member', dn)]) + except ldap.TYPE_OR_VALUE_EXISTS: + # Value already set + pass +@@ -1935,7 +1934,7 @@ + """ + dn = "uid=" + uid + "," + self.l.baseUsersDN + try: +- self.l.l.modify_s(self._getGpoDN(gpoName), [(ldap.MOD_DELETE, 'member', dn)]) ++ self.l.l.modify_ext_s(self._getGpoDN(gpoName), [(ldap.MOD_DELETE, 'member', dn)]) + except ldap.NO_SUCH_ATTRIBUTE: + # Value already deleted + pass +@@ -1969,7 +1968,7 @@ + """ + dn = "cn=" + group + "," + self.l.baseGroupsDN + try: +- self.l.l.modify_s( self._getGpoDN(gpoName), [(ldap.MOD_ADD, 'member', dn)]) ++ self.l.l.modify_ext_s( self._getGpoDN(gpoName), [(ldap.MOD_ADD, 'member', dn)]) + except ldap.TYPE_OR_VALUE_EXISTS: + # Value already set + pass +@@ -1983,7 +1982,7 @@ + """ + dn = "cn=" + group + "," + self.l.baseGroupsDN + try: +- self.l.l.modify_s(self._getGpoDN(gpoName), [(ldap.MOD_DELETE, 'member', dn)]) ++ self.l.l.modify_ext_s(self._getGpoDN(gpoName), [(ldap.MOD_DELETE, 'member', dn)]) + except ldap.NO_SUCH_ATTRIBUTE: + # Value already deleted + pass +diff -Naur mmc-agent-2.3.2.orig/mmc/plugins/userquota/__init__.py mmc-agent-2.3.2/mmc/plugins/userquota/__init__.py +--- mmc-agent-2.3.2.orig/mmc/plugins/userquota/__init__.py 1970-01-01 00:00:00.000000000 +0000 ++++ mmc-agent-2.3.2/mmc/plugins/userquota/__init__.py 2010-02-04 00:06:51.000000000 +0000 +@@ -0,0 +1,602 @@ ++# -*- coding: utf-8; -*- ++# (c) 2009 Open Systems Specilists - Glen Ogilvie ++# ++# $Id: __init__.py $ ++# ++# This file is a plugin for Mandriva Management Console (MMC). ++# ++# MMC 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. ++# ++# MMC 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 MMC; if not, write to the Free Software ++# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA ++ ++import socket ++import ldap ++import logging ++import os ++import os.path ++import grp ++import tempfile ++ ++from mmc.plugins.base import ldapUserGroupControl ++from mmc.support.config import * ++from mmc.support import mmctools ++from string import Template ++ ++ ++import mmc ++ ++INI = "/etc/mmc/plugins/userquota.ini" ++ ++VERSION = "0.0.3" ++APIVERSION = "1:0:0" ++REVISION = int("$Rev: 1 $".split(':')[1].strip(' $')) ++ ++def getVersion(): return VERSION ++def getApiVersion(): return APIVERSION ++def getRevision(): return REVISION ++ ++ ++def activate(): ++ return True ++ ++def getActiveComponents(): ++ return UserQuotaControl().getActiveComponents() ++ ++def getDevicemap(): ++ return UserQuotaControl().getDevicemap() ++ ++def getNetworkmap(): ++ return UserQuotaControl().getNetworkmap() ++ ++def setDiskQuota(uid, device, quota): ++ return UserQuotaControl().setDiskQuota(uid, device, quota) ++ ++def setNetworkQuota(uid, network, quota): ++ return UserQuotaControl().setNetworkQuota(uid, network, quota) ++ ++def setGroupDiskQuota(group, device, quota, overwrite): ++ return UserQuotaControl().setGroupDiskQuota(group, device, quota, overwrite) ++ ++def deleteGroupDiskQuota(cn, device): ++ return UserQuotaControl().deleteGroupDiskQuotas(cn, device) ++ ++def setGroupNetworkQuota(group, network, quota, overwrite): ++ return UserQuotaControl().setGroupNetworkQuota(group, network, quota, overwrite) ++ ++def deleteGroupNetworkQuota(cn, device): ++ return UserQuotaControl().deleteGroupNetworkQuotas(cn, device) ++ ++ ++def deleteDiskQuota(uid, device): ++ return UserQuotaControl().deleteDiskQuota(uid, device) ++ ++def deleteNetworkQuota(uid, network): ++ return UserQuotaControl().deleteNetworkQuota(uid, network) ++ ++def setUserQuotaDefaults(user, group): ++ return UserQuotaControl().setUserQuotaDefaults(user, group) ++ ++class UserQuotaConfig(PluginConfig): ++ ++ def readConf(self): ++ PluginConfig.readConf(self) ++ try: self.diskquotaenable = self.getboolean("diskquota", "enable") ++ except: pass ++ try: self.networkquotaenable = self.getboolean("networkquota", "enable") ++ except: pass ++ self.devicemap = self.get("diskquota", "devicemap").split(',') ++ self.inodesperblock = self.getfloat("diskquota", "inodesperblock") ++ self.softquotablocks = self.getfloat("diskquota", "softquotablocks") ++ self.softquotainodes = self.getfloat("diskquota", "softquotainodes") ++ self.setquotascript = self.get("diskquota", "setquotascript") ++ self.delquotascript = self.get("diskquota", "delquotascript") ++ self.networkmap = self.get("networkquota", "networkmap").split(',') ++ ++ def setDefault(self): ++ PluginConfig.setDefault(self) ++ self.diskquotaenable = True ++ self.networkquotaenable = False ++ ++ ++class UserQuotaControl(ldapUserGroupControl): ++ def __init__(self, conffile=None, conffilebase=None): ++ mmc.plugins.base.ldapUserGroupControl.__init__(self, conffilebase) ++ self.configuserquota = UserQuotaConfig("userquota", conffile) ++ self.tempfilename = False ++ self.tempdelfilename = False ++ def getDevicemap(self): ++ return self.configuserquota.devicemap ++ def getNetworkmap(self): ++ return self.configuserquota.networkmap ++ def getActiveComponents(self): ++ return ({"disk":self.configuserquota.diskquotaenable, "network":self.configuserquota.networkquotaenable}) ++ ++ def deleteNetworkQuota(self, uid, network): ++ logger = logging.getLogger() ++ try: ++ currentquotas = self.getDetailedUser(uid)["networkquota"] ++ newquotas = [] ++ for x in currentquotas: ++ if not x.split(',')[0] == network: ++ newquotas.append(x) ++ ++ if len(newquotas) == 0: ++ self.changeUserAttributes(uid, 'networkquota', None) ++ self.delQuotaObjectClass(uid) ++ ++ else: ++ self.changeUserAttributes(uid, 'networkquota', newquotas) ++ ++ except KeyError: ++ pass ++ return True ++ ++ def deleteDiskQuota(self, uid, device, single=True): ++ logger = logging.getLogger() ++# logger.info("Deleting quota for: "+ uid) ++ devicepath = device.split(':')[0] ++ try: ++ currentquotas = self.getDetailedUser(uid)["quota"] ++ newquotas = [] ++ for x in currentquotas: ++ if not x.split('=')[0] == devicepath: ++ newquotas.append(x) ++ ++ if len(newquotas) == 0: ++ self.changeUserAttributes(uid, 'quota', None) ++ self.delQuotaObjectClass(uid) ++ ++ else: ++ self.changeUserAttributes(uid, 'quota', newquotas) ++ ++ self.appendDeleteQuotatasks(uid, devicepath) ++ if single: ++ logger.info("Delete Single quota") ++ self.deleteQuotaOnFS(); ++ ++ except KeyError: ++ pass ++ ++ return True ++ ++ ++ def setNetworkQuota(self, uid, network, quota, overwrite = "all"): ++ logger = logging.getLogger() ++ ldapquota = '%s,%s' % (network, str(int(quota) * 1048576)) ++ logger.info("Network Quota:" + ldapquota) ++ ++ if not self.hasDiskQuotaObjectClass(uid): ++ self.addDiskQuotaObjectClass(uid) ++ # @todo, fix copy from disk quotas. ++ try: ++ userdetails = self.getDetailedUser(uid) ++ currentquotas = userdetails["networkquota"] ++ newquotas = [] ++ quotachanged = False ++ for x in currentquotas: ++ if x.split(',')[0] == network: ++ logger.info("Current network quota sizes: " + str(self.convertNetworkQuotaToMB(x))) ++ logger.info("Requested quota size: " + quota) ++ logger.info("Overwrite mode: " + overwrite) ++ if (overwrite == "none"): ++ logger.info('No overwrite mode set. so not overwriting.') ++ return False ++ if overwrite == "smaller" and self.convertNetworkQuotaToMB(x) > int(quota): ++ logger.info('Current network quota is bigger than new quota, so not overwriting') ++ return False ++ if overwrite == "larger" and int(quota) > self.convertNetworkQuotaToMB(x): ++ logger.info('Current network quota is smaller than new quota, so not overwriting') ++ return False ++ newquotas.append(ldapquota) ++ quotachanged = True ++ else: ++ newquotas.append(x) ++ ++ if not quotachanged: ++ newquotas.append(ldapquota) ++ ++ self.changeUserAttributes(uid, 'networkquota', newquotas) ++ except KeyError: ++ self.changeUserAttributes(uid, 'networkquota', ldapquota) ++ pass ++ ++ return True ++ ++ def setDiskQuota(self, uid, device, quota, overwrite = "all",single = True): ++ logger = logging.getLogger() ++ logger.info("received quota for " + uid + ", device: " + device + ", size: " + quota) ++ blocks = self.convertMBtoBlocks(quota, device); ++ softblocks = int (blocks * self.configuserquota.softquotablocks) ++ inodes = int(blocks * self.configuserquota.inodesperblock) ++ softinodes = int(inodes * self.configuserquota.softquotainodes) ++ devicepath = device.split(':')[0] ++# logger.info("Devicepath: " + devicepath) ++# logger.info("Blocks: " + str(blocks)) ++# logger.info("Soft Blocks: " + str(softblocks)) ++# logger.info("Inodes: " + str(inodes)) ++# logger.info("Soft Inodes: " + str(softinodes)) ++ ldapquota = '%s=%s:%s:%s:%s' % (devicepath, str(blocks), str(softblocks), str(inodes), str(softinodes)) ++ logger.info("Quota for: " + uid + " - " + ldapquota) ++ ++ if not self.hasDiskQuotaObjectClass(uid): ++ self.addDiskQuotaObjectClass(uid) ++ try: ++ userdetails = self.getDetailedUser(uid) ++ currentquotas = userdetails["quota"] ++ newquotas = [] ++ quotachanged = False ++ for x in currentquotas: ++ if x.split('=')[0] == devicepath: ++ logger.info("Current network quota sizes: " + str(self.convertDiskQuotaToMB(x))) ++ logger.info("Requested quota size: " + quota) ++ logger.info("Overwrite mode: " + overwrite) ++ if overwrite == "none": ++ return False ++ if overwrite == "smaller" and self.convertDiskQuotaToMB(x) > int(quota): ++ logger.info('Current quota is bigger than new quota, so not overwriting') ++ return False ++ if overwrite == "larger" and int(quota) > self.convertDiskQuotaToMB(x): ++ logger.info('Current quota is smaller than new quota, so not overwriting') ++ return False ++ ++ newquotas.append(ldapquota) ++ quotachanged = True ++ else: ++ newquotas.append(x) ++ ++ if not quotachanged: ++ newquotas.append(ldapquota) ++ self.changeUserAttributes(uid, 'quota', newquotas) ++ except KeyError: ++ self.changeUserAttributes(uid, 'quota', ldapquota) ++ pass ++ ++ self.appendQuotatasks(uid, blocks, softblocks, inodes, softinodes, devicepath) ++ if single: ++ self.applyQuotaToFS() ++ ++ return True ++ ++ def appendQuotatasks(self, uid, blocks, softblocks, inodes, softinodes, devicepath): ++ logger = logging.getLogger() ++ if not self.tempfilename: ++ self.tempfilename = tempfile.mktemp() ++ logger.info("Temp file: %s" % (self.tempfilename)) ++ ++ ++ s = Template(self.configuserquota.setquotascript) ++ shellscript = s.substitute(uid=uid, blocks=blocks, softblocks=softblocks, inodes=inodes, softinodes=softinodes, devicepath=devicepath) ++ logger.info("Append SetQuotaScript: " + shellscript); ++ f = open(self.tempfilename, 'a') ++ f.write("%s\n" % (shellscript)) ++ f.close ++ ++ ++ def applyQuotaToFS(self): ++ if not self.tempfilename: ++ return ++ logger = logging.getLogger() ++ shellscript = "/bin/sh %s" % (self.tempfilename) ++ logger.info("ApplyQuotas: " + shellscript); ++ def cb(shprocess): ++ # The callback just return the process outputs ++ # ++ if shprocess.exitCode != 0: ++ logger.error("Error applying quotas: " + shprocess.err) ++ logger.info("shell result:" + shprocess.out) ++ logger.error("See: " + self.tempfilename + " for details of the commands run") ++ else: ++ os.remove(self.tempfilename) ++ ++ self.tempfilename = False ++ return shprocess.exitCode, shprocess.out, shprocess.err ++ ++ d = mmctools.shLaunchDeferred(shellscript) ++ # shLaunchDeferred returns a Deferred() object ++ # We add the cb function as a callback ++ d.addCallback(cb) ++ # We return the Deferred() object ++ return d ++ ++ def appendDeleteQuotatasks(self, uid, devicepath): ++ logger = logging.getLogger() ++ if not self.tempdelfilename: ++ self.tempdelfilename = tempfile.mktemp() ++ logger.info("Temp file: %s" % (self.tempdelfilename)) ++ ++ s = Template(self.configuserquota.delquotascript) ++ shellscript = s.substitute(uid=uid, devicepath=devicepath) ++ logger.info("Append DelQuotaScript: " + shellscript); ++ f = open(self.tempdelfilename, 'a') ++ f.write("%s\n" % (shellscript)) ++ f.close ++ ++ ++ def deleteQuotaOnFS(self): ++ if not self.tempdelfilename: ++ return ++ logger = logging.getLogger() ++ shellscript = "/bin/sh %s" % (self.tempdelfilename) ++ logger.info("DelQuotaScript: " + shellscript); ++ def cb(shprocess): ++ # The callback just return the process outputs ++ if shprocess.exitCode != 0: ++ logger.error("Error applying del quotas: " + shprocess.err) ++ logger.info("shell result:" + shprocess.out) ++ logger.error("See: " + self.tempfilename + " for details of the commands run") ++ else: ++ os.remove(self.tempdelfilename) ++ ++ self.tempdelfilename = False ++ return shprocess.exitCode, shprocess.out, shprocess.err ++ d = mmctools.shLaunchDeferred(shellscript) ++ # shLaunchDeferred returns a Deferred() object ++ # We add the cb function as a callback ++ d.addCallback(cb) ++ # We return the Deferred() object ++ return d ++ ++ def convertMBtoBlocks(self, quota, device): ++ parts = device.split(':') ++ blocks = int(parts[1]) ++ bytes = int(quota) * 1048576 ++ return int(bytes / blocks) ++ ++ def convertNetworkQuotaToMB(self, quota): ++ return int(quota.split(',')[1])/1048576 ++ ++ def convertDiskQuotaToMB(self,quota): ++ devicemap = self.getDevicemap() ++ devicepath = quota.split('=')[0] ++ for x in devicemap: ++ if x.split(':')[0] == devicepath: ++ return int(quota.split('=')[1].split(":")[0]) * int(x.split(':')[1]) / 1048576 ++ return False ++ ++ ++ def hasDiskQuotaObjectClass(self, uid): ++ """ ++ Return true if the user owns the systemQuotas objectClass. ++ ++ @param uid: user name ++ @type uid: str ++ ++ @return: return True if the user owns the mailAccount objectClass. ++ @rtype: boolean ++ """ ++ return "systemQuotas" in self.getDetailedUser(uid)["objectClass"] ++ ++ def delQuotaObjectClass(self, uid): ++ """ ++ Return true if the objectClass is removed. ++ ++ @return: return True if the object class is able to be removed ++ @rtype: boolean ++ """ ++ logger = logging.getLogger() ++ user = self.getDetailedUser(uid) ++ logger.info("Del object class") ++ ++ if "quota" in user.keys() or "networkquota" in user.keys(): ++ return False ++ ++ logger.info("Del object class removal") ++ if "systemQuotas" in user["objectClass"]: ++ user["objectClass"].remove("systemQuotas") ++ self.changeUserAttributes(uid, 'objectClass', user["objectClass"]) ++ return True ++ return False ++ ++ def delGroupQuotaObjectClass(self, cn): ++ """ ++ Return true if the objectClass is removed. ++ ++ @return: return True if the object class is able to be removed ++ @rtype: boolean ++ """ ++ logger = logging.getLogger() ++ group = self.getDetailedGroup(cn) ++ logger.info("Del Group object class") ++ logger.info("group keys" + str(group.keys())) ++ if "quota" in group.keys() or "networkquota" in group.keys(): ++ return False ++ ++ logger.info("Del object class removal") ++ if "defaultQuotas" in group["objectClass"]: ++ group["objectClass"].remove("defaultQuotas") ++ logger.info("ObjectClass to save:" + str( group["objectClass"]) ) ++ self.changeGroupAttribute(cn, 'objectClass', group["objectClass"]) ++ return True ++ return False ++ ++ def addDiskQuotaObjectClass(self, uid): ++ user = self.getDetailedUser(uid)['objectClass'] ++ if not "systemQuotas" in user: ++ user.append("systemQuotas") ++ self.l.modify_ext_s('uid=' + uid + ',' + self.baseUsersDN, [(ldap.MOD_REPLACE, 'objectClass', user)]) ++ return True ++ ++ ++ def setGroupDiskQuota(self, group, device, quota, overwrite): ++ logger = logging.getLogger() ++ logger.info("SetGroupDiskQuota: Overwrite mode: " + overwrite) ++ logger.info("ldap timeout:" + str(self.l.timeout)) ++ self.l.set_option(ldap.OPT_NETWORK_TIMEOUT, 100) ++ logger.info("ldap network timeout:" + str(self.l.get_option(ldap.OPT_NETWORK_TIMEOUT))) ++ ++ ++ self.addGroupDefaultDiskQuotaObjectClass(group) ++ ++ blocks = self.convertMBtoBlocks(quota, device); ++ softblocks = int (blocks * self.configuserquota.softquotablocks) ++ inodes = int(blocks * self.configuserquota.inodesperblock) ++ softinodes = int(inodes * self.configuserquota.softquotainodes) ++ devicepath = device.split(':')[0] ++ ldapquota = '%s=%s:%s:%s:%s' % (devicepath, str(blocks), str(softblocks), str(inodes), str(softinodes)) ++ # @todo improve this, it's a copy of set disk quota. ++ try: ++ currentquotas = self.getDetailedGroup(group)["quota"] ++ newquotas = [] ++ quotachanged = False ++ for x in currentquotas: ++ if x.split('=')[0] == devicepath: ++ newquotas.append(ldapquota) ++ quotachanged = True ++ else: ++ newquotas.append(x) ++ ++ if not quotachanged: ++ newquotas.append(ldapquota) ++ ++ self.changeGroupAttribute(group, "quota", newquotas) ++ ++ except KeyError: ++ self.changeGroupAttribute(group, "quota", ldapquota) ++ pass ++ ++ ++ for uid in self.getMembers(group): ++ self.setDiskQuota(uid, device, quota, overwrite, single=False) ++ ++ # apply the group quotas to FS. ++ self.applyQuotaToFS() ++ ++ ++ return True ++ ++ def setGroupNetworkQuota(self, group, network, quota, overwrite): ++ logger = logging.getLogger() ++ logger.info("SetGroupNetworkQuota Overwrite mode: " + overwrite) ++ self.addGroupDefaultDiskQuotaObjectClass(group) ++ ldapquota = '%s,%s' % (network, str(int(quota) * 1048576)) ++ # @todo improve this, it's a copy of set disk quota. ++ try: ++ currentquotas = self.getDetailedGroup(group)["networkquota"] ++ newquotas = [] ++ quotachanged = False ++ for x in currentquotas: ++ if x.split(',')[0] == network: ++ newquotas.append(ldapquota) ++ quotachanged = True ++ else: ++ newquotas.append(x) ++ ++ if not quotachanged: ++ newquotas.append(ldapquota) ++ ++ self.changeGroupAttribute(group, "networkquota", newquotas) ++ ++ except KeyError: ++ self.changeGroupAttribute(group, "networkquota", ldapquota) ++ pass ++ ++ for uid in self.getMembers(group): ++ self.setNetworkQuota(uid, network, quota, overwrite) ++ return True ++ ++ def setUserQuotaDefaults(self, uid, group): ++ # @todo: unfinished, does nothing yet. ++ logger = logging.getLogger() ++ logger.info("Set user quota defaults: user: " + uid + " group: " + group) ++ keys = [] ++ # don't set the quota if one has been set before. ++ logger.info(self.getDetailedUser(uid)["objectClass"]) ++ logger.info("Value of: self.hasDiskQuotaObjectClass(uid)" + str(self.hasDiskQuotaObjectClass(uid))) ++ if self.hasDiskQuotaObjectClass(uid): ++ logger.info("User already has quota Object class") ++ return keys ++ ++ groupdefaults = self.getDetailedGroup(group) ++ ++ # @todo, check components before action ++ if "quota" in groupdefaults.keys(): ++ # copy quota values to user ++ logger.info("copy quota values to user:" + uid) ++ self.addDiskQuotaObjectClass(uid) ++ self.changeUserAttributes(uid, "quota", groupdefaults["quota"]) ++ keys.append('quota') ++ ++ if "networkquota" in groupdefaults.keys(): ++ # copy networkquota values to user ++ logger.info("copy network quota values to user:" + uid) ++ self.addDiskQuotaObjectClass(uid) ++ self.changeUserAttributes(uid, "networkquota", groupdefaults["networkquota"]) ++ keys.append('networkquota') ++ ++ return keys ++ ++ def addGroupDefaultDiskQuotaObjectClass(self, cn): ++ group = self.getDetailedGroup(cn)['objectClass'] ++ if not "defaultQuotas" in group: ++ group.append("defaultQuotas") ++ self.changeGroupAttribute(cn, 'objectClass', group) ++ return True ++ ++ def changeGroupAttribute(self, cn, attr, attrval): ++ self.l.modify_ext_s('cn=' + cn + ',' + self.baseGroupsDN, [(ldap.MOD_REPLACE, attr, attrval)]) ++ ++ def deleteGroupDiskQuotas(self, cn, device): ++ logger = logging.getLogger() ++ devicepath = device.split(':')[0] ++ logger.info("Delete quotas for members of:" + cn) ++ logger.info("ldap timeout:" + str(self.l.timeout)) ++ self.l.set_option(ldap.OPT_NETWORK_TIMEOUT, 100) ++ logger.info("ldap network timeout:" + str(self.l.get_option(ldap.OPT_NETWORK_TIMEOUT))) ++ ++ ++ for uid in self.getMembers(cn): ++ self.deleteDiskQuota(uid, device, single=False) ++ ++ self.deleteQuotaOnFS(); ++ ++ try: ++ currentquotas = self.getDetailedGroup(cn)["quota"] ++ newquotas = [] ++ for x in currentquotas: ++ if not x.split('=')[0] == devicepath: ++ newquotas.append(x) ++ ++ if len(newquotas) == 0: ++ self.changeGroupAttribute(cn, 'quota', None) ++ self.delGroupQuotaObjectClass(cn) ++ else: ++ self.changeGroupAttribute(cn, 'quota', newquotas) ++ ++ except KeyError: ++ pass ++ ++ return True ++ ++ def deleteGroupNetworkQuotas(self, cn, network): ++ logger = logging.getLogger() ++ logger.info("Delete networkquotas for members of: " + cn) ++ for uid in self.getMembers(cn): ++ self.deleteNetworkQuota(uid, network) ++ try: ++ currentquotas = self.getDetailedGroup(cn)["networkquota"] ++ newquotas = [] ++ ++ for x in currentquotas: ++ if not x.split(',')[0] == network: ++ newquotas.append(x) ++ ++ if len(newquotas) == 0: ++ self.changeGroupAttribute(cn, 'networkquota', None) ++ self.delGroupQuotaObjectClass(cn) ++ else: ++ self.changeGroupAttribute(cn, 'networkquota', newquotas) ++ ++ except KeyError: ++ pass ++ return True ++ +diff -Naur mmc-agent-2.3.2.orig/setup.py mmc-agent-2.3.2/setup.py +--- mmc-agent-2.3.2.orig/setup.py 2010-02-05 18:08:41.170067138 +0000 ++++ mmc-agent-2.3.2/setup.py 2010-02-05 18:09:35.879049358 +0000 +@@ -8,5 +8,5 @@ + author_email = "cdelfosse@mandriva.com", + maintainer = "Cedric Delfosse", + maintainer_email = "cdelfosse@mandriva.com", +- packages = ["mmc", "mmc.support", "mmc.plugins", "mmc.plugins.base", "mmc.plugins.samba", "mmc.plugins.proxy", "mmc.plugins.mail", "mmc.plugins.network", "mmc.plugins.kerberos", "mmc.plugins.printstats", "mmc.plugins.printing"], ++ packages = ["mmc", "mmc.support", "mmc.plugins", "mmc.plugins.base", "mmc.plugins.samba", "mmc.plugins.proxy", "mmc.plugins.mail", "mmc.plugins.network", "mmc.plugins.kerberos", "mmc.plugins.printstats", "mmc.plugins.printing", "mmc.plugins.userquota"], + ) diff --git a/app-admin/mmc-agent/mmc-agent-2.3.2_p798.ebuild b/app-admin/mmc-agent/mmc-agent-2.3.2_p798.ebuild index 546b45d..274a905 100644 --- a/app-admin/mmc-agent/mmc-agent-2.3.2_p798.ebuild +++ b/app-admin/mmc-agent/mmc-agent-2.3.2_p798.ebuild @@ -34,7 +34,7 @@ src_prepare() { epatch "${FILESDIR}"/${PN}-2.3.1-kerberos-1.patch epatch "${FILESDIR}"/${PN}-2.3.2-printing-1.patch epatch "${FILESDIR}"/${PN}-2.3.2-powerdns-2.patch - epatch "${FILESDIR}"/${PN}-2.3.2-userquota-1.patch + epatch "${FILESDIR}"/${PN}-2.3.2-userquota-2.patch epatch "${FILESDIR}"/${PN}-2.3.2-bulkimport-2.patch }