[Et-mgmt-commits-list] [SCM] virt-factory branch, master now at v0.0.3-336-g0542911

Scott Seago sseago at redhat.com
Mon Oct 22 15:28:31 UTC 2007


Hello,

This is an automated email from the git hooks/update script, it was
generated because a ref change was pushed to the repository.

Updating branch, master,
       via  05429115bfdb2b758abad655149b5372c130dafe (commit)
       via  0896391518af68591e19290e2e131a8c15543869 (commit)
       via  aff0927d50f74cc898f1d5e5931be290c9f7d1b3 (commit)
      from  515b8c48dae81a7e3bd73727bee0c474ab32b7e4 (commit)

- Log -----------------------------------------------------------------
commit 05429115bfdb2b758abad655149b5372c130dafe
Merge: 0896391... 515b8c4...
Author: Scott Seago <sseago at redhat.com>
Date:   Mon Oct 22 11:01:15 2007 -0400

    Merge branch 'master' of git+ssh://g-sseago@et.redhat.com/git/virt-factory

commit 0896391518af68591e19290e2e131a8c15543869
Author: Scott Seago <sseago at redhat.com>
Date:   Mon Oct 22 11:01:06 2007 -0400

    upgrade script for tag changes

commit aff0927d50f74cc898f1d5e5931be290c9f7d1b3
Author: Scott Seago <sseago at redhat.com>
Date:   Mon Oct 22 10:50:57 2007 -0400

    refactored machine and deployment tags to use a separate tags table with many-to-many sqlalchemy mapping to map tags to machines/deployments
-----------------------------------------------------------------------

Diffstat:
 service/db/schema/upgrade/0003.py                |   29 ++--
 service/modules/deployment.py                    |   81 ++++----
 service/modules/machine.py                       |   82 ++++----
 service/modules/tag.py                           |  214 +++++++++++-----------
 service/server/db.py                             |   29 +++-
 wui/src/app/controllers/deployment_controller.rb |    8 +-
 wui/src/app/controllers/machine_controller.rb    |    8 +-
 wui/src/app/controllers/tag_controller.rb        |   10 +-
 wui/src/app/models/deployment.rb                 |    5 +-
 wui/src/app/models/machine.rb                    |    5 +-
 wui/src/app/models/managed_object.rb             |   11 +-
 wui/src/app/models/tag.rb                        |   20 ++-
 wui/src/app/views/deployment/edit.rhtml          |    8 +-
 wui/src/app/views/machine/edit.rhtml             |    8 +-
 14 files changed, 273 insertions(+), 245 deletions(-)

diff --git a/service/db/schema/upgrade/0003.py b/service/db/schema/upgrade/0003.py
index e4c4179..f8e6e5e 100644
--- a/service/db/schema/upgrade/0003.py
+++ b/service/db/schema/upgrade/0003.py
@@ -5,24 +5,29 @@ from migrate.changeset import *
 from datetime import datetime
 
 meta = BoundMetaData(migrate_engine)
-tables = []  # no new tables
+tables = []
+
+Database.tables.append(Table('tags', Database.meta,
+    Column('id', Integer, Sequence('tagid'), primary_key=True),
+    Column('name', String(255), unique=True)
+))
+        
+Database.tables.append(Table('machine_tags', Database.meta,
+    Column('tag_id', Integer, ForeignKey('tags.id')),
+    Column('machine_id', Integer, ForeignKey('machines.id'))
+))
+        
+Database.tables.append(Table('deployment_tags', Database.meta,
+    Column('tag_id', Integer, ForeignKey('tags.id')),
+    Column('deployment_id', Integer, ForeignKey('deployments.id'))
+))
 
 # provides a static dictionary of tables.
 table = dict([(t.name, t) for t in tables])
 
 
 def get_columns():
-
-    machines_table = sqlalchemy.Table('machines',meta) 
-    deployments_table = sqlalchemy.Table('deployments',meta) 
-    
-    machine_tags_column = Column('tags',String(4000),nullable=True)
-    deployment_tags_column = Column('tags',String(4000),nullable=True)
-
-    return { 
-        machine_tags_column:     machines_table,
-        deployment_tags_column:  deployments_table
-    }
+    return {}
 
 columns = get_columns()
 
diff --git a/service/modules/deployment.py b/service/modules/deployment.py
index e8cfbd0..16d0231 100755
--- a/service/modules/deployment.py
+++ b/service/modules/deployment.py
@@ -26,6 +26,7 @@ import web_svc
 import task
 import regtoken
 import provisioning
+import tag
 from server import config_data
 
 import re
@@ -124,10 +125,8 @@ class Deployment(web_svc.AuthWebSvc):
                     'is_locked',
                     'auto_start',
                     'last_heartbeat',
-                    'tags')
+                    'tag_ids')
         self.logger.info(args)
-        if args.has_key('tags') and type(args['tags']) is list:
-            args['tags'] = ','.join(dict.fromkeys(args['tags']).keys())
         validator = FieldValidator(args)
         validator.verify_required(required)
         validator.verify_printable('puppet_node_diff')
@@ -169,6 +168,9 @@ class Deployment(web_svc.AuthWebSvc):
             deployment = db.Deployment()
             deployment.update(args)
             session.save(deployment)
+            if args.has_key('tag_ids'):
+                setattr(deployment, "tags", tag.Tag().tags_from_ids(session,
+                                                                 args['tag_ids']))
             session.flush()
             self.cobbler_sync(deployment.get_hash())
             args["id"] = deployment.id
@@ -204,11 +206,8 @@ class Deployment(web_svc.AuthWebSvc):
         optional = ('machine_id', 'state', 'display_name',
                     'hostname', 'ip_address', 'registration_token',
                     'mac_address', 'netboot_enabled', 'puppet_node_diff',
-                    'is_locked', 'last_heartbeat','auto_start', 'tags')
+                    'is_locked', 'last_heartbeat','auto_start', 'tag_ids')
         filter = ('id', 'profile_id')
-        if args.has_key('tags') and type(args['tags']) is list:
-            print "tags is a list: ", args['tags']
-            args['tags'] = ','.join(dict.fromkeys(args['tags']).keys())
         validator = FieldValidator(args)
         validator.verify_required(required)
         validator.verify_printable('puppet_node_diff', 'tags')
@@ -245,6 +244,9 @@ class Deployment(web_svc.AuthWebSvc):
                 
             deployment.update(args, filter)
             session.save(deployment)
+            if args.has_key('tag_ids'):
+                setattr(deployment, "tags", tag.Tag().tags_from_ids(session,
+                                                                 args['tag_ids']))
             session.flush()
             self.cobbler_sync(deployment.get_hash())
             return success()
@@ -424,19 +426,19 @@ class Deployment(web_svc.AuthWebSvc):
         @type token: string
         @param args: A dictionary of deployment attributes.
             - id
-            - tag
+            - tag_id
         @type args: dict
         @raise SQLException: On database error
         @raise NoSuchObjectException: On object not found.
         """
-        required = ('id', 'tag',)
+        required = ('id', 'tag_id',)
         FieldValidator(args).verify_required(required)
         deployment = self.get(token, {"id": args["id"]}).data
-        tag = args["tag"]
-        tags = deployment["tags"]
-        if not tag in tags:
-            tags.append(tag)
-            self.edit(token, {"id": args["id"], "tags": tags})
+        tag_id = args["tag_id"]
+        tag_ids = deployment["tag_ids"]
+        if not int(tag_id) in tag_ids:
+            tag_ids.append(int(tag_id))
+            self.edit(token, {"id": args["id"], "tag_ids": tag_ids})
         return success()
 
     def remove_tag(self, token, args):
@@ -446,19 +448,19 @@ class Deployment(web_svc.AuthWebSvc):
         @type token: string
         @param args: A dictionary of deployment attributes.
             - id
-            - tag
+            - tag_id
         @type args: dict
         @raise SQLException: On database error
         @raise NoSuchObjectException: On object not found.
         """
-        required = ('id', 'tag',)
+        required = ('id', 'tag_id',)
         FieldValidator(args).verify_required(required)
         deployment = self.get(token, {"id": args["id"]}).data
-        tag = args["tag"]
-        tags = deployment["tags"]
-        if tag in tags:
-            tags.remove(tag)
-            self.edit(token, {"id": args["id"], "tags": tags})
+        tag_id = args["tag_id"]
+        tag_ids = deployment["tag_ids"]
+        if int(tag_id) in tag_ids:
+            tag_ids.remove(int(tag_id))
+            self.edit(token, {"id": args["id"], "tag_ids": tag_ids})
         return success()
 
     def get_by_mac_address(self, token, args):
@@ -620,31 +622,30 @@ class Deployment(web_svc.AuthWebSvc):
         """
         Return a list of all deployments tagged with the given tag
         """
-        required = ('tag',)
+        required = ('tag_id',)
         FieldValidator(args).verify_required(required)
-        in_tag = args['tag']
-        deployments = self.list(None, {})
-        if deployments.error_code != 0:
-            return deployments
-
-        result = []
-        for deployment in deployments.data:
-            tags = deployment["tags"]
-            if tags is not None:
-                for tag in tags:
-                    if in_tag.strip() == tag.strip():
-                        result.append(deployment)
-                        break
-        return success(result)
+        tag_id = args['tag_id']
+        session = db.open_session()
+        try:
+            name = args['name']
+            deployment_tags = db.Database.table['deployment_tags']
+            deployments = session.query(db.Deployment).select((deployment_tags.c.tag_id==tag_id &
+                                                         deployment_tags.c.deployment_id==db.Deployment.c.id))
+            if deployments:
+                deployments = self.expand(deployments)
+            return codes.success(deployments)
+        finally:
+            session.close()
 
     def expand(self, deployment):
         result = deployment.get_hash()
         result['machine'] = deployment.machine.get_hash()
         result['profile'] = deployment.profile.get_hash()
-        if result.has_key('tags') and result['tags'] is not None:
-            result['tags'] = re.compile('\s*,\s*').split(result['tags'])
-        else:
-            result['tags'] = []
+        result['tags'] = []
+        result['tag_ids'] = []
+        for tag in deployment.tags:
+            result['tags'].append(tag.get_hash())
+            result['tag_ids'].append(tag.id)
         return result
 
 
diff --git a/service/modules/machine.py b/service/modules/machine.py
index 0ddd706..f0a8cc3 100755
--- a/service/modules/machine.py
+++ b/service/modules/machine.py
@@ -24,6 +24,7 @@ import provisioning
 import deployment
 import web_svc
 import regtoken
+import tag
 from server import config_data
 
 import re
@@ -63,12 +64,9 @@ class Machine(web_svc.AuthWebSvc):
             'kickstart_metadata', 'list_group', 'mac_address', 
             'is_container', 'puppet_node_diff', 
             'netboot_enabled', 'is_locked', 'status',
-            'last_heartbeat', 'tags'
+            'last_heartbeat', 'tag_ids'
         )
         required = ('profile_id',)
-        if args.has_key('tags') and type(args['tags']) is list:
-            print "tags is a list: ", args['tags']
-            args['tags'] = ','.join(dict.fromkeys(args['tags']).keys())
         self.validate(args, required)
         session = db.open_session()
         try:
@@ -77,6 +75,9 @@ class Machine(web_svc.AuthWebSvc):
             machine.registration_token = regtoken.RegToken().generate(token)
             machine.netboot_enabled = 1 # initially, allow PXE, until it registers
             session.save(machine)
+            if args.has_key('tag_ids'):
+                setattr(machine, "tags", tag.Tag().tags_from_ids(session,
+                                                                 args['tag_ids']))
             session.flush()
             if machine.profile_id >= 0:
                 self.cobbler_sync(machine.get_hash()) 
@@ -157,16 +158,17 @@ class Machine(web_svc.AuthWebSvc):
              'kickstart_metadata', 'profile_id', 
              'list_group', 'mac_address', 'is_container', 
              'puppet_node_diff', 'netboot_enabled', 'is_locked',
-             'state', 'last_heartbeat', 'tags'
+             'state', 'last_heartbeat', 'tag_ids'
         )
-        if args.has_key('tags') and type(args['tags']) is list:
-            args['tags'] = ','.join(dict.fromkeys(args['tags']).keys())
         self.validate(args, required)
         session = db.open_session()
         try:
             machine = db.Machine.get(session, args['id'])
             machine.update(args)
             session.save(machine)
+            if args.has_key('tag_ids'):
+                setattr(machine, "tags", tag.Tag().tags_from_ids(session,
+                                                                 args['tag_ids']))
             session.flush()
             if machine.profile_id >= 0:
                 self.cobbler_sync(machine.get_hash())
@@ -296,19 +298,19 @@ class Machine(web_svc.AuthWebSvc):
         @type token: string
         @param args: A dictionary of machine attributes.
             - id
-            - tag
+            - tag_id
         @type args: dict
         @raise SQLException: On database error
         @raise NoSuchObjectException: On object not found.
         """
-        required = ('id', 'tag',)
+        required = ('id', 'tag_id',)
         FieldValidator(args).verify_required(required)
         machine = self.get(token, {"id": args["id"]}).data
-        tag = args["tag"]
-        tags = machine["tags"]
-        if not tag in tags:
-            tags.append(tag)
-            self.edit(token, {"id": args["id"], "tags": tags})
+        tag_id = args["tag_id"]
+        tag_ids = machine["tag_ids"]
+        if not int(tag_id) in tag_ids:
+            tag_ids.append(int(tag_id))
+            self.edit(token, {"id": args["id"], "tag_ids": tag_ids})
         return codes.success()
 
     def remove_tag(self, token, args):
@@ -318,19 +320,19 @@ class Machine(web_svc.AuthWebSvc):
         @type token: string
         @param args: A dictionary of machine attributes.
             - id
-            - tag
+            - tag_id
         @type args: dict
         @raise SQLException: On database error
         @raise NoSuchObjectException: On object not found.
         """
-        required = ('id', 'tag',)
+        required = ('id', 'tag_id',)
         FieldValidator(args).verify_required(required)
         machine = self.get(token, {"id": args["id"]}).data
-        tag = args["tag"]
-        tags = machine["tags"]
-        if tag in tags:
-            tags.remove(tag)
-            self.edit(token, {"id": args["id"], "tags": tags})
+        tag_id = args["tag_id"]
+        tag_ids = machine["tag_ids"]
+        if int(tag_id) in tag_ids:
+            tag_ids.remove(int(tag_id))
+            self.edit(token, {"id": args["id"], "tag_ids": tag_ids})
         return codes.success()
 
     def get_by_regtoken(self, token, args):
@@ -411,22 +413,20 @@ class Machine(web_svc.AuthWebSvc):
         """
         Return a list of all machines tagged with the given tag
         """
-        required = ('tag',)
+        required = ('tag_id',)
         FieldValidator(args).verify_required(required)
-        in_tag = args['tag']
-        machines = self.list(None, {})
-        if machines.error_code != 0:
-            return machines
-
-        result = []
-        for machine in machines.data:
-            tags = machine["tags"]
-            if tags is not None:
-                for tag in tags:
-                    if in_tag.strip() == tag.strip():
-                        result.append(machine)
-                        break
-        return codes.success(result)
+        tag_id = args['tag_id']
+        session = db.open_session()
+        try:
+            name = args['name']
+            machine_tags = db.Database.table['machine_tags']
+            machines = session.query(db.Machine).select((machine_tags.c.tag_id==tag_id &
+                                                         machine_tags.c.machine_id==db.Machine.c.id))
+            if machines:
+                machines = self.expand(machines)
+            return codes.success(machines)
+        finally:
+            session.close()
 
     def validate(self, args, required):
         vdr = FieldValidator(args)
@@ -443,11 +443,11 @@ class Machine(web_svc.AuthWebSvc):
         result = machine.get_hash()
         result['profile'] = machine.profile.get_hash()
         result['profile']['distribution'] = machine.profile.distribution.get_hash()
-        if result.has_key('tags') and result['tags'] is not None:
-            result['tags'] = re.compile('\s*,\s*').split(result['tags'])
-        else:
-            result['tags'] = []
-
+        result['tags'] = []
+        result['tag_ids'] = []
+        for tag in machine.tags:
+            result['tags'].append(tag.get_hash())
+            result['tag_ids'].append(tag.id)
         return result
 
 
diff --git a/service/modules/tag.py b/service/modules/tag.py
index 0fa4715..02db1e4 100644
--- a/service/modules/tag.py
+++ b/service/modules/tag.py
@@ -14,6 +14,8 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 """
 
 from server.codes import *
+from server import codes
+from server import db
 from fieldvalidator import FieldValidator
 
 from datetime import *
@@ -27,34 +29,12 @@ import web_svc
 class Tag(web_svc.AuthWebSvc):
     def __init__(self):
         self.methods = {"tag_list": self.list,
-                        "tag_get_names": self.get_tag_names,
                         "tag_get": self.get,
                         "tag_add": self.add,
                         "tag_edit": self.edit,
                         "tag_delete": self.delete}
         web_svc.AuthWebSvc.__init__(self)
 
-    def get_tags_internal(self, module_obj, module_key, id_key, tag_dict):
-        item_list = module_obj.list(None, {})
-        for item in item_list.data:
-            tags = item["tags"]
-            for tag_name in tags:
-                if not tag_dict.has_key(tag_name):
-                    tag_dict[tag_name]={"id": tag_name,
-                                        "name": tag_name,
-                                        "machines": [],
-                                        "machine_ids": [],
-                                        "deployments": [],
-                                        "deployment_ids": [] }
-                tag_dict[tag_name][module_key].append(item)
-                tag_dict[tag_name][id_key].append(item["id"])
-        return tag_dict
-
-    def get_tag_dict(self):
-        tag_dict = self.get_tags_internal(machine.Machine(), "machines", "machine_ids", {})
-        tag_dict = self.get_tags_internal(deployment.Deployment(), "deployments", "deployment_ids", tag_dict)
-        return tag_dict
-        
     def get(self, token, args={}):
         """
         Get a tag by name.
@@ -62,31 +42,47 @@ class Tag(web_svc.AuthWebSvc):
         @type token: string
         @param args: A dictionary of tag attributes.
             - id
-            - name
         @type args: dict
         @return A tag
         @rtype: dict
+        @raise SQLException: On database error
         @raise NoSuchObjectException: On object not found.
         """
-        # also accept id for name to make WUI happy
-        if args.has_key('id') and (not args.has_key('name')):
-            args["name"]=args["id"]
-        required = ('name',)
+        required = ('id',)
         FieldValidator(args).verify_required(required)
-        tag_dict = self.get_tag_dict()
-        if not tag_dict.has_key(args["name"]):
-            raise NoSuchObjectException(comment='tag %s not found' % args["name"])
-        return success(self.get_tag_dict()[args["name"]])
+        session = db.open_session()
+        try:
+            tag = db.Tag.get(session, args['id'])
+            results = self.expand(tag)
+            self.logger.info("your tag is: %s" % results)
+            return success(results)
+
+        finally:
+            session.close()
         
-    def list(self, token, args={}):
-        """
-        Returns a list of tags with associated machines and deployments
+    def list(self, token, args):
         """
-        return success(self.get_tag_dict().values())
-        
-    def get_tag_names(self, token, args={}):
-        return success(self.get_tag_dict().keys())
-        
+        Get a list of all tags.
+        @param token: A security token.
+        @type token: string
+        @param args: A dictionary of tag attributes.
+        @type args: dict
+            - offset (optional)
+            - limit (optional)
+        @return A list of all tags.
+        @rtype: [dict,]
+        @raise SQLException: On database error
+        """    
+        session = db.open_session()
+        try:
+            result = []
+            offset, limit = self.offset_and_limit(args)
+            for tag in db.Tag.list(session, offset, limit):
+                result.append(self.expand(tag))
+            return codes.success(result)
+        finally:
+            session.close()
+
     def add(self, token, args):
         """
         Create a tag
@@ -100,28 +96,26 @@ class Tag(web_svc.AuthWebSvc):
             - deployment_ids
         @raise SQLException: On database error
         """
-        # also accept id for name to make WUI happy
-        if args.has_key('id') and (not args.has_key('name')):
-            args["name"]=args["id"]
         required = ('name',)
         optional = ('machine_ids', 'deployment_ids')
         FieldValidator(args).verify_required(required)
-        name = args["name"]
-        machine_ids = []
-        deployment_ids = []
-        if args.has_key('machine_ids'):
-            machine_ids = args['machine_ids']
-        if args.has_key('deployment_ids'):
-            deployment_ids = args['deployment_ids']
-        if name in self.get_tag_names(token).data:
-            raise InvalidArgumentsException(comment='tag %s already exists' % name)
-        machine_obj = machine.Machine()
-        deployment_obj = deployment.Deployment()
-        for machine_id in machine_ids:
-            machine_obj.add_tag(token, {"id": machine_id, "tag": name})
-        for deployment_id in deployment_ids:
-            deployment_obj.add_tag(token, {"id": deployment_id, "tag": name})
-        return success()
+        session = db.open_session()
+        try:
+            tag = db.Tag()
+            tag.update(args)
+            session.save(tag)
+            if args.has_key('machine_ids'):
+                setattr(tag, "machines", self.objects_from_ids(session,
+                                                               db.Machine,
+                                                               args['machine_ids']))
+            if args.has_key('deployment_ids'):
+                setattr(tag, "deployments", self.objects_from_ids(session,
+                                                                  db.Deployment,
+                                                                  args['deployment_ids']))
+            session.flush()
+            return success()
+        finally:
+            session.close()
          
     def edit(self, token, args):
         """
@@ -137,54 +131,26 @@ class Tag(web_svc.AuthWebSvc):
         @raise SQLException: On database error
         @raise NoSuchObjectException: On object not found.
         """
-        # also accept id for name to make WUI happy
-        if args.has_key('id') and (not args.has_key('name')):
-            args["name"]=args["id"]
-        required = ('name',)
-        optional = ('machine_ids', 'deployment_ids')
+        required = ('id',)
+        optional = ('name', 'machine_ids', 'deployment_ids')
         FieldValidator(args).verify_required(required)
-        name = args["name"]
-        machine_ids = []
-        deployment_ids = []
-        db_machine_ids = []
-        db_deployment_ids = []
-        if args.has_key('machine_ids'):
-            machine_ids = args['machine_ids']
-        if args.has_key('deployment_ids'):
-            deployment_ids = args['deployment_ids']
-        tag_in_db = self.get(token, {"name":  name}).data
-        machine_obj = machine.Machine()
-        deployment_obj = deployment.Deployment()
-
-        # loop through current machines for this tag -- remove
-        # any that are not in the new list
-        for db_machine in tag_in_db["machines"]:
-            this_id = db_machine["id"]
-            db_machine_ids.append(this_id)
-            if this_id not in machine_ids:
-                machine_obj.remove_tag(token, {"id": this_id, "tag": name})
-
-        # loop through current deployments for this tag -- remove
-        # any that are not in the new list
-        for db_deployment in tag_in_db["deployments"]:
-            this_id = db_deployment["id"]
-            db_deployment_ids.append(this_id)
-            if this_id not in deployment_ids:
-                deployment_obj.remove_tag(token, {"id": this_id, "tag": name})
-            
-        # loop through new machines for this tag -- add
-        # any that are not in the current list
-        for machine_id in machine_ids:
-            if machine_id not in db_machine_ids:
-                machine_obj.add_tag(token, {"id": machine_id, "tag": name})
-
-        # loop through new deployments for this tag -- add
-        # any that are not in the current list
-        for deployment_id in deployment_ids:
-            if deployment_id not in db_deployment_ids:
-                deployment_obj.add_tag(token, {"id": deployment_id, "tag": name})
-                
-        return success()
+        session = db.open_session()
+        try:
+            tag = db.Tag.get(session, args['id'])
+            tag.update(args)
+            session.save(tag)
+            if args.has_key('machine_ids'):
+                setattr(tag, "machines", self.objects_from_ids(session,
+                                                               db.Machine,
+                                                               args['machine_ids']))
+            if args.has_key('deployment_ids'):
+                setattr(tag, "deployments", self.objects_from_ids(session,
+                                                                  db.Deployment,
+                                                                  args['deployment_ids']))
+            session.flush()
+            return success()
+        finally:
+            session.close()
          
     def delete(self, token, args):
         """
@@ -197,10 +163,40 @@ class Tag(web_svc.AuthWebSvc):
         @raise SQLException: On database error
         @raise NoSuchObjectException: On object not found.
         """
-        if args.has_key('id') and (not args.has_key('name')):
-            args["name"]=args["id"]
-        return self.edit(token, {"name": args["name"], "deployment_ids": [], "machine_ids": []})
-
+        required = ('id',)
+        FieldValidator(args).verify_required(required)
+        session = db.open_session()
+        try:
+            db.Tag.delete(session, args['id'])
+            return codes.success()
+        finally:
+            session.close()
+
+    def tags_from_ids(self, session, tag_ids):
+        return self.objects_from_ids(session, db.Tag, tag_ids)
+            
+    def objects_from_ids(self, session, type_obj, ids):
+        objs = []
+        for id in ids:
+            objs.append(type_obj.get(session, id))
+        return objs
+
+    def expand(self, tag):
+        result = tag.get_hash()
+        result['machines'] = []
+        result['machine_ids'] = []
+        for machine in tag.machines:
+            result['machines'].append(machine.get_hash())
+            result['machine_ids'].append(machine.id)
+        result['deployments'] = []
+        result['deployment_ids'] = []
+        for deployment in tag.deployments:
+            deployment_hash = deployment.get_hash()
+            deployment_hash["machine"] = deployment.machine.get_hash()
+            deployment_hash["profile"] = deployment.profile.get_hash()
+            result['deployments'].append(deployment_hash)
+            result['deployment_ids'].append(deployment.id)
+        return result
 
 
 methods = Tag()
diff --git a/service/server/db.py b/service/server/db.py
index 2ec1013..e183c1e 100644
--- a/service/server/db.py
+++ b/service/server/db.py
@@ -97,6 +97,8 @@ class Task(Base):
     pass
 class Event(Base):
     pass
+class Tag(Base):
+    pass
 
 
 
@@ -216,8 +218,7 @@ class Database:
             Column('netboot_enabled', Integer),
             Column('is_locked', Integer),
             Column('state', String(255)),
-            Column('last_heartbeat', Integer),
-            Column('tags', String(4000))
+            Column('last_heartbeat', Integer)
         ))
          
         Database.tables.append(Table('deployments', Database.meta,
@@ -240,8 +241,7 @@ class Database:
             Column('netboot_enabled', Integer),
             Column('is_locked', Integer),
             Column('auto_start', Integer),
-            Column('last_heartbeat', Integer),
-            Column('tags', String(4000))
+            Column('last_heartbeat', Integer)
         ))
         
         Database.tables.append(Table('regtokens', Database.meta,
@@ -302,6 +302,21 @@ class Database:
             Column('user_comment', String(255))
         ))
     
+        Database.tables.append(Table('tags', Database.meta,
+            Column('id', Integer, Sequence('tagid'), primary_key=True),
+            Column('name', String(255), unique=True)
+        ))
+        
+        Database.tables.append(Table('machine_tags', Database.meta,
+            Column('tag_id', Integer, ForeignKey('tags.id')),
+            Column('machine_id', Integer, ForeignKey('machines.id'))
+        ))
+        
+        Database.tables.append(Table('deployment_tags', Database.meta,
+            Column('tag_id', Integer, ForeignKey('tags.id')),
+            Column('deployment_id', Integer, ForeignKey('deployments.id'))
+        ))
+        
         #
         # provides a static dictionary of tables.
         #
@@ -363,9 +378,13 @@ class Database:
                     'machine' : relation(Machine, lazy=True),
                     'deployment' : relation(Deployment, lazy=True),
                     }),
+            mapper(Tag, Database.table['tags'], extension=Database.ctx.mapper_extension,
+                properties={
+                    'machines' : relation(Machine, secondary=Database.table['machine_tags'], backref='tags'),
+                    'deployments' : relation(Deployment, secondary=Database.table['deployment_tags'], backref='tags'),
+                    }),
         )
     
-    
         #
         # provides a static dictionary of orm classes to mapped
         # table column names.
diff --git a/wui/src/app/controllers/deployment_controller.rb b/wui/src/app/controllers/deployment_controller.rb
index ebb4e6e..c13e7dd 100755
--- a/wui/src/app/controllers/deployment_controller.rb
+++ b/wui/src/app/controllers/deployment_controller.rb
@@ -47,7 +47,7 @@ class DeploymentController < AbstractObjectController
         get_valid_profiles
         #get list of current tags from virt-factory
         begin
-            @tags = ManagedObject.call_server("tag_get_names", get_login, {})
+	    @tags = ManagedObject.retrieve_all(Tag, get_login)
         rescue XMLRPCClientException => ex
             set_flash_on_exception(ex)
         end
@@ -65,11 +65,7 @@ class DeploymentController < AbstractObjectController
     end
 
     def edit_submit
-        tags = params["form"]["tags"]
-        tags = [] if tags.nil?
-        new_tags = params["form"]["new_tags"]
-        params["form"]["tags"] = tags + new_tags.strip.split(%r{\s*,\s*})
-        params["form"].delete("new_tags")
+        params["form"]["tag_ids"] = [] if params["form"]["tag_ids"].nil?
         super
     end
         
diff --git a/wui/src/app/controllers/machine_controller.rb b/wui/src/app/controllers/machine_controller.rb
index dadfce0..0ccdeb2 100755
--- a/wui/src/app/controllers/machine_controller.rb
+++ b/wui/src/app/controllers/machine_controller.rb
@@ -34,18 +34,14 @@ class MachineController < AbstractObjectController
 
         #get list of current tags from virt-factory
         begin
-            @tags = ManagedObject.call_server("tag_get_names", get_login, {})
+	    @tags = ManagedObject.retrieve_all(Tag, get_login)
         rescue XMLRPCClientException => ex
             set_flash_on_exception(ex)
         end
     end
 
     def edit_submit
-        tags = params["form"]["tags"]
-        tags = [] if tags.nil?
-        new_tags = params["form"]["new_tags"]
-        params["form"]["tags"] = tags + new_tags.strip.split(%r{\s*,\s*})
-        params["form"].delete("new_tags")
+        params["form"]["tag_ids"] = [] if params["form"]["tag_ids"].nil?
         super
     end
         
diff --git a/wui/src/app/controllers/tag_controller.rb b/wui/src/app/controllers/tag_controller.rb
index c411136..479446f 100644
--- a/wui/src/app/controllers/tag_controller.rb
+++ b/wui/src/app/controllers/tag_controller.rb
@@ -31,15 +31,13 @@ class TagController < AbstractObjectController
     end
 
     def edit_submit
-        machine_ids = params["form"]["machine_ids"]
-        machine_ids = [] if machine_ids.nil?
-        deployment_ids = params["form"]["deployment_ids"]
-        deployment_ids = [] if deployment_ids.nil?
+        params["form"]["machine_ids"] = [] if params["form"]["machine_ids"].nil?
+        params["form"]["deployment_ids"] = [] if params["form"]["deployment_ids"].nil?
         super
     end
 
     def remove_machine
-        args = { "id" => params[:machine_id], "tag" => params[:id]}
+        args = { "id" => params[:machine_id], "tag_id" => params[:id]}
         begin
             ManagedObject.call_server("machine_remove_tag", get_login, args)
         rescue XMLRPCClientException => ex
@@ -49,7 +47,7 @@ class TagController < AbstractObjectController
     end
 
     def remove_deployment
-        args = { "id" => params[:deployment_id], "tag" => params[:id]}
+        args = { "id" => params[:deployment_id], "tag_id" => params[:id]}
         begin
             ManagedObject.call_server("deployment_remove_tag", get_login, args)
         rescue XMLRPCClientException => ex
diff --git a/wui/src/app/models/deployment.rb b/wui/src/app/models/deployment.rb
index 9ccf7b7..381884e 100755
--- a/wui/src/app/models/deployment.rb
+++ b/wui/src/app/models/deployment.rb
@@ -21,8 +21,9 @@ class Deployment < ManagedObject
        :is_locked          => { :type => Integer },
        :auto_start         => { :type => Integer },
        :last_heartbeat     => { :type => Integer },
-       :tags               => {:type => [Array, String]},
-       :new_tags           => {:type => String} 
+       :tags               => {:type => [Array, Tag]},
+       :tag_ids            => {:type => [Array, Integer]}#,
+#       :new_tags           => {:type => String} 
     }
     self.set_attrs(ATTR_LIST)
      
diff --git a/wui/src/app/models/machine.rb b/wui/src/app/models/machine.rb
index c9e5ac3..0c87b27 100755
--- a/wui/src/app/models/machine.rb
+++ b/wui/src/app/models/machine.rb
@@ -27,8 +27,9 @@ class Machine < ManagedObject
                   :is_locked => {:type => Integer},
                   :last_heartbeat => {:type => Integer},
                   :state => {:type => String},
-                  :tags => {:type => [Array, String]},
-                  :new_tags => {:type => String}
+                  :tags => {:type => [Array, Tag]},
+                  :tag_ids => {:type => [Array, Integer]}#,
+#                  :new_tags => {:type => String}
     }
 
     self.set_attrs(ATTR_LIST)
diff --git a/wui/src/app/models/managed_object.rb b/wui/src/app/models/managed_object.rb
index 92c8b26..345b294 100755
--- a/wui/src/app/models/managed_object.rb
+++ b/wui/src/app/models/managed_object.rb
@@ -199,7 +199,15 @@ class ManagedObject
         hash = Hash.new
         self.class::ATTR_LIST.each do |attr, metadata|
             if (newval = self.method(attr).call)
-                if (newval.methods.include?("to_hash"))
+                if (newval.is_a?(Array))
+                    newval = newval.collect do |x|
+                        if (x.methods.include?("to_hash"))
+                            x.to_hash
+                        else
+                            x
+                        end
+                    end
+                elsif (newval.methods.include?("to_hash"))
                     newval = newval.to_hash
                 end
                 hash[attr.to_s] = newval 
@@ -222,7 +230,6 @@ class ManagedObject
 
         # the return signature for a backend API method is usually (rc, hash) where hash contains
         # one or more of the following fields.  See explanation in XMLRPCClientException class.
- 
         (rc, rawdata) = @@server.call(method_name, login, args)
 
         unless rc == ERR_SUCCESS
diff --git a/wui/src/app/models/tag.rb b/wui/src/app/models/tag.rb
index 3397bf2..6ed03ce 100644
--- a/wui/src/app/models/tag.rb
+++ b/wui/src/app/models/tag.rb
@@ -5,7 +5,7 @@ class Tag < ManagedObject
     # corresponds to what's in the DB schema
  
     ATTR_LIST = { 
-        :id             => {:type => String}, 
+        :id             => {:type => Integer}, 
         :name           => {:type => String}, 
         :machines       => {:type => [Array, Machine], :id_attr => :machine_ids},
         :machine_ids    => {:type => [Array, Integer]},
@@ -23,5 +23,21 @@ class Tag < ManagedObject
     def objname
         name
     end
-  
+
+    #def machine_ids
+    #    if self.machines.nil?
+    #        []
+    #    else
+    #        self.machines.collect {|machine| machine.id }  
+     #   end
+    #end
+
+    #def deployment_ids
+    #    if self.deployments.nil?
+    #        []
+    #    else
+    #        self.deployments.collect {|deployment| deployment.id }  
+    #    end
+    #end
+
 end
diff --git a/wui/src/app/views/deployment/edit.rhtml b/wui/src/app/views/deployment/edit.rhtml
index aa9446c..284b6b5 100755
--- a/wui/src/app/views/deployment/edit.rhtml
+++ b/wui/src/app/views/deployment/edit.rhtml
@@ -56,7 +56,7 @@
                 <TD><%= _("Current Tags") %></TD>
                 <TD>
                     <% @item.tags.each do |tag| %>
-                        <%= tag %><br/>
+                        <%= tag.name %><br/>
                     <% end %>
                 </TD>
              </TR>
@@ -64,15 +64,11 @@
          <TR>
             <TD><%= _("Add/Remove Tags") %></TD>
             <TD>
-                <%= f.collection_select(:tags,  @tags, :strip, :strip,
+                <%= f.collection_select(:tag_ids,  @tags, :id, :name,
                     {},"multiple"=>'multiple',"size"=>10) %></td>
             </TD>
          </TR>
          <TR>
-            <TD><%= _("New Tags") %></TD>
-            <TD><%= f.text_field :new_tags %></TD>
-         </TR>
-         <TR>
             <TD COLSPAN="2"><input type="submit" value="<%= @operation=="edit" ?  _("Edit") : _("Add") %>"></TD>
          </TR>
       </TABLE>
diff --git a/wui/src/app/views/machine/edit.rhtml b/wui/src/app/views/machine/edit.rhtml
index f259405..4724c75 100755
--- a/wui/src/app/views/machine/edit.rhtml
+++ b/wui/src/app/views/machine/edit.rhtml
@@ -76,7 +76,7 @@
                 <TD><%= _("Current Tags") %></TD>
                 <TD>
                     <% @item.tags.each do |tag| %>
-                        <%= tag %><br/>
+                        <%= tag.name %><br/>
                     <% end %>
                 </TD>
              </TR>
@@ -84,15 +84,11 @@
          <TR>
             <TD><%= _("Add/Remove Tags") %></TD>
             <TD>
-                <%= f.collection_select(:tags,  @tags, :strip, :strip,
+                <%= f.collection_select(:tag_ids,  @tags, :id, :name,
                     {},"multiple"=>'multiple',"size"=>10) %></td>
             </TD>
          </TR>
          <TR>
-            <TD><%= _("New Tags") %></TD>
-            <TD><%= f.text_field :new_tags %></TD>
-         </TR>
-         <TR>
             <% if @operation == "add" %>
                  <TD COLSPAN="2"><input type="submit" value=<%= _("Add") %>></TD>
             <% else %>

hooks/update
---
Git Source Code Management System
hooks/update refs/heads/master \
  515b8c48dae81a7e3bd73727bee0c474ab32b7e4 \
  05429115bfdb2b758abad655149b5372c130dafe




More information about the Et-mgmt-commits-list mailing list