Add support for
authorEric Price <ecprice@mit.edu>
Wed, 10 Oct 2007 02:08:20 +0000 (22:08 -0400)
committerEric Price <ecprice@mit.edu>
Wed, 10 Oct 2007 02:08:20 +0000 (22:08 -0400)
(A) modifying VM names, memory, disksize
(B) transferring ownership, hostname

Has issues with multiple disks/nics because of current interface.

(tabbott is the real author here)

svn path=/trunk/web/; revision=161

templates/getafsgroups.py [new file with mode: 0644]
templates/info.tmpl
templates/main.py

diff --git a/templates/getafsgroups.py b/templates/getafsgroups.py
new file mode 100644 (file)
index 0000000..0567efe
--- /dev/null
@@ -0,0 +1,74 @@
+#!/usr/bin/python
+import pprint
+import subprocess
+
+# import ldap
+# l = ldap.open("W92-130-LDAP-2.mit.edu")
+# # ldap.mit.edu is 1/2 broken right now so we're going to the working backend
+# l.simple_bind_s("", "")
+
+# def getLdapGroups(user):
+#     """
+#     getLdapGroups(user): returns a generator for the list of LDAP groups containing user
+#     """
+#     for user_data in l.search_s("ou=affiliates,dc=mit,dc=edu", ldap.SCOPE_ONELEVEL, "uid=" + user, []):
+#         for group_data in l.search_s("ou=groups,dc=mit,dc=edu", ldap.SCOPE_ONELEVEL, "uniqueMember="+user_data[0], ['cn']):
+#             yield group_data[1]['cn'][0]
+
+# def checkLdapGroups(user, group):
+#     """
+#     checkLdapGroups(user, group): returns True if and only if user is in LDAP group group
+#     """
+#     for result_data in l.search_s("ou=affiliates,dc=mit,dc=edu", ldap.SCOPE_ONELEVEL, "uid=" + user, []):
+#         if l.search_s("ou=groups,dc=mit,dc=edu", ldap.SCOPE_ONELEVEL, "(&(cn=" + group + ")(uniqueMember="+result_data[0] + "))", []) != []:
+#             return True
+#     return False
+
+def checkAfsGroup(user, group, cell):
+    """
+    checkAfsGroup(user, group) returns True if and only if user is in AFS group group in cell cell
+    """
+    print user, group
+    p = subprocess.Popen(["pts", "membership", group, '-c', cell], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    p2 = subprocess.Popen(["grep", "-v", "^Members"], stdin=p.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    if p2.wait():
+        return False
+    for member in p2.stdout.read().split():
+        if member == user:
+            return True
+    return False
+
+def checkLockerOwner(user, locker):
+    """
+    checkLockerOwner(user, locker) returns True if and only if user administers locker
+    """
+    p = subprocess.Popen(["fs", "whichcell", "/mit/" + locker], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    if (p.wait()):
+        return False
+    cell = p.stdout.read().split()[-1][1:-1]
+    p = subprocess.Popen(["fs", "listacl", "/mit/" + locker], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    p2 = subprocess.Popen(["grep", "^  .* rlidwka$"], stdin=p.stdout, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
+    if (p2.wait()):
+        return False
+    for line in p2.stdout.read().split('\n'):
+        entry = line.split()
+        if entry == [] or entry[0] == "Negative":
+            break
+        if entry[1] == "rlidwka":
+            if entry[0] == user or (entry[0][0:6] == "system" and checkAfsGroup(user, entry[0], cell)):
+                return True
+    return False
+
+
+if __name__ == "__main__":
+#    print list(getldapgroups("tabbott"))
+    print checkAfsGroup("tabbott", "system:debathena", 'athena.mit.edu')
+    print checkAfsGroup("tabbott", "system:debathena", 'sipb.mit.edu')
+    print checkAfsGroup("tabbott", "system:debathena-root", 'athena.mit.edu')
+    print checkAfsGroup("tabbott", "system:hmmt-request", 'athena.mit.edu')
+    print checkLockerOwner("tabbott", "tabbott")
+    print checkLockerOwner("tabbott", "debathena")
+    print checkLockerOwner("tabbott", "sipb")
+    print checkLockerOwner("tabbott", "lsc")
+    print checkLockerOwner("tabbott", "scripts")
+    print checkLockerOwner("ecprice", "hmmt")
index ca98ff9..ca7d107 100644 (file)
@@ -62,10 +62,13 @@ Info on $machine.name
 <form action="modify" method="POST">
   <input type="hidden" name="machine_id" value="$machine.machine_id"/>
   <table>
-    <tr><td>Owner:</td><td><input type="text" name="owner", value="$machine.owner"/></td></tr>
+    <tr><td>Owner:</td><td><input type="text" name="owner", value="$machine.owner"/></td>
+       <td>NOTE: The Owner must the name of a locker that you administer</td></tr>
     <tr><td>Contact email:</td><td><input type="text" name="contact" value="$machine.contact"/></td></tr>
+    <tr><td>Machine Name:</td><td><input type="text" name="name" value="$machine.name"/></td></tr>
 #if $machine.nics
-    <tr><td>Hostname:</td><td><input type="text" name="hostname" value="$machine.nics[0].hostname"/>.servers.csail.mit.edu</td></tr>
+    <tr><td>Hostname:</td><td><input type="text" name="hostname" value="$machine.nics[0].hostname"/>.servers.csail.mit.edu</td>
+       <td>NOTE: The hostname must being with "Owner_".</td></tr>
 #end if
 #if not $on
     <tr><td>Ram:</td><td><input type="text" size=3 name="memory" value="$machine.memory"/>MB (max $max_mem)</td></tr>
index ccef044..e5dae26 100755 (executable)
@@ -13,6 +13,7 @@ import sha
 import hmac
 import datetime
 import StringIO
+import getafsgroups
 
 sys.stderr = StringIO.StringIO()
 sys.path.append('/home/ecprice/.local/lib/python2.5/site-packages')
@@ -117,7 +118,7 @@ def haveAccess(user, machine):
     """Return whether a user has access to a machine"""
     if user.username == 'moo':
         return True
-    return machine.owner == user.username
+    return getafsgroups.checkLockerOwner(user.username,machine.owner)
 
 def error(op, user, fields, err, emsg):
     """Print an error page when a CodeError occurs"""
@@ -567,7 +568,7 @@ def command(user, fields):
     return Template(file="command.tmpl", searchList=[d, global_dict])
 
 def testOwner(user, owner, machine=None):
-    if owner != user.username:
+    if not getafsgroups.checkLockerOwner(user.username, owner):
         raise InvalidInput('owner', owner,
                            "Invalid")
     return owner
@@ -578,10 +579,19 @@ def testContact(user, contact, machine=None):
                            "Invalid")
     return contact
 
+def testDisk(user, disksize, machine=None):
+    return disksize
+
+def testName(user, name, machine=None):
+    return name
+
 def testHostname(user, hostname, machine):
     for nic in machine.nics:
         if hostname == nic.hostname:
             return hostname
+    # check if doesn't already exist
+    if NIC.select_by(hostname=hostname) == []:
+        return hostname
     raise InvalidInput('hostname', hostname,
                        "Different from before")
 
@@ -589,19 +599,59 @@ def testHostname(user, hostname, machine):
 def modify(user, fields):
     """Handler for modifying attributes of a machine."""
     #XXX not written yet
-    machine = testMachineId(user, fields.getfirst('machine_id'))
-    owner = testOwner(user, fields.getfirst('owner'), machine)
-    contact = testContact(user, fields.getfirst('contact'))
-    hostname = testHostname(user, fields.getfirst('hostname'),
+
+    transaction = ctx.current.create_transaction()
+    try:
+        machine = testMachineId(user, fields.getfirst('machine_id'))
+        owner = testOwner(user, fields.getfirst('owner'), machine)
+        contact = testContact(user, fields.getfirst('contact'))
+        hostname = testHostname(owner, fields.getfirst('hostname'),
                             machine)
-    ram = fields.getfirst('memory')
-    if ram is not None:
-        ram = validMemory(user, ram, machine)
-    disk = testDisk(user, fields.getfirst('disk'))
-    if disk is not None:
-        disk = validDisk(user, disk, machine)
+        name = testName(user, fields.getfirst('name'))
+        oldname = machine.name
+        olddisk = {}
+
+        memory = fields.getfirst('memory')
+        if memory is not None:
+            memory = validMemory(user, memory, machine)
+        if memory != machine.memory:
+            machine.memory = memory
+
+        disksize = testDisk(user, fields.getfirst('disk'))
+        if disksize is not None:
+            disksize = validDisk(user, disksize, machine)
+        
+        for disk in machine.disks:
+            disk.size = disksize
+            olddisk[disk.guest_device_name] = disk.size
+            ctx.current.save(disk)
+        
+        # XXX all NICs get same hostname on change?  Interface doesn't support more.
+        for nic in machine.nics:
+            nic.hostname = hostname
+            ctx.current.save(nic)
+
+        if owner != machine.owner:
+            machine.owner = owner
+        if name != machine.name:
+            machine.name = name
+            
+        ctx.current.save(machine)
+        transaction.commit()
+    except:
+        transaction.rollback()
+    remctl("web", "moveregister", oldname, name)
+    for disk in machine.disks:
+        # XXX all disks get the same size on change?  Interface doesn't support more.
+        if disk.size != olddisk[disk.guest_device_name]:
+            remctl("web", "lvresize", oldname, disk.guest_device_name, str(disk.size))
+        if oldname != name:
+            remctl("web", "lvrename", oldname, disk.guest_device_name, name)
+    d = dict(user=user,
+             command="modify",
+             machine=machine)
+    return Template(file="command.tmpl", searchList=[d, global_dict])    
 
-    
 
 def help(user, fields):
     """Handler for help messages."""