You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by fr...@apache.org on 2013/10/09 19:52:56 UTC

[2/2] git commit: updated refs/heads/4.2 to 30a680e

Add missing Baremetal security_group_agent java part
Change security_group_agent python side in line with default security
group rules change in 4.2


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/d31dcdfd
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/d31dcdfd
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/d31dcdfd

Branch: refs/heads/4.2
Commit: d31dcdfd92a47635315a7296b14ce855015045a5
Parents: e256794
Author: Frank.Zhang <fr...@citrix.com>
Authored: Mon Oct 7 18:03:12 2013 -0700
Committer: Frank.Zhang <fr...@citrix.com>
Committed: Wed Oct 9 10:52:42 2013 -0700

----------------------------------------------------------------------
 .../security_group_agent/cs_sg_agent.py         | 585 ++++++++++++-------
 .../security_group_agent/sglib.py               | 115 ++--
 .../networkservice/BareMetalResourceBase.java   |  43 +-
 .../networkservice/SecurityGroupHttpClient.java | 259 ++++++--
 .../networkservice/schema/ObjectFactory.java    |  55 ++
 .../schema/SecurityGroupRule.java               | 146 +++++
 .../schema/SecurityGroupVmRuleSet.java          | 263 +++++++++
 pom.xml                                         |   2 +
 8 files changed, 1150 insertions(+), 318 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d31dcdfd/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/cs_sg_agent.py
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/cs_sg_agent.py b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/cs_sg_agent.py
index a292c0b..f940264 100755
--- a/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/cs_sg_agent.py
+++ b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/cs_sg_agent.py
@@ -16,222 +16,369 @@
 # under the License.
 # 
 # Automatically generated by addcopyright.py at 01/29/2013
-'''
-Created on Jan 2, 2013
-
-@author: frank
-'''
-import cherrypy
-import sglib
-import xmlobject
-import types
-import uuid
-import os.path
-import sys
-import os
-
-class SGRule(object):
-    def __init__(self):
-        self.protocol = None
-        self.start_port = None
-        self.end_port = None
-        self.allowed_ips = []
-
-class IPSet(object):
-    IPSET_TYPE = 'hash:ip'
-    def __init__(self, setname, ips):
-        self.ips = ips
-        self.name = setname
-    
-    def create(self):
-        tmpname = str(uuid.uuid4()).replace('-', '')[0:30]
-        sglib.ShellCmd('ipset -N %s %s' % (tmpname, self.IPSET_TYPE))()
-        try:
-            for ip in self.ips:
-                sglib.ShellCmd('ipset -A %s %s' % (tmpname, ip))()
-            
-            try:
-                sglib.ShellCmd('ipset -N %s %s' % (self.name, self.IPSET_TYPE))()
-                cherrypy.log('created new ipset: %s' % self.name)
-            except Exception:
-                cherrypy.log('%s already exists, no need to create new' % self.name)
-        finally:
-            sglib.ShellCmd('ipset -W %s %s' % (tmpname, self.name))()
-            sglib.ShellCmd('ipset -F %s' % tmpname)()
-            sglib.ShellCmd('ipset -X %s' % tmpname)()
-            
-    @staticmethod 
-    def destroy_sets(sets_to_keep):
-        sets = sglib.ShellCmd('ipset list')()
-        for s in sets.split('\n'):
-            if 'Name:' in s:
-                set_name = s.split(':', 1)[1].strip()
-                if not set_name in sets_to_keep:
-                    sglib.ShellCmd('ipset destroy %s' % set_name)()
-                    cherrypy.log('destroyed unused ipset: %s' % set_name)
-        
-class SGAgent(object):
-    def __init__(self):
-        pass
-    
-    def _self_list(self, obj):
-        if isinstance(obj, types.ListType):
-            return obj
-        else:
-            return [obj]
-        
-    def set_rules(self, req):
-        body = req.body
-        doc = xmlobject.loads(body)
-        vm_name = doc.vmName.text_
-        vm_id = doc.vmId.text_
-        vm_ip = doc.vmIp.text_
-        vm_mac = doc.vmMac.text_
-        sig = doc.signature.text_
-        seq = doc.sequenceNumber.text_
-        
-        def parse_rules(rules, lst):
-            for i in self._self_list(rules):
-                r = SGRule()
-                r.protocol = i.protocol.text_
-                r.start_port = i.startPort.text_
-                r.end_port = i.endPort.text_
-                if hasattr(i, 'ip'):
-                    for ip in self._self_list(i.ip):
-                        r.allowed_ips.append(ip.text_)
-                lst.append(r)
-            
-        i_rules = []
-        if hasattr(doc, 'ingressRules'):
-            parse_rules(doc.ingressRules, i_rules)
-            
-        e_rules = []
-        if hasattr(doc, 'egressRules'):
-            parse_rules(doc.egressRules, e_rules)
-            
-        def create_chain(name):
-            try:
-                sglib.ShellCmd('iptables -F %s' % name)()
-            except Exception:
-                sglib.ShellCmd('iptables -N %s' % name)()
-            
-        def apply_rules(rules, chainname, direction, action, current_set_names):
-            create_chain(chainname)
-            for r in i_rules:
-                allow_any = False
-                if '0.0.0.0/0' in r.allowed_ips:
-                    allow_any = True
-                    r.allowed_ips.remove('0.0.0.0/0')
-                
-                if r.allowed_ips:
-                    setname = '_'.join([chainname, r.protocol, r.start_port, r.end_port])
-                    ipset = IPSet(setname, r.allowed_ips)
-                    ipset.create()
-                    current_set_names.append(setname)
-                    
-                    if r.protocol == 'all':
-                        cmd = ['iptables -I', chainname, '-m state --state NEW -m set --set', setname, direction, '-j', action]
-                        sglib.ShellCmd(' '.join(cmd))()
-                    elif r.protocol != 'icmp':
-                        port_range = ":".join([r.start_port, r.end_port])
-                        cmd = ['iptables', '-I', chainname, '-p', r.protocol, '-m', r.protocol, '--dport', port_range, '-m state --state NEW -m set --set', setname, direction, '-j', action]
-                        sglib.ShellCmd(' '.join(cmd))()
-                    else:
-                        port_range = "/".join([r.start_port, r.end_port])
-                        if r.start_port == "-1":
-                            port_range = "any"
-                        cmd = ['iptables', '-I', i_chain_name, '-p', 'icmp', '--icmp-type', port_range, '-m set --set', setname, direction, '-j', action]
-                        sglib.ShellCmd(' '.join(cmd))()
-                        
-                    
-                if allow_any and r.protocol != 'all':
-                    if r.protocol != 'icmp':
-                        port_range = ":".join([r.start_port, r.end_port])
-                        cmd = ['iptables', '-I', chainname, '-p', r.protocol, '-m', r.protocol, '--dport', port_range, '-m', 'state', '--state', 'NEW', '-j', action]
-                        sglib.ShellCmd(' '.join(cmd))()
-                    else:
-                        port_range = "/".join([r.start_port, r.end_port])
-                        if r.start_port == "-1":
-                            port_range = "any"
-                        cmd = ['iptables', '-I', i_chain_name, '-p', 'icmp', '--icmp-type', port_range, '-j', action]
-                        sglib.ShellCmd(' '.join(cmd))()
-        
-        current_sets = []
-        i_chain_name = vm_name + '-in'
-        apply_rules(i_rules, i_chain_name, 'src', 'ACCEPT', current_sets)
-        e_chain_name = vm_name + '-eg'
-        apply_rules(e_rules, e_chain_name, 'dst', 'RETURN', current_sets)
-        
-        if e_rules:
-            sglib.ShellCmd('iptables -A %s -j RETURN' % e_chain_name)
-        else:
-            sglib.ShellCmd('iptables -A %s -j DROP' % e_chain_name)
-        
-        sglib.ShellCmd('iptables -A %s -j DROP' % i_chain_name)
-        IPSet.destroy_sets(current_sets)
-                
-        
-    def echo(self, req):
-        cherrypy.log("echo: I am alive")
-        
-    def index(self):
-        req = sglib.Request.from_cherrypy_request(cherrypy.request)
-        cmd_name = req.headers['command']
-        
-        if not hasattr(self, cmd_name):
-            raise ValueError("SecurityGroupAgent doesn't have a method called '%s'" % cmd_name)           
-        method = getattr(self, cmd_name)
-        
-        return method(req)
-    index.exposed = True
-    
-    @staticmethod
-    def start():
-        cherrypy.log.access_file = '/var/log/cs-securitygroup.log'
-        cherrypy.log.error_file = '/var/log/cs-securitygroup.log'
-        cherrypy.server.socket_host = '0.0.0.0'
-        cherrypy.server.socket_port = 9988
-        cherrypy.quickstart(SGAgent())
-        
-    @staticmethod 
-    def stop():
-        cherrypy.engine.exit()
-
-PID_FILE = '/var/run/cssgagent.pid'
-class SGAgentDaemon(sglib.Daemon):
-    def __init__(self):
-        super(SGAgentDaemon, self).__init__(PID_FILE)
-        self.is_stopped = False
-        self.agent = SGAgent()
-        sglib.Daemon.register_atexit_hook(self._do_stop)
-    
-    def _do_stop(self):
-        if self.is_stopped:
-            return
-        self.is_stopped = True
-        self.agent.stop()
-    
-    def run(self):
-        self.agent.start()
-        
-    def stop(self):
-        self.agent.stop()
-        super(SGAgentDaemon, self).stop()
-
-def main():
-    usage = 'usage: python -c "from security_group_agent import cs_sg_agent; cs_sg_agent.main()" start|stop|restart'
-    if len(sys.argv) != 2 or not sys.argv[1] in ['start', 'stop', 'restart']:
-        print usage
-        sys.exit(1)
-    
-    cmd = sys.argv[1]
-    agentdaemon = SGAgentDaemon()
-    if cmd == 'start':
-        agentdaemon.start()
-    elif cmd == 'stop':
-        agentdaemon.stop()
-    else:
-        agentdaemon.restart()
-        
-    sys.exit(0)
-        
\ No newline at end of file
+
+'''
+Created on Jan 2, 2013
+
+@author: frank
+'''
+import cherrypy
+import sglib
+import xmlobject
+import types
+import uuid
+import os.path
+import sys
+import os
+
+class SGRule(object):
+    def __init__(self):
+        self.protocol = None
+        self.start_port = None
+        self.end_port = None
+        self.allowed_ips = []
+
+# iptables -D cannot handle rules having ipset match
+# we have to delete these rules by line number that's why I introduce 
+# this class that maintains rules with their line number
+class IptableChain(object):
+    def __init__(self):
+        self.name = None
+        self.rules = {}
+        
+    def delete_rule_by_line_number(self, num):
+        if str(num) not in self.rules.values():
+            return
+        
+        sglib.ShellCmd('iptables -D %s %s' % (self.name, num))()
+        
+    @staticmethod
+    def from_iptable_lists():
+        txt= sglib.ShellCmd('iptables --list --line-number')()
+        blocks = txt.split('\n')
+        
+        def is_rule_line(rule):
+            def is_number(n):
+                try:
+                    int(n)
+                    return True
+                except Exception:
+                    return False
+            
+            words = rule.split()
+            return is_number(words[0])
+            
+        current_chain = None
+        chains = []
+        for line in blocks:
+            line = line.strip()
+            if line == '':
+                continue
+            
+            if line.startswith('Chain'):
+                current_chain = IptableChain()
+                current_chain.name = line.split()[1]
+                chains.append(current_chain)
+                continue
+            
+            if not is_rule_line(line):
+                continue
+            
+            specs = line.split(None, 6)
+            if len(specs) == 7:
+                # e.g '1    RETURN     tcp  --  anywhere             anywhere            tcp dpt:https state NEW match-set i-4-32-VM-eg_tcp_443_443 dst'
+                # the last part is spec, using spec as key
+                current_chain.rules[specs[-1]] = specs[0]
+            else:
+                # e.g '3    DROP       all  --  anywhere             anywhere'
+                # no spec, using target as key
+                current_chain.rules[specs[1]] = specs[0]
+        
+        return chains
+            
+            
+        
+class IPSet(object):
+    IPSET_TYPE = 'hash:net'
+    def __init__(self, setname, ips):
+        self.ips = ips
+        self.name = setname
+    
+    def create(self):
+        tmpname = str(uuid.uuid4()).replace('-', '')[0:30]
+        sglib.ShellCmd('ipset -N %s %s' % (tmpname, self.IPSET_TYPE))()
+        try:
+            for ip in self.ips:
+                sglib.ShellCmd('ipset -A %s %s' % (tmpname, ip))()
+            
+            try:
+                sglib.ShellCmd('ipset -N %s %s' % (self.name, self.IPSET_TYPE))()
+                cherrypy.log('created ip set as: \nname: %s\nips: %s\n' % (self.name, self.ips))
+            except Exception:
+                cherrypy.log('%s already exists, no need to create new' % self.name)
+        finally:
+            sglib.ShellCmd('ipset -W %s %s' % (tmpname, self.name))()
+            sglib.ShellCmd('ipset -F %s' % tmpname)()
+            sglib.ShellCmd('ipset -X %s' % tmpname)()
+            
+    @staticmethod 
+    def destroy_sets_not_in(sets_to_keep):
+        def remove_iptable_rules_having_set_name(setname):
+            chains = IptableChain.from_iptable_lists()
+            for c in chains:
+                for spec, linenum in c.rules.items():
+                    if setname in spec:
+                        c.delete_rule_by_line_number(linenum)
+                        # as line number will change each time after deleting a rule,
+                        # we have to retrieve all chains again
+                        # this shows that old solid tools also have old bad user experience
+                        remove_iptable_rules_having_set_name(setname)
+            return
+                        
+        sets = sglib.ShellCmd('ipset list')()
+        for s in sets.split('\n'):
+            if 'Name:' in s:
+                set_name = s.split(':', 1)[1].strip()
+                if not set_name in sets_to_keep:
+                    remove_iptable_rules_having_set_name(set_name)
+                    sglib.ShellCmd('ipset destroy %s' % set_name)()
+                    cherrypy.log('destroyed unused ipset: %s' % set_name)
+        
+class SGAgent(object):
+    RULE_HISTORY_PTH = '/var/lib/cloudstack/cs-agent.history'
+    
+    def __init__(self):
+        history_dir = os.path.dirname(self.RULE_HISTORY_PTH)
+        if not os.path.exists(history_dir):
+            os.makedirs(history_dir, 0755)
+    
+    def _self_list(self, obj):
+        if isinstance(obj, types.ListType):
+            return obj
+        else:
+            return [obj]
+        
+    def sync(self, req):
+        if not os.path.exists(self.RULE_HISTORY_PTH):
+            return ''
+        
+        with open(self.RULE_HISTORY_PTH, 'r') as fd:
+            history = fd.read()
+        
+        cherrypy.log('sync: %s' % history)
+        return history
+    
+    def create_rule_if_not_exists(self, rule):
+        out = sglib.ShellCmd('iptables-save')()
+        if rule in out:
+            return
+        
+        sglib.ShellCmd('iptables %s' % rule)()
+            
+    @sglib.lock('set_rules')
+    def set_rules(self, req):
+        body = req.body
+        cherrypy.log('received security group rules as:\n%s\n' % body)
+        doc = xmlobject.loads(body)
+        vm_name = doc.vmName.text_
+        vm_id = doc.vmId.text_
+        vm_ip = doc.vmIp.text_
+        vm_mac = doc.vmMac.text_
+        sig = doc.signature.text_
+        seq = doc.sequenceNumber.text_
+        
+        def parse_rules(rules, lst):
+            for i in self._self_list(rules):
+                r = SGRule()
+                r.protocol = i.protocol.text_
+                r.start_port = i.startPort.text_
+                r.end_port = i.endPort.text_
+                if hasattr(i, 'ip'):
+                    for ip in self._self_list(i.ip):
+                        r.allowed_ips.append(ip.text_)
+                lst.append(r)
+            
+        i_rules = []
+        if hasattr(doc, 'ingressRules'):
+            parse_rules(doc.ingressRules, i_rules)
+            
+        e_rules = []
+        if hasattr(doc, 'egressRules'):
+            parse_rules(doc.egressRules, e_rules)
+            
+        def create_chain(name):
+            try:
+                sglib.ShellCmd('iptables -F %s' % name)()
+            except Exception:
+                sglib.ShellCmd('iptables -N %s' % name)()
+        
+        def delete_chain(name):
+            try:
+                sglib.ShellCmd('iptables -F %s' % name)()
+                
+                try:
+                    sglib.ShellCmd('iptables -D INPUT -j %s' % name)()
+                except:
+                    pass
+                
+                try:
+                    sglib.ShellCmd('iptables -D OUTPUT -j %s' % name)()
+                except:
+                    pass
+                
+                try:
+                    sglib.ShellCmd('iptables -D %s -p tcp --dport 9988 -j ACCEPT' % name)()
+                except:
+                    pass
+                
+                sglib.ShellCmd('iptables -X %s' % name)()
+                
+                cherrypy.log('deleted chain %s' % name)
+            except:
+                # safely ignore error
+                pass
+            
+        def apply_rules(rules, chainname, direction, action, current_set_names):
+            for r in rules:
+                allow_any = False
+                if '0.0.0.0/0' in r.allowed_ips:
+                    allow_any = True
+                    r.allowed_ips.remove('0.0.0.0/0')
+                
+                if r.allowed_ips:
+                    setname = '_'.join([chainname, r.protocol, r.start_port, r.end_port])
+                    ipset = IPSet(setname, r.allowed_ips)
+                    ipset.create()
+                    current_set_names.append(setname)
+                    
+                    if r.protocol == 'all':
+                        cmd = ['iptables -I', chainname, '-m state --state NEW -m set --set', setname, direction, '-j', action]
+                        sglib.ShellCmd(' '.join(cmd))()
+                    elif r.protocol != 'icmp':
+                        port_range = ":".join([r.start_port, r.end_port])
+                        cmd = ['iptables', '-I', chainname, '-p', r.protocol, '-m', r.protocol, '--dport', port_range, '-m state --state NEW -m set --set', setname, direction, '-j', action]
+                        sglib.ShellCmd(' '.join(cmd))()
+                    else:
+                        port_range = "/".join([r.start_port, r.end_port])
+                        if r.start_port == "-1":
+                            port_range = "any"
+                        cmd = ['iptables', '-I', chainname, '-p', 'icmp', '--icmp-type', port_range, '-m set --set', setname, direction, '-j', action]
+                        sglib.ShellCmd(' '.join(cmd))()
+                        
+                    
+                if allow_any and r.protocol != 'all':
+                    if r.protocol != 'icmp':
+                        port_range = ":".join([r.start_port, r.end_port])
+                        cmd = ['iptables', '-I', chainname, '-p', r.protocol, '-m', r.protocol, '--dport', port_range, '-m', 'state', '--state', 'NEW', '-j', action]
+                        sglib.ShellCmd(' '.join(cmd))()
+                    else:
+                        port_range = "/".join([r.start_port, r.end_port])
+                        if r.start_port == "-1":
+                            port_range = "any"
+                        cmd = ['iptables', '-I', chainname, '-p', 'icmp', '--icmp-type', port_range, '-j', action]
+                        sglib.ShellCmd(' '.join(cmd))()
+        
+        current_sets = []
+        i_chain_name = vm_name + '-in'
+        if i_rules:
+            create_chain(i_chain_name)
+            self.create_rule_if_not_exists('-A INPUT -j %s' % i_chain_name)
+            sglib.ShellCmd('iptables -A %s -p tcp --dport 9988 -j ACCEPT' % i_chain_name)()
+            sglib.ShellCmd('iptables -A %s -m state --state RELATED,ESTABLISHED -j ACCEPT' % i_chain_name)()
+            apply_rules(i_rules, i_chain_name, 'src', 'ACCEPT', current_sets)
+            sglib.ShellCmd('iptables -A %s -j DROP' % i_chain_name)()
+        else:
+            delete_chain(i_chain_name)
+        
+        e_chain_name = vm_name + '-eg'
+        if e_rules:
+            create_chain(e_chain_name)
+            self.create_rule_if_not_exists('-A OUTPUT -j %s' % e_chain_name)
+            sglib.ShellCmd('iptables -A %s -m state --state RELATED,ESTABLISHED -j RETURN' % e_chain_name)()
+            apply_rules(e_rules, e_chain_name, 'dst', 'RETURN', current_sets)
+            sglib.ShellCmd('iptables -A %s -j DROP' % e_chain_name)
+        else:
+            delete_chain(e_chain_name)
+        
+        IPSet.destroy_sets_not_in(current_sets)
+        
+        history = ','.join([vm_name, vm_id, vm_ip, '_', sig, seq])
+        with open(self.RULE_HISTORY_PTH, 'w') as fd:
+            fd.write(history)
+                
+        
+    def echo(self, req):
+        cherrypy.log("echo: I am alive")
+        
+    def index(self):
+        req = sglib.Request.from_cherrypy_request(cherrypy.request)
+        cmd_name = req.headers['command']
+        
+        if not hasattr(self, cmd_name):
+            raise ValueError("SecurityGroupAgent doesn't have a method called '%s'" % cmd_name)           
+        method = getattr(self, cmd_name)
+        
+        return method(req)
+    index.exposed = True
+    
+    @staticmethod
+    def start():
+        def prepare_default_rules():
+            sglib.ShellCmd('iptables --policy INPUT DROP')()
+            name = 'default-chain'
+            try:
+                sglib.ShellCmd('iptables -F %s' % name)()
+            except Exception:
+                sglib.ShellCmd('iptables -N %s' % name)()
+            sglib.ShellCmd('iptables -I INPUT -p tcp --dport 9988 -j ACCEPT')()
+
+
+        prepare_default_rules()
+        cherrypy.log.access_file = '/var/log/cs-securitygroup.log'
+        cherrypy.log.error_file = '/var/log/cs-securitygroup.log'
+        cherrypy.server.socket_host = '0.0.0.0'
+        cherrypy.server.socket_port = 9988
+        cherrypy.quickstart(SGAgent())
+        
+    @staticmethod 
+    def stop():
+        cherrypy.engine.exit()
+
+PID_FILE = '/var/run/cssgagent.pid'
+class SGAgentDaemon(sglib.Daemon):
+    def __init__(self):
+        super(SGAgentDaemon, self).__init__(PID_FILE)
+        self.is_stopped = False
+        self.agent = SGAgent()
+        sglib.Daemon.register_atexit_hook(self._do_stop)
+    
+    def _do_stop(self):
+        if self.is_stopped:
+            return
+        self.is_stopped = True
+        self.agent.stop()
+    
+    def run(self):
+        self.agent.start()
+        
+    def stop(self):
+        self.agent.stop()
+        super(SGAgentDaemon, self).stop()
+
+def main():
+    usage = 'usage: python -c "from security_group_agent import cs_sg_agent; cs_sg_agent.main()" start|stop|restart'
+    if len(sys.argv) != 2 or not sys.argv[1] in ['start', 'stop', 'restart']:
+        print usage
+        sys.exit(1)
+    
+    cmd = sys.argv[1]
+    agentdaemon = SGAgentDaemon()
+    if cmd == 'start':
+        agentdaemon.start()
+    elif cmd == 'stop':
+        agentdaemon.stop()
+    else:
+        agentdaemon.restart()
+        
+    sys.exit(0)
+        

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d31dcdfd/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/sglib.py
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/sglib.py b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/sglib.py
index bf64eff..b4a39eb 100755
--- a/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/sglib.py
+++ b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/sglib.py
@@ -1,4 +1,3 @@
-#!/usr/bin/env python
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
 # distributed with this work for additional information
@@ -18,13 +17,55 @@
 # 
 # Automatically generated by addcopyright.py at 01/29/2013
 
-import sys, os, time, atexit
-import traceback
+#!/usr/bin/env python
+
+import sys, os, time, atexit
+import traceback
 import subprocess
-from signal import SIGTERM 
+from signal import SIGTERM,SIGKILL
 import cherrypy
 import copy
 
+import weakref
+import threading
+import functools
+
+_internal_lock = threading.RLock()
+_locks = weakref.WeakValueDictionary()
+
+def _get_lock(name):
+    with _internal_lock:
+        lock = _locks.get(name, threading.RLock())
+        if not name in _locks:
+            _locks[name] = lock
+        return lock
+
+class NamedLock(object):
+    def __init__(self, name):
+        self.name = name
+        self.lock = None
+    
+    def __enter__(self):
+        self.lock = _get_lock(self.name)
+        self.lock.acquire()
+        #logger.debug('%s got lock %s' % (threading.current_thread().name, self.name))
+    
+    def __exit__(self, type, value, traceback):
+        self.lock.release()
+        #logger.debug('%s released lock %s' % (threading.current_thread().name, self.name))
+    
+
+def lock(name='defaultLock'):
+    def wrap(f):
+        @functools.wraps(f)
+        def inner(*args, **kwargs):
+            with NamedLock(name):
+                retval = f(*args, **kwargs)
+            return retval
+        return inner
+    return wrap
+
+
 class Request(object):
     def __init__(self):
         self.headers = None
@@ -80,28 +121,28 @@ class Daemon(object):
     A generic daemon class.
     
     Usage: subclass the Daemon class and override the run() method
-    """
-    atexit_hooks = []
+    """
+    atexit_hooks = []
     
     def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
         self.stdin = stdin
         self.stdout = stdout
         self.stderr = stderr
         self.pidfile = pidfile
-    
-    @staticmethod
-    def register_atexit_hook(hook):
-        Daemon.atexit_hooks.append(hook)
-        
+    
     @staticmethod
-    def _atexit():
-        for hook in Daemon.atexit_hooks:
-            try:
+    def register_atexit_hook(hook):
+        Daemon.atexit_hooks.append(hook)
+        
+    @staticmethod
+    def _atexit():
+        for hook in Daemon.atexit_hooks:
+            try:
                 hook()
-            except Exception:
+            except Exception:
                 content = traceback.format_exc()
-                err = 'Exception when calling atexit hook[%s]\n%s' % (hook.__name__, content)
-                #logger.error(err)
+                err = 'Exception when calling atexit hook[%s]\n%s' % (hook.__name__, content)
+                #logger.error(err)
                 
     def daemonize(self):
         """
@@ -145,7 +186,7 @@ class Daemon(object):
     
         # write pidfile
         Daemon.register_atexit_hook(self.delpid)
-        atexit.register(Daemon._atexit)
+        atexit.register(Daemon._atexit)
         pid = str(os.getpid())
         file(self.pidfile,'w').write("%s\n" % pid)
     
@@ -173,12 +214,12 @@ class Daemon(object):
                 sys.exit(0)
         
         # Start the daemon
-        self.daemonize()
+        self.daemonize()
         try:
-            self.run()
-        except Exception:
-            content = traceback.format_exc()
-            #logger.error(content)
+            self.run()
+        except Exception:
+            content = traceback.format_exc()
+            #logger.error(content)
             sys.exit(1)
 
     def stop(self):
@@ -192,25 +233,29 @@ class Daemon(object):
             pf.close()
         except IOError:
             pid = None
-    
+
         if not pid:
             message = "pidfile %s does not exist. Daemon not running?\n"
             sys.stderr.write(message % self.pidfile)
             return # not an error in a restart
 
         # Try killing the daemon process    
-        try:
-            while 1:
-                os.kill(pid, SIGTERM)
-                time.sleep(0.1)
-        except OSError, err:
-            err = str(err)
-            if err.find("No such process") > 0:
-                if os.path.exists(self.pidfile):
-                    os.remove(self.pidfile)
+        wait_stop = 5
+        start_time = time.time()
+        while 1:
+            if os.path.exists('/proc/' + str(pid)):
+                curr_time = time.time()
+                if (curr_time - start_time) > wait_stop:
+                    os.kill(pid, SIGKILL)
+                else:
+                    os.kill(pid, SIGTERM)
+                time.sleep(0.3)
             else:
-                print str(err)
-                sys.exit(1)
+                if os.path.exists(self.pidfile):
+                    self.delpid()
+                break
+
+        print "Stop Daemon Successfully"
 
     def restart(self):
         """

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d31dcdfd/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
index d46048e..f4e4463 100755
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
@@ -29,35 +29,12 @@ import java.util.Map;
 import javax.ejb.Local;
 import javax.naming.ConfigurationException;
 
+import com.cloud.agent.api.*;
+import com.cloud.utils.Pair;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.log4j.Logger;
 
 import com.cloud.agent.IAgentControl;
-import com.cloud.agent.api.Answer;
-import com.cloud.agent.api.CheckNetworkAnswer;
-import com.cloud.agent.api.CheckNetworkCommand;
-import com.cloud.agent.api.CheckVirtualMachineAnswer;
-import com.cloud.agent.api.CheckVirtualMachineCommand;
-import com.cloud.agent.api.Command;
-import com.cloud.agent.api.MaintainAnswer;
-import com.cloud.agent.api.MaintainCommand;
-import com.cloud.agent.api.MigrateAnswer;
-import com.cloud.agent.api.MigrateCommand;
-import com.cloud.agent.api.PingCommand;
-import com.cloud.agent.api.PingRoutingCommand;
-import com.cloud.agent.api.PrepareForMigrationAnswer;
-import com.cloud.agent.api.PrepareForMigrationCommand;
-import com.cloud.agent.api.ReadyAnswer;
-import com.cloud.agent.api.ReadyCommand;
-import com.cloud.agent.api.RebootAnswer;
-import com.cloud.agent.api.RebootCommand;
-import com.cloud.agent.api.SecurityGroupRulesCmd;
-import com.cloud.agent.api.StartAnswer;
-import com.cloud.agent.api.StartCommand;
-import com.cloud.agent.api.StartupCommand;
-import com.cloud.agent.api.StartupRoutingCommand;
-import com.cloud.agent.api.StopAnswer;
-import com.cloud.agent.api.StopCommand;
 import com.cloud.agent.api.baremetal.IpmISetBootDevCommand;
 import com.cloud.agent.api.baremetal.IpmISetBootDevCommand.BootDev;
 import com.cloud.agent.api.baremetal.IpmiBootorResetCommand;
@@ -373,7 +350,21 @@ public class BareMetalResourceBase extends ManagerBase implements ServerResource
 			return null;
 		}
 
-		return new PingRoutingCommand(getType(), id, deltaSync());
+
+        if (hostId != null) {
+            vmDao = ComponentContext.getComponent(VMInstanceDao.class);
+            final List<? extends VMInstanceVO> vms = vmDao.listByHostId(hostId);
+            if (vms.isEmpty()) {
+                return new PingRoutingCommand(getType(), id, deltaSync());
+            } else {
+                VMInstanceVO vm = vms.get(0);
+                SecurityGroupHttpClient client = new SecurityGroupHttpClient();
+                HashMap<String, Pair<Long, Long>> nwGrpStates = client.sync(vm.getInstanceName(), vm.getId(), vm.getPrivateIpAddress());
+                return new PingRoutingWithNwGroupsCommand(getType(), id, null, nwGrpStates);
+            }
+        } else {
+            return new PingRoutingCommand(getType(), id, deltaSync());
+        }
 	}
 
 	protected Answer execute(IpmISetBootDevCommand cmd) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d31dcdfd/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java
index b9c2e84..8e27a44 100755
--- a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java
@@ -1,38 +1,221 @@
-// Licensed to the Apache Software Foundation (ASF) under one
-// or more contributor license agreements.  See the NOTICE file
-// distributed with this work for additional information
-// regarding copyright ownership.  The ASF licenses this file
-// to you under the Apache License, Version 2.0 (the
-// "License"); you may not use this file except in compliance
-// with the License.  You may obtain a copy of the License at
-//
-//   http://www.apache.org/licenses/LICENSE-2.0
-//
-// Unless required by applicable law or agreed to in writing,
-// software distributed under the License is distributed on an
-// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-// KIND, either express or implied.  See the License for the
-// specific language governing permissions and limitations
-// under the License.
-//
-// Automatically generated by addcopyright.py at 01/29/2013
-// Apache License, Version 2.0 (the "License"); you may not use this
-// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-package com.cloud.baremetal.networkservice;
-
-import com.cloud.agent.api.Answer;
-import com.cloud.agent.api.SecurityGroupRulesCmd;
-
-public class SecurityGroupHttpClient {
-
-	public Answer call(String guestIp, SecurityGroupRulesCmd cmd) {
-		// TODO Auto-generated method stub
-		return null;
-	}
-
-	public boolean echo(String ip, long millis, long millis2) {
-		// TODO Auto-generated method stub
-		return false;
-	}
-
-}
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+//
+// Automatically generated by addcopyright.py at 01/29/2013
+// Apache License, Version 2.0 (the "License"); you may not use this
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+//
+// Automatically generated by addcopyright.py at 04/03/2012
+
+package com.cloud.baremetal.networkservice;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.net.SocketTimeoutException;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.zip.DeflaterOutputStream;
+
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Marshaller;
+
+import com.cloud.agent.api.SecurityGroupRuleAnswer;
+import com.cloud.agent.api.SecurityGroupRulesCmd;
+import com.cloud.agent.api.SecurityGroupRulesCmd.IpPortAndProto;
+import com.cloud.baremetal.networkservice.schema.SecurityGroupRule;
+import com.cloud.baremetal.networkservice.schema.SecurityGroupVmRuleSet;
+import com.cloud.utils.Pair;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.net.NetUtils;
+
+import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
+import org.apache.commons.httpclient.methods.PostMethod;
+import org.apache.commons.httpclient.methods.StringRequestEntity;
+import org.apache.http.params.BasicHttpParams;
+import org.apache.http.params.HttpConnectionParams;
+import org.apache.http.params.HttpParams;
+import org.apache.log4j.Logger;
+
+public class SecurityGroupHttpClient {
+    private static final Logger logger = Logger.getLogger(SecurityGroupHttpClient.class);
+	private static final String ARG_NAME = "args";
+	private static final String COMMAND = "command";
+	private JAXBContext context;
+	private int port;
+	private static HttpClient httpClient;
+	
+	static {
+	    MultiThreadedHttpConnectionManager connman = new MultiThreadedHttpConnectionManager();
+	    httpClient = new HttpClient(connman);
+        httpClient.setConnectionTimeout(5000);
+	}
+
+	private enum OpConstant {
+		setRules, echo,
+	}
+
+	public SecurityGroupHttpClient() {
+		try {
+			context = JAXBContext.newInstance(SecurityGroupRule.class, SecurityGroupVmRuleSet.class);
+			port = 9988;
+		} catch (Exception e) {
+			throw new CloudRuntimeException(
+					"Unable to create JAXBContext for security group", e);
+		}
+	}
+
+	private List<SecurityGroupRule> generateRules(IpPortAndProto[] ipps) {
+		List<SecurityGroupRule> rules = new ArrayList<SecurityGroupRule>(
+				ipps.length);
+		for (SecurityGroupRulesCmd.IpPortAndProto ipp : ipps) {
+			SecurityGroupRule r = new SecurityGroupRule();
+			r.setProtocol(ipp.getProto());
+			r.setStartPort(ipp.getStartPort());
+			r.setEndPort(ipp.getEndPort());
+			for (String cidr : ipp.getAllowedCidrs()) {
+				r.getIp().add(cidr);
+			}
+			rules.add(r);
+		}
+		return rules;
+	}
+
+	public HashMap<String, Pair<Long, Long>> sync(String vmName, Long vmId, String agentIp) {
+	    HashMap<String, Pair<Long, Long>> states = new HashMap<String, Pair<Long, Long>>();
+	    
+	    PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort()));
+	    try {
+	        post.addRequestHeader("command", "sync");
+            if (httpClient.executeMethod(post) != 200) {
+                logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString()));
+            } else {
+                String res = post.getResponseBodyAsString();
+                // res = ';'.join([vmName, vmId, seqno])
+                String[] rulelogs = res.split(",");
+                if (rulelogs.length != 6) {
+                    logger.debug(String.format("host[%s] returns invalid security group sync document[%s], reset rules", agentIp, res));
+                    states.put(vmName, new Pair<Long, Long>(vmId, -1L));
+                    return states;
+                }
+                
+                Pair<Long, Long> p = new Pair<Long, Long>(Long.valueOf(rulelogs[1]), Long.valueOf(rulelogs[5]));
+                states.put(rulelogs[0], p);
+                return states;
+            }
+        } catch (SocketTimeoutException se) {
+            logger.warn(String.format("unable to sync security group rules on host[%s], %s", agentIp, se.getMessage()));
+        } catch (Exception e) {
+            logger.warn(String.format("unable to sync security group rules on host[%s]", agentIp), e);
+        } finally {
+            if (post != null) {
+                post.releaseConnection();
+            }
+        }
+	    return states;
+	}
+	
+    public boolean echo(String agentIp, long l, long m) {
+        boolean ret = false;
+        int count = 1;
+        while (true) {
+            try {
+                Thread.sleep(m);
+                count++;
+            } catch (InterruptedException e1) {
+                logger.warn("", e1);
+                break;
+            }
+            
+            PostMethod post = new PostMethod(String.format("http://%s:%s/", agentIp, getPort()));
+            try {
+                post.addRequestHeader("command", "echo");
+                if (httpClient.executeMethod(post) != 200) {
+                    logger.debug(String.format("echoing baremetal security group agent on %s got error: %s", agentIp, post.getResponseBodyAsString()));
+                } else {
+                    ret = true;
+                }
+                break;
+            } catch (Exception e) {
+                if (count*m >= l) {
+                    logger.debug(String.format("ping security group agent on vm[%s] timeout after %s minutes, starting vm failed, count=%s", agentIp, TimeUnit.MILLISECONDS.toSeconds(l), count));
+                    break;
+                } else {
+                    logger.debug(String.format("Having pinged security group agent on vm[%s] %s times, continue to wait...", agentIp, count));
+                }
+            } finally {
+                if (post != null) {
+                    post.releaseConnection();
+                }
+            }
+        }
+        return ret;
+    }
+	
+	public SecurityGroupRuleAnswer call(String agentIp,
+			SecurityGroupRulesCmd cmd) {
+		PostMethod post = new PostMethod(String.format(
+		        "http://%s:%s", agentIp, getPort()));
+		try {
+			SecurityGroupVmRuleSet rset = new SecurityGroupVmRuleSet();
+			rset.getEgressRules().addAll(generateRules(cmd.getEgressRuleSet()));
+			rset.getIngressRules().addAll(
+					generateRules(cmd.getIngressRuleSet()));
+			rset.setVmName(cmd.getVmName());
+			rset.setVmIp(cmd.getGuestIp());
+			rset.setVmMac(cmd.getGuestMac());
+			rset.setVmId(cmd.getVmId());
+			rset.setSignature(cmd.getSignature());
+			rset.setSequenceNumber(cmd.getSeqNum());
+			Marshaller marshaller = context.createMarshaller();
+			StringWriter writer = new StringWriter();
+			marshaller.marshal(rset, writer);
+			String xmlContents = writer.toString();
+			logger.debug(xmlContents);
+
+			post.addRequestHeader("command", "set_rules");
+			StringRequestEntity entity = new StringRequestEntity(xmlContents);
+			post.setRequestEntity(entity);
+			if (httpClient.executeMethod(post) != 200) {
+				return new SecurityGroupRuleAnswer(cmd, false,
+						post.getResponseBodyAsString());
+			} else {
+				return new SecurityGroupRuleAnswer(cmd);
+			}
+		} catch (Exception e) {
+			return new SecurityGroupRuleAnswer(cmd, false, e.getMessage());
+		} finally {
+		    if (post != null) {
+		        post.releaseConnection();
+		    }
+		}
+	}
+
+	public int getPort() {
+		return port;
+	}
+
+	public void setPort(int port) {
+		this.port = port;
+	}
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d31dcdfd/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/ObjectFactory.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/ObjectFactory.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/ObjectFactory.java
new file mode 100644
index 0000000..d0944ce
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/ObjectFactory.java
@@ -0,0 +1,55 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.07.11 at 03:24:15 PM PDT 
+//
+
+
+package com.cloud.baremetal.networkservice.schema;
+
+import javax.xml.bind.annotation.XmlRegistry;
+
+
+/**
+ * This object contains factory methods for each 
+ * Java content interface and Java element interface 
+ * generated in the com.cloud.network.security.schema package. 
+ * <p>An ObjectFactory allows you to programatically 
+ * construct new instances of the Java representation 
+ * for XML content. The Java representation of XML 
+ * content can consist of schema derived interfaces 
+ * and classes representing the binding of schema 
+ * type definitions, element declarations and model 
+ * groups.  Factory methods for each of these are 
+ * provided in this class.
+ * 
+ */
+@XmlRegistry
+public class ObjectFactory {
+
+
+    /**
+     * Create a new ObjectFactory that can be used to create new instances of schema derived classes for package: com.cloud.network.security.schema
+     * 
+     */
+    public ObjectFactory() {
+    }
+
+    /**
+     * Create an instance of {@link SecurityGroupRule }
+     * 
+     */
+    public SecurityGroupRule createSecurityGroupRule() {
+        return new SecurityGroupRule();
+    }
+
+    /**
+     * Create an instance of {@link SecurityGroupVmRuleSet }
+     * 
+     */
+    public SecurityGroupVmRuleSet createSecurityGroupVmRuleSet() {
+        return new SecurityGroupVmRuleSet();
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d31dcdfd/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupRule.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupRule.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupRule.java
new file mode 100644
index 0000000..a8958dd
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupRule.java
@@ -0,0 +1,146 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.07.11 at 03:24:15 PM PDT 
+//
+
+
+package com.cloud.baremetal.networkservice.schema;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlSchemaType;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for SecurityGroupRule complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType name="SecurityGroupRule">
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="protocol" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         &lt;element name="startPort" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
+ *         &lt;element name="endPort" type="{http://www.w3.org/2001/XMLSchema}unsignedInt"/>
+ *         &lt;sequence maxOccurs="unbounded" minOccurs="0">
+ *           &lt;element name="ip" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         &lt;/sequence>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "SecurityGroupRule", propOrder = {
+    "protocol",
+    "startPort",
+    "endPort",
+    "ip"
+})
+public class SecurityGroupRule {
+
+    @XmlElement(required = true)
+    protected String protocol;
+    @XmlSchemaType(name = "unsignedInt")
+    protected long startPort;
+    @XmlSchemaType(name = "unsignedInt")
+    protected long endPort;
+    protected List<String> ip;
+
+    /**
+     * Gets the value of the protocol property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getProtocol() {
+        return protocol;
+    }
+
+    /**
+     * Sets the value of the protocol property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setProtocol(String value) {
+        this.protocol = value;
+    }
+
+    /**
+     * Gets the value of the startPort property.
+     * 
+     */
+    public long getStartPort() {
+        return startPort;
+    }
+
+    /**
+     * Sets the value of the startPort property.
+     * 
+     */
+    public void setStartPort(long value) {
+        this.startPort = value;
+    }
+
+    /**
+     * Gets the value of the endPort property.
+     * 
+     */
+    public long getEndPort() {
+        return endPort;
+    }
+
+    /**
+     * Sets the value of the endPort property.
+     * 
+     */
+    public void setEndPort(long value) {
+        this.endPort = value;
+    }
+
+    /**
+     * Gets the value of the ip property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the ip property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getIp().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link String }
+     * 
+     * 
+     */
+    public List<String> getIp() {
+        if (ip == null) {
+            ip = new ArrayList<String>();
+        }
+        return this.ip;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d31dcdfd/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupVmRuleSet.java
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupVmRuleSet.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupVmRuleSet.java
new file mode 100644
index 0000000..7ad13ce
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/schema/SecurityGroupVmRuleSet.java
@@ -0,0 +1,263 @@
+//
+// This file was generated by the JavaTM Architecture for XML Binding(JAXB) Reference Implementation, vJAXB 2.1.10 
+// See <a href="http://java.sun.com/xml/jaxb">http://java.sun.com/xml/jaxb</a> 
+// Any modifications to this file will be lost upon recompilation of the source schema. 
+// Generated on: 2012.07.11 at 03:24:15 PM PDT 
+//
+
+
+package com.cloud.baremetal.networkservice.schema;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import javax.xml.bind.annotation.XmlType;
+
+
+/**
+ * <p>Java class for anonymous complex type.
+ * 
+ * <p>The following schema fragment specifies the expected content contained within this class.
+ * 
+ * <pre>
+ * &lt;complexType>
+ *   &lt;complexContent>
+ *     &lt;restriction base="{http://www.w3.org/2001/XMLSchema}anyType">
+ *       &lt;sequence>
+ *         &lt;element name="vmName" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         &lt;element name="vmId" type="{http://www.w3.org/2001/XMLSchema}long"/>
+ *         &lt;element name="vmIp" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         &lt;element name="vmMac" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         &lt;element name="signature" type="{http://www.w3.org/2001/XMLSchema}string"/>
+ *         &lt;element name="sequenceNumber" type="{http://www.w3.org/2001/XMLSchema}long"/>
+ *         &lt;sequence maxOccurs="unbounded" minOccurs="0">
+ *           &lt;element name="ingressRules" type="{}SecurityGroupRule"/>
+ *         &lt;/sequence>
+ *         &lt;sequence maxOccurs="unbounded" minOccurs="0">
+ *           &lt;element name="egressRules" type="{}SecurityGroupRule"/>
+ *         &lt;/sequence>
+ *       &lt;/sequence>
+ *     &lt;/restriction>
+ *   &lt;/complexContent>
+ * &lt;/complexType>
+ * </pre>
+ * 
+ * 
+ */
+@XmlAccessorType(XmlAccessType.FIELD)
+@XmlType(name = "", propOrder = {
+    "vmName",
+    "vmId",
+    "vmIp",
+    "vmMac",
+    "signature",
+    "sequenceNumber",
+    "ingressRules",
+    "egressRules"
+})
+@XmlRootElement(name = "SecurityGroupVmRuleSet")
+public class SecurityGroupVmRuleSet {
+
+    @XmlElement(required = true)
+    protected String vmName;
+    protected long vmId;
+    @XmlElement(required = true)
+    protected String vmIp;
+    @XmlElement(required = true)
+    protected String vmMac;
+    @XmlElement(required = true)
+    protected String signature;
+    protected long sequenceNumber;
+    protected List<SecurityGroupRule> ingressRules;
+    protected List<SecurityGroupRule> egressRules;
+
+    /**
+     * Gets the value of the vmName property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getVmName() {
+        return vmName;
+    }
+
+    /**
+     * Sets the value of the vmName property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setVmName(String value) {
+        this.vmName = value;
+    }
+
+    /**
+     * Gets the value of the vmId property.
+     * 
+     */
+    public long getVmId() {
+        return vmId;
+    }
+
+    /**
+     * Sets the value of the vmId property.
+     * 
+     */
+    public void setVmId(long value) {
+        this.vmId = value;
+    }
+
+    /**
+     * Gets the value of the vmIp property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getVmIp() {
+        return vmIp;
+    }
+
+    /**
+     * Sets the value of the vmIp property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setVmIp(String value) {
+        this.vmIp = value;
+    }
+
+    /**
+     * Gets the value of the vmMac property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getVmMac() {
+        return vmMac;
+    }
+
+    /**
+     * Sets the value of the vmMac property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setVmMac(String value) {
+        this.vmMac = value;
+    }
+
+    /**
+     * Gets the value of the signature property.
+     * 
+     * @return
+     *     possible object is
+     *     {@link String }
+     *     
+     */
+    public String getSignature() {
+        return signature;
+    }
+
+    /**
+     * Sets the value of the signature property.
+     * 
+     * @param value
+     *     allowed object is
+     *     {@link String }
+     *     
+     */
+    public void setSignature(String value) {
+        this.signature = value;
+    }
+
+    /**
+     * Gets the value of the sequenceNumber property.
+     * 
+     */
+    public long getSequenceNumber() {
+        return sequenceNumber;
+    }
+
+    /**
+     * Sets the value of the sequenceNumber property.
+     * 
+     */
+    public void setSequenceNumber(long value) {
+        this.sequenceNumber = value;
+    }
+
+    /**
+     * Gets the value of the ingressRules property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the ingressRules property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getIngressRules().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link SecurityGroupRule }
+     * 
+     * 
+     */
+    public List<SecurityGroupRule> getIngressRules() {
+        if (ingressRules == null) {
+            ingressRules = new ArrayList<SecurityGroupRule>();
+        }
+        return this.ingressRules;
+    }
+
+    /**
+     * Gets the value of the egressRules property.
+     * 
+     * <p>
+     * This accessor method returns a reference to the live list,
+     * not a snapshot. Therefore any modification you make to the
+     * returned list will be present inside the JAXB object.
+     * This is why there is not a <CODE>set</CODE> method for the egressRules property.
+     * 
+     * <p>
+     * For example, to add a new item, do as follows:
+     * <pre>
+     *    getEgressRules().add(newItem);
+     * </pre>
+     * 
+     * 
+     * <p>
+     * Objects of the following type(s) are allowed in the list
+     * {@link SecurityGroupRule }
+     * 
+     * 
+     */
+    public List<SecurityGroupRule> getEgressRules() {
+        if (egressRules == null) {
+            egressRules = new ArrayList<SecurityGroupRule>();
+        }
+        return this.egressRules;
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/d31dcdfd/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 7da0751..567bd60 100644
--- a/pom.xml
+++ b/pom.xml
@@ -510,7 +510,9 @@
       </properties>
       <modules>
         <module>developer</module>
+        <!--
         <module>tools</module>
+-->
       </modules>
     </profile>
     <profile>