CloudStack CLOUDSTACK-774
Supporting kickstart in CloudStack baremetal

merge baremetal feature to master
diff --git a/api/src/com/cloud/event/EventTypes.java b/api/src/com/cloud/event/EventTypes.java
index 87eddca..63b7cd0 100755
--- a/api/src/com/cloud/event/EventTypes.java
+++ b/api/src/com/cloud/event/EventTypes.java
@@ -313,4 +313,10 @@
     public static final String EVENT_AUTOSCALEVMGROUP_UPDATE = "AUTOSCALEVMGROUP.UPDATE";
     public static final String EVENT_AUTOSCALEVMGROUP_ENABLE = "AUTOSCALEVMGROUP.ENABLE";
     public static final String EVENT_AUTOSCALEVMGROUP_DISABLE = "AUTOSCALEVMGROUP.DISABLE";
+    
+    public static final String EVENT_BAREMETAL_DHCP_SERVER_ADD = "PHYSICAL.DHCP.ADD";
+    public static final String EVENT_BAREMETAL_DHCP_SERVER_DELETE = "PHYSICAL.DHCP.DELETE";
+    
+    public static final String EVENT_BAREMETAL_PXE_SERVER_ADD = "PHYSICAL.PXE.ADD";
+    public static final String EVENT_BAREMETAL_PXE_SERVER_DELETE = "PHYSICAL.PXE.DELETE";
 }
diff --git a/api/src/com/cloud/host/Host.java b/api/src/com/cloud/host/Host.java
index bd26f81..7236680 100755
--- a/api/src/com/cloud/host/Host.java
+++ b/api/src/com/cloud/host/Host.java
@@ -39,6 +39,8 @@
         ExternalLoadBalancer(false),
         ExternalVirtualSwitchSupervisor(false),
         PxeServer(false),
+        BaremetalPxe(false),
+        BaremetalDhcp(false),
         TrafficMonitor(false),
 
         ExternalDhcp(false),
diff --git a/api/src/org/apache/cloudstack/api/ApiConstants.java b/api/src/org/apache/cloudstack/api/ApiConstants.java
old mode 100644
new mode 100755
index 58a7831..d084271
--- a/api/src/org/apache/cloudstack/api/ApiConstants.java
+++ b/api/src/org/apache/cloudstack/api/ApiConstants.java
@@ -427,6 +427,7 @@
     public static final String CONDITION_IDS = "conditionids";
     public static final String COUNTERPARAM_LIST = "counterparam";
     public static final String AUTOSCALE_USER_ID = "autoscaleuserid";
+    public static final String BAREMETAL_DISCOVER_NAME = "baremetaldiscovername";
 
     public enum HostDetails {
         all, capacity, events, stats, min;
diff --git a/plugins/hypervisors/baremetal/pom.xml b/plugins/hypervisors/baremetal/pom.xml
new file mode 100755
index 0000000..600eedb
--- /dev/null
+++ b/plugins/hypervisors/baremetal/pom.xml
@@ -0,0 +1,37 @@
+<!--

+  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.

+-->

+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

+  <modelVersion>4.0.0</modelVersion>

+  <parent>

+    <groupId>org.apache.cloudstack</groupId>

+    <artifactId>cloudstack-plugins</artifactId>

+    <version>4.1.0-SNAPSHOT</version>

+    <relativePath>../../pom.xml</relativePath>

+  </parent>

+  <artifactId>cloud-plugin-hypervisor-baremetal</artifactId>

+  <name>Apache CloudStack Plugin - Hypervisor Baremetal</name>

+  <dependencies>

+  	<dependency>

+		<groupId>commons-lang</groupId>

+		<artifactId>commons-lang</artifactId>

+		<version>2.6</version>

+	</dependency>

+   </dependencies>

+            

+</project>

diff --git a/plugins/hypervisors/baremetal/resources/security_group_agent/cs-sgagent b/plugins/hypervisors/baremetal/resources/security_group_agent/cs-sgagent
new file mode 100755
index 0000000..cda7017
--- /dev/null
+++ b/plugins/hypervisors/baremetal/resources/security_group_agent/cs-sgagent
@@ -0,0 +1,51 @@
+#!/bin/sh
+
+# the following is chkconfig init header
+#
+# cs-sgagent:  cloudStack baremetal sercurity group agent
+#
+# chkconfig: 345 97 03
+# description:  This is a daemon instructed by CloudStack management server \
+#               to perform baremetal security group related operations\
+#
+# processname: cs-sgagent
+# pidfile: /var/run/cssgagent.pid
+#
+
+check_status() {
+	pidfile='/var/run/cssgagent.pid'
+	if [ ! -f $pidfile ]; then
+		echo "cloudstack baremetal security group agent is stopped"
+		exit 1
+	else
+		pid=`cat $pidfile`
+		ps -p $pid > /dev/null
+		if [ $? -eq 0 ]; then
+			echo "cloudstack baremetal security group agent is running, pid is $pid"
+			exit 0
+		else
+			echo "cloudstack baremetal security group agent is stopped, but pidfile at $pidfile is not cleaned. It may be caused by the agent crashed at last time, manually cleaning it would be ok"
+			exit 1
+		fi
+	fi
+}
+
+if [ $# -eq 0 ]; then
+	echo "usage: $0
+[start|stop|restart|status]"
+	exit 1
+fi
+
+if [ "$@" = "status" ]; then
+	check_status
+else
+    python -c "from security_group_agent import cs_sg_agent; cs_sg_agent.main()" $@
+fi
+
+if [ $? -eq 0 ]; then
+    echo "$@ cloudstack baremetal security group agent .... SUCCESS"
+    exit 0
+else
+    echo "$@ cloudstack baremetal security group agent .... FAILED"
+    exit 1
+fi
diff --git a/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/__init__.py b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/__init__.py
new file mode 100644
index 0000000..f7f5f60
--- /dev/null
+++ b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/__init__.py
@@ -0,0 +1,18 @@
+# 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
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
new file mode 100755
index 0000000..a292c0b
--- /dev/null
+++ b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/cs_sg_agent.py
@@ -0,0 +1,237 @@
+# 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
+'''

+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
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
new file mode 100755
index 0000000..bf64eff
--- /dev/null
+++ b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/sglib.py
@@ -0,0 +1,226 @@
+#!/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
+# 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
+
+import sys, os, time, atexit

+import traceback

+import subprocess
+from signal import SIGTERM 

+import cherrypy
+import copy
+
+class Request(object):
+    def __init__(self):
+        self.headers = None
+        self.body = None
+        self.method = None
+        self.query_string = None
+    
+    @staticmethod
+    def from_cherrypy_request(creq):
+        req = Request()
+        req.headers = copy.copy(creq.headers)
+        req.body = creq.body.fp.read() if creq.body else None
+        req.method = copy.copy(creq.method)
+        req.query_string = copy.copy(creq.query_string) if creq.query_string else None
+        return req
+    
+class ShellError(Exception):
+    '''shell error'''
+    
+class ShellCmd(object):
+    '''
+    classdocs
+    '''
+    def __init__(self, cmd, workdir=None, pipe=True):
+        '''
+        Constructor
+        '''
+        self.cmd = cmd
+        if pipe:
+            self.process = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE, executable='/bin/sh', cwd=workdir)
+        else:
+            self.process = subprocess.Popen(cmd, shell=True, executable='/bin/sh', cwd=workdir)
+            
+        self.stdout = None
+        self.stderr = None
+        self.return_code = None
+        
+    def __call__(self, is_exception=True):
+        (self.stdout, self.stderr) = self.process.communicate()
+        if is_exception and self.process.returncode != 0:
+            err = []
+            err.append('failed to execute shell command: %s' % self.cmd)
+            err.append('return code: %s' % self.process.returncode)
+            err.append('stdout: %s' % self.stdout)
+            err.append('stderr: %s' % self.stderr)
+            raise ShellError('\n'.join(err))
+            
+        self.return_code = self.process.returncode
+        return self.stdout
+
+class Daemon(object):
+    """
+    A generic daemon class.
+    
+    Usage: subclass the Daemon class and override the run() method
+    """

+    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:

+                hook()
+            except Exception:

+                content = traceback.format_exc()
+                err = 'Exception when calling atexit hook[%s]\n%s' % (hook.__name__, content)

+                #logger.error(err)

+                
+    def daemonize(self):
+        """
+        do the UNIX double-fork magic, see Stevens' "Advanced 
+        Programming in the UNIX Environment" for details (ISBN 0201563177)
+        http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
+        """
+        try: 
+            pid = os.fork() 
+            if pid > 0:
+                # exit first parent
+                sys.exit(0) 
+        except OSError, e: 
+            sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
+            sys.exit(1)
+    
+        # decouple from parent environment
+        os.chdir("/") 
+        os.setsid() 
+        os.umask(0) 
+    
+        # do second fork
+        try: 
+            pid = os.fork() 
+            if pid > 0:
+                # exit from second parent
+                sys.exit(0) 
+        except OSError, e: 
+            sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
+            sys.exit(1) 
+    
+        # redirect standard file descriptors
+        sys.stdout.flush()
+        sys.stderr.flush()
+        si = file(self.stdin, 'r')
+        so = file(self.stdout, 'a+')
+        se = file(self.stderr, 'a+', 0)
+        os.dup2(si.fileno(), sys.stdin.fileno())
+        os.dup2(so.fileno(), sys.stdout.fileno())
+        os.dup2(se.fileno(), sys.stderr.fileno())
+    
+        # write pidfile
+        Daemon.register_atexit_hook(self.delpid)
+        atexit.register(Daemon._atexit)

+        pid = str(os.getpid())
+        file(self.pidfile,'w').write("%s\n" % pid)
+    
+    def delpid(self):
+        os.remove(self.pidfile)
+
+    def start(self):
+        """
+        Start the daemon
+        """
+        # Check for a pidfile to see if the daemon already runs
+        try:
+            pf = file(self.pidfile,'r')
+            pid = int(pf.read().strip())
+            pf.close()
+        except IOError:
+            pid = None
+    
+        if pid:
+            pscmd = ShellCmd('ps -p %s > /dev/null' % pid)
+            pscmd(is_exception=False)
+            if pscmd.return_code == 0:
+                message = "Daemon already running, pid is %s\n"
+                sys.stderr.write(message % pid)
+                sys.exit(0)
+        
+        # Start the daemon
+        self.daemonize()

+        try:
+            self.run()

+        except Exception:

+            content = traceback.format_exc()

+            #logger.error(content)

+            sys.exit(1)
+
+    def stop(self):
+        """
+        Stop the daemon
+        """
+        # Get the pid from the pidfile
+        try:
+            pf = file(self.pidfile,'r')
+            pid = int(pf.read().strip())
+            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)
+            else:
+                print str(err)
+                sys.exit(1)
+
+    def restart(self):
+        """
+        Restart the daemon
+        """
+        self.stop()
+        self.start()
+
+    def run(self):
+        """
+        You should override this method when you subclass Daemon. It will be called after the process has been
+        daemonized by start() or restart().
+        """
diff --git a/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/xmlobject.py b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/xmlobject.py
new file mode 100755
index 0000000..cb66d26
--- /dev/null
+++ b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/xmlobject.py
@@ -0,0 +1,97 @@
+# 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
+'''

+Created on Dec 25, 2012

+

+@author: Frank

+'''

+import xml.etree.ElementTree as etree

+import re

+import types

+

+class XmlObject(object):

+    def __init__(self, tag):

+        self.__tag_name__ = tag

+    

+    def put_attr(self, name, val):

+        val = val.strip().strip('\t')

+        setattr(self, name + '_', val)

+    

+    def put_text(self, val):

+        val = val.strip().strip('\n').strip('\t')

+        if val == "":

+            setattr(self, 'text_', None)

+        else:

+            setattr(self, 'text_', val)

+    

+    def put_node(self, name, val):

+        if not hasattr(self, name):

+            setattr(self, name, val)

+            return

+            

+        nodes = getattr(self, name)

+        if not isinstance(nodes, types.ListType):

+            nodes = []

+            old = getattr(self, name)

+            nodes.append(old)

+            nodes.append(val)

+            setattr(self, name, nodes)

+        else:

+            nodes.append(val)

+            setattr(self, name, nodes)

+    

+    def get(self, name, default=None):

+        if hasattr(self, name):

+            val = getattr(self, name)

+            if name.endswith('_'):

+                return val

+            else:

+                return val.text_

+        else:

+            return default

+    

+    def __getattr__(self, name):

+        if name.endswith('__'):

+            n = name[:-1]

+            if hasattr(self, n):

+                return getattr(self, n)

+            else:

+                return None

+        else:

+            e = AttributeError('%s has no attribute %s. missing attribute %s in element <%s>' % (self.__class__.__name__, name, name, self.__tag_name__))

+            setattr(e, 'missing_attrib', name)

+            setattr(e, 'tag_name', self.__tag_name__)

+            raise e

+            

+

+def _loads(node):

+    xo = XmlObject(node.tag)

+    for key in node.attrib.keys():

+        xo.put_attr(key, node.attrib.get(key))

+    if node.text:

+        xo.put_text(node.text)

+    for n in list(node):

+        sub_xo = _loads(n)

+        xo.put_node(n.tag, sub_xo)

+    return xo

+    

+def loads(xmlstr):

+    xmlstr = re.sub(r'xmlns=".*"', '', xmlstr)

+    root = etree.fromstring(xmlstr)

+    return _loads(root)
\ No newline at end of file
diff --git a/plugins/hypervisors/baremetal/resources/security_group_agent/setup.py b/plugins/hypervisors/baremetal/resources/security_group_agent/setup.py
new file mode 100755
index 0000000..2de41d2
--- /dev/null
+++ b/plugins/hypervisors/baremetal/resources/security_group_agent/setup.py
@@ -0,0 +1,44 @@
+# 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
+from setuptools import setup, find_packages
+import sys, os
+
+version = '1.0'
+
+setup(name='security_group_agent',
+      version=version,
+      description="security group agent for CloudStack Baremetal",
+      long_description="""\
+security group agent for CloudStack Baremetal""",
+      classifiers=[], # Get strings from http://pypi.python.org/pypi?%3Aaction=list_classifiers
+      keywords='security group cloudstack',
+      author='Frank Zhang',
+      author_email='frank.zhang@citrix.com',
+      url='http://incubator.apache.org/cloudstack/',
+      license='Apache License 2',
+      packages=find_packages(exclude=['ez_setup', 'examples', 'tests']),
+      include_package_data=True,
+      zip_safe=True,
+      install_requires=[
+        'CherryPy',
+      ],
+      entry_points="""
+      # -*- Entry points: -*-
+      """,
+      )
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDao.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDao.java
new file mode 100755
index 0000000..0f20c67
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDao.java
@@ -0,0 +1,25 @@
+// 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
+package com.cloud.baremetal.database;

+

+import com.cloud.utils.db.GenericDao;

+

+public interface BaremetalCmdbDao extends GenericDao<BaremetalCmdbVO, Long> {

+

+}

diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDaoImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDaoImpl.java
new file mode 100755
index 0000000..fcc95ef
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDaoImpl.java
@@ -0,0 +1,29 @@
+// 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
+package com.cloud.baremetal.database;

+

+import javax.ejb.Local;

+

+import com.cloud.utils.db.DB;

+import com.cloud.utils.db.GenericDaoBase;

+@Local(value = {BaremetalCmdbDao.class})

+@DB(txn = false)

+public class BaremetalCmdbDaoImpl extends GenericDaoBase<BaremetalCmdbVO, Long> implements BaremetalCmdbDao {

+

+}

diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbVO.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbVO.java
new file mode 100755
index 0000000..ee3848a
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbVO.java
@@ -0,0 +1,104 @@
+// 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
+package com.cloud.baremetal.database;

+

+import java.util.UUID;

+

+import javax.persistence.Column;

+import javax.persistence.Entity;

+import javax.persistence.GeneratedValue;

+import javax.persistence.GenerationType;

+import javax.persistence.Id;

+import javax.persistence.Table;

+

+@Entity

+@Table(name="baremetal_cmdb")

+public class BaremetalCmdbVO {

+    @Id

+    @GeneratedValue(strategy = GenerationType.IDENTITY)

+    @Column(name = "id")

+    private long id;

+    

+    @Column(name="uuid")

+    private String uuid;

+    

+    @Column(name="zone_id")

+    private long zoneId;

+    

+    @Column(name="url")

+    private String url;

+    

+    @Column(name="password")

+    private String password;

+    

+    @Column(name="username")

+    private String username;

+

+    public BaremetalCmdbVO() {

+        uuid = UUID.randomUUID().toString();

+    }

+    

+    public long getId() {

+        return id;

+    }

+

+    public void setId(long id) {

+        this.id = id;

+    }

+

+    public String getUuid() {

+        return uuid;

+    }

+

+    public void setUuid(String uuid) {

+        this.uuid = uuid;

+    }

+

+    public long getZoneId() {

+        return zoneId;

+    }

+

+    public void setZoneId(long zoneId) {

+        this.zoneId = zoneId;

+    }

+

+    public String getUrl() {

+        return url;

+    }

+

+    public void setUrl(String url) {

+        this.url = url;

+    }

+

+    public String getPassword() {

+        return password;

+    }

+

+    public void setPassword(String password) {

+        this.password = password;

+    }

+

+    public String getUsername() {

+        return username;

+    }

+

+    public void setUsername(String username) {

+        this.username = username;

+    }

+}

diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalDhcpDao.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalDhcpDao.java
new file mode 100644
index 0000000..fe6d86c
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalDhcpDao.java
@@ -0,0 +1,25 @@
+// 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
+package com.cloud.baremetal.database;
+
+import com.cloud.utils.db.GenericDao;
+
+public interface BaremetalDhcpDao extends GenericDao<BaremetalDhcpVO, Long> {
+
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalDhcpDaoImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalDhcpDaoImpl.java
new file mode 100644
index 0000000..3d9c6de
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalDhcpDaoImpl.java
@@ -0,0 +1,42 @@
+// 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
+package com.cloud.baremetal.database;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.GenericSearchBuilder;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.SearchCriteria2;
+
+@Local(value=BaremetalDhcpDao.class)
+@DB(txn=false)
+public class BaremetalDhcpDaoImpl extends GenericDaoBase<BaremetalDhcpVO, Long> implements BaremetalDhcpDao {
+
+    public BaremetalDhcpDaoImpl() {
+    }
+    
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalDhcpVO.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalDhcpVO.java
new file mode 100644
index 0000000..0bfd541
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalDhcpVO.java
@@ -0,0 +1,118 @@
+// 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
+package com.cloud.baremetal.database;
+
+import java.util.UUID;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.EnumType;
+import javax.persistence.Enumerated;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name="baremetal_dhcp_devices")
+public class BaremetalDhcpVO {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private long id;
+    
+    @Column(name="uuid")
+    private String uuid;
+    
+    @Column(name = "host_id")
+    private long hostId;
+    
+    @Column(name = "pod_id")
+    private long podId;
+
+    @Column(name = "physical_network_id")
+    private long physicalNetworkId;
+    
+    @Column(name = "nsp_id")
+    private long networkServiceProviderId ;
+    
+    @Column(name = "device_type")
+    private String deviceType;
+
+    public BaremetalDhcpVO() {
+        super();
+        this.uuid = UUID.randomUUID().toString();
+    }
+
+    public long getId() {
+        return id;
+    }
+
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getUuid() {
+        return uuid;
+    }
+
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
+
+    public long getHostId() {
+        return hostId;
+    }
+
+    public void setHostId(long hostId) {
+        this.hostId = hostId;
+    }
+
+    public long getPhysicalNetworkId() {
+        return physicalNetworkId;
+    }
+
+    public void setPhysicalNetworkId(long physicalNetworkId) {
+        this.physicalNetworkId = physicalNetworkId;
+    }
+    
+    public String getDeviceType() {
+        return deviceType;
+    }
+
+    public void setDeviceType(String deviceType) {
+        this.deviceType = deviceType;
+    }
+
+    public long getNetworkServiceProviderId() {
+        return networkServiceProviderId;
+    }
+
+    public void setNetworkServiceProviderId(long networkServiceProviderId) {
+        this.networkServiceProviderId = networkServiceProviderId;
+    }
+
+    public long getPodId() {
+        return podId;
+    }
+
+    public void setPodId(long podId) {
+        this.podId = podId;
+    }
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalPxeDao.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalPxeDao.java
new file mode 100644
index 0000000..c640638
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalPxeDao.java
@@ -0,0 +1,26 @@
+// 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
+package com.cloud.baremetal.database;
+
+import com.cloud.utils.db.GenericDao;
+import com.cloud.utils.db.GenericDaoBase;
+
+public interface BaremetalPxeDao extends GenericDao<BaremetalPxeVO, Long> {
+
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalPxeDaoImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalPxeDaoImpl.java
new file mode 100644
index 0000000..c47d6b2
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalPxeDaoImpl.java
@@ -0,0 +1,38 @@
+// 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
+package com.cloud.baremetal.database;
+
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.Filter;
+import com.cloud.utils.db.GenericDaoBase;
+import com.cloud.utils.db.GenericSearchBuilder;
+import com.cloud.utils.db.SearchBuilder;
+import com.cloud.utils.db.SearchCriteria;
+import com.cloud.utils.db.SearchCriteria2;
+
+@Local(value = {BaremetalPxeDao.class})
+@DB(txn = false)
+public class BaremetalPxeDaoImpl extends GenericDaoBase<BaremetalPxeVO, Long> implements BaremetalPxeDao {
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalPxeVO.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalPxeVO.java
new file mode 100644
index 0000000..e0daa46
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalPxeVO.java
@@ -0,0 +1,115 @@
+// 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
+package com.cloud.baremetal.database;
+
+import java.util.UUID;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.GeneratedValue;
+import javax.persistence.GenerationType;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+@Entity
+@Table(name="baremetal_pxe_devices")
+public class BaremetalPxeVO {
+    @Id
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    @Column(name = "id")
+    private long id;
+    
+    @Column(name="uuid")
+    private String uuid;
+    
+    @Column(name = "host_id")
+    private long hostId;
+    
+    @Column(name = "pod_id")
+    private long podId;
+
+    @Column(name = "physical_network_id")
+    private long physicalNetworkId;
+    
+    @Column(name = "nsp_id")
+    private long networkServiceProviderId ;
+    
+    @Column(name = "device_type")
+    private String deviceType;
+    
+    public long getId() {
+        return id;
+    }
+
+    public BaremetalPxeVO() {
+        uuid = UUID.randomUUID().toString();
+    }
+    
+    public void setId(long id) {
+        this.id = id;
+    }
+
+    public String getUuid() {
+        return uuid;
+    }
+
+    public void setUuid(String uuid) {
+        this.uuid = uuid;
+    }
+
+    public long getHostId() {
+        return hostId;
+    }
+
+    public void setHostId(long hostId) {
+        this.hostId = hostId;
+    }
+
+    public long getPhysicalNetworkId() {
+        return physicalNetworkId;
+    }
+
+    public void setPhysicalNetworkId(long physicalNetworkId) {
+        this.physicalNetworkId = physicalNetworkId;
+    }
+
+    public long getNetworkServiceProviderId() {
+        return networkServiceProviderId;
+    }
+
+    public void setNetworkServiceProviderId(long networkServiceProviderId) {
+        this.networkServiceProviderId = networkServiceProviderId;
+    }
+
+    public long getPodId() {
+        return podId;
+    }
+
+    public void setPodId(long podId) {
+        this.podId = podId;
+    }
+
+    public String getDeviceType() {
+        return deviceType;
+    }
+
+    public void setDeviceType(String deviceType) {
+        this.deviceType = deviceType;
+    }
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/AddBaremetalHostCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/AddBaremetalHostCmd.java
new file mode 100755
index 0000000..5222d10
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/AddBaremetalHostCmd.java
@@ -0,0 +1,41 @@
+// 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
+package com.cloud.baremetal.manager;

+

+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.command.admin.host.AddHostCmd;
+

+public class AddBaremetalHostCmd extends AddHostCmd {
+    

+    @Parameter(name=ApiConstants.IP_ADDRESS, type=CommandType.STRING, description="ip address intentionally allocated to this host after provisioning")

+    private String vmIpAddress;

+

+    public AddBaremetalHostCmd() {

+        this.getFullUrlParams().put(ApiConstants.BAREMETAL_DISCOVER_NAME, BareMetalDiscoverer.class.getName());

+    }

+    

+    public String getVmIpAddress() {

+        return vmIpAddress;

+    }

+

+    public void setVmIpAddress(String vmIpAddress) {

+        this.vmIpAddress = vmIpAddress;

+    }

+}

diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalDiscoverer.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalDiscoverer.java
new file mode 100755
index 0000000..64eeaea
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalDiscoverer.java
@@ -0,0 +1,280 @@
+// 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.manager;
+
+import java.net.InetAddress;
+import java.net.URI;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.UUID;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.agent.api.StartupRoutingCommand;
+import com.cloud.baremetal.networkservice.BareMetalResourceBase;
+import com.cloud.configuration.Config;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.dc.ClusterVO;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.exception.DiscoveryException;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.network.Network;
+import com.cloud.resource.Discoverer;
+import com.cloud.resource.DiscovererBase;
+import com.cloud.resource.ResourceManager;
+import com.cloud.resource.ResourceStateAdapter;
+import com.cloud.resource.ServerResource;
+import com.cloud.resource.UnableDeleteHostException;
+import com.cloud.utils.component.Inject;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.script.Script;
+import com.cloud.utils.script.Script2;
+import com.cloud.utils.script.Script2.ParamType;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.dao.VMInstanceDao;
+
+@Local(value=Discoverer.class)
+public class BareMetalDiscoverer extends DiscovererBase implements Discoverer, ResourceStateAdapter {
+	protected static final Logger s_logger = Logger.getLogger(BareMetalDiscoverer.class);
+	@Inject protected ClusterDao _clusterDao;
+	@Inject protected HostDao _hostDao;
+	@Inject protected DataCenterDao _dcDao;
+    @Inject protected VMInstanceDao _vmDao = null;
+    @Inject protected ResourceManager _resourceMgr;
+    @Inject protected ConfigurationDao _configDao;
+	
+    @Override
+    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+    	_resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this);
+    	return super.configure(name, params);
+    }
+    
+    @Override
+    public boolean stop() {
+    	_resourceMgr.unregisterResourceStateAdapter(this.getClass().getSimpleName());
+        return super.stop();
+    }
+    
+	@Override
+	public Map<? extends ServerResource, Map<String, String>> find(long dcId, Long podId, Long clusterId, URI url, String username, String password, List<String> hostTags)
+			throws DiscoveryException {
+	    
+	    String discoverName = _params.get(ApiConstants.BAREMETAL_DISCOVER_NAME);
+	    if (!this.getClass().getName().equals(discoverName)) {
+	        return null;
+	    }
+	    
+		Map<BareMetalResourceBase, Map<String, String>> resources = new HashMap<BareMetalResourceBase, Map<String, String>>();
+		Map<String, String> details = new HashMap<String, String>();
+		        
+		if (!url.getScheme().equals("http")) {
+			String msg = "urlString is not http so we're not taking care of the discovery for this: " + url;
+			s_logger.debug(msg);
+			return null;
+		}
+		if (clusterId == null) {
+			String msg = "must specify cluster Id when add host";
+			s_logger.debug(msg);
+			throw new RuntimeException(msg);
+		}
+
+		if (podId == null) {
+			String msg = "must specify pod Id when add host";
+			s_logger.debug(msg);
+			throw new RuntimeException(msg);
+		}
+		
+		ClusterVO cluster = _clusterDao.findById(clusterId);
+		if (cluster == null || (cluster.getHypervisorType() != HypervisorType.BareMetal)) {
+			if (s_logger.isInfoEnabled())
+				s_logger.info("invalid cluster id or cluster is not for Bare Metal hosts");
+			return null;
+		}
+		
+		DataCenterVO zone = _dcDao.findById(dcId);
+		if (zone == null) {
+			throw new RuntimeException("Cannot find zone " + dcId);
+		}
+
+		try {
+			String hostname = url.getHost();
+			InetAddress ia = InetAddress.getByName(hostname);
+			String ipmiIp = ia.getHostAddress();
+			String guid = UUID.nameUUIDFromBytes(ipmiIp.getBytes()).toString();
+			
+			String injectScript = "scripts/util/ipmi.py";
+			String scriptPath = Script.findScript("", injectScript);
+			if (scriptPath == null) {
+				throw new CloudRuntimeException("Unable to find key ipmi script "
+						+ injectScript);
+			}
+
+			final Script2 command = new Script2(scriptPath, s_logger);
+			command.add("ping");
+			command.add("hostname="+ipmiIp);
+			command.add("usrname="+username);
+			command.add("password="+password, ParamType.PASSWORD);
+			final String result = command.execute();
+			if (result != null) {
+				s_logger.warn(String.format("Can not set up ipmi connection(ip=%1$s, username=%2$s, password=%3$s, args) because %4$s", ipmiIp, username, "******", result));
+				return null;
+			}
+			
+			ClusterVO clu = _clusterDao.findById(clusterId);
+			if (clu.getGuid() == null) {
+				clu.setGuid(UUID.randomUUID().toString());
+				_clusterDao.update(clusterId, clu);
+			}
+			
+			Map<String, Object> params = new HashMap<String, Object>();
+			params.putAll(_params);
+			params.put("zone", Long.toString(dcId));
+			params.put("pod", Long.toString(podId));
+			params.put("cluster",  Long.toString(clusterId));
+			params.put("guid", guid); 
+			params.put(ApiConstants.PRIVATE_IP, ipmiIp);
+			params.put(ApiConstants.USERNAME, username);
+			params.put(ApiConstants.PASSWORD, password);
+			
+			String resourceClassName = _configDao.getValue(Config.ExternalBaremetalResourceClassName.key());
+			BareMetalResourceBase resource = null;
+			if (resourceClassName != null) {
+			    Class<?> clazz = Class.forName(resourceClassName);
+			    resource = (BareMetalResourceBase) clazz.newInstance();
+			    String externalUrl = _configDao.getValue(Config.ExternalBaremetalSystemUrl.key());
+			    if (externalUrl == null) {
+			        throw new IllegalArgumentException(String.format("You must specify ExternalBaremetalSystemUrl in global config page as ExternalBaremetalResourceClassName is not null"));
+			    }
+			    details.put(BaremetalManager.ExternalBaremetalSystemUrl, externalUrl);
+			} else {
+			    resource = new BareMetalResourceBase();
+			}
+			resource.configure("Bare Metal Agent", params);
+			
+			String memCapacity = (String)params.get(ApiConstants.MEMORY);
+			String cpuCapacity = (String)params.get(ApiConstants.CPU_SPEED);
+			String cpuNum = (String)params.get(ApiConstants.CPU_NUMBER);
+			String mac = (String)params.get(ApiConstants.HOST_MAC);
+			if (hostTags != null && hostTags.size() != 0) {
+			    details.put("hostTag", hostTags.get(0));
+			}
+			details.put(ApiConstants.MEMORY, memCapacity);
+			details.put(ApiConstants.CPU_SPEED, cpuCapacity);
+			details.put(ApiConstants.CPU_NUMBER, cpuNum);
+			details.put(ApiConstants.HOST_MAC, mac);
+			details.put(ApiConstants.USERNAME, username);
+			details.put(ApiConstants.PASSWORD, password);
+			details.put(ApiConstants.PRIVATE_IP, ipmiIp);
+			String vmIp = (String)params.get(ApiConstants.IP_ADDRESS);
+			if (vmIp != null) {
+			    details.put(ApiConstants.IP_ADDRESS, vmIp);
+			}
+			String isEchoScAgent = _configDao.getValue(Config.EnableBaremetalSecurityGroupAgentEcho.key());

+			details.put(BaremetalManager.EchoSecurityGroupAgent, isEchoScAgent);
+
+			resources.put(resource, details);
+			resource.start();
+			
+			zone.setGatewayProvider(Network.Provider.ExternalGateWay.getName());
+			zone.setDnsProvider(Network.Provider.ExternalDhcpServer.getName());
+			zone.setDhcpProvider(Network.Provider.ExternalDhcpServer.getName());	
+			_dcDao.update(zone.getId(), zone);
+			
+			s_logger.debug(String.format("Discover Bare Metal host successfully(ip=%1$s, username=%2$s, password=%3%s," +
+					"cpuNum=%4$s, cpuCapacity-%5$s, memCapacity=%6$s)", ipmiIp, username, "******", cpuNum, cpuCapacity, memCapacity));
+			return resources;
+		} catch (Exception e) {
+			s_logger.warn("Can not set up bare metal agent", e);
+		}
+
+		return null;
+	}
+
+	@Override
+	public void postDiscovery(List<HostVO> hosts, long msId)
+			throws DiscoveryException {
+	}
+
+	@Override
+	public boolean matchHypervisor(String hypervisor) {
+		return hypervisor.equalsIgnoreCase(Hypervisor.HypervisorType.BareMetal.toString());
+	}
+
+	@Override
+	public HypervisorType getHypervisorType() {
+		return Hypervisor.HypervisorType.BareMetal;
+	}
+
+	@Override
+    public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) {
+	    // TODO Auto-generated method stub
+	    return null;
+    }
+
+	@Override
+    public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map<String, String> details,
+            List<String> hostTags) {
+		StartupCommand firstCmd = startup[0];
+		if (!(firstCmd instanceof StartupRoutingCommand)) {
+			return null;
+		}
+
+		StartupRoutingCommand ssCmd = ((StartupRoutingCommand) firstCmd);
+		if (ssCmd.getHypervisorType() != HypervisorType.BareMetal) {
+			return null;
+		}
+		
+		return _resourceMgr.fillRoutingHostVO(host, ssCmd, HypervisorType.BareMetal, details, hostTags);
+    }
+
+	@Override
+    public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException {
+		if (host.getType() != Host.Type.Routing || host.getHypervisorType() != HypervisorType.BareMetal) {
+            return null;
+        }
+        
+        List<VMInstanceVO> deadVms = _vmDao.listByLastHostId(host.getId());
+        for (VMInstanceVO vm : deadVms) {
+            if (vm.getState() == State.Running || vm.getHostId() != null) {
+                throw new CloudRuntimeException("VM " + vm.getId() + "is still running on host " + host.getId());
+            }
+            _vmDao.remove(vm.getId());
+        }
+        
+        return new DeleteHostAnswer(true);
+    }
+
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalGuru.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalGuru.java
new file mode 100755
index 0000000..b8a0af3
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalGuru.java
@@ -0,0 +1,87 @@
+// 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.manager;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.ejb.Local;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.hypervisor.HypervisorGuru;
+import com.cloud.hypervisor.HypervisorGuruBase;
+import com.cloud.storage.GuestOSVO;
+import com.cloud.storage.dao.GuestOSDao;
+import com.cloud.utils.component.Inject;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.dao.VMInstanceDao;
+
+@Local(value=HypervisorGuru.class)
+public class BareMetalGuru extends HypervisorGuruBase implements HypervisorGuru {
+	private static final Logger s_logger = Logger.getLogger(BareMetalGuru.class);
+	@Inject GuestOSDao _guestOsDao;
+	@Inject HostDao _hostDao;
+	@Inject VMInstanceDao _vmDao;
+	
+	protected BareMetalGuru() {
+		super();
+	}
+	
+	@Override
+	public HypervisorType getHypervisorType() {
+		return HypervisorType.BareMetal;
+	}
+
+	@Override
+	public <T extends VirtualMachine> VirtualMachineTO implement(VirtualMachineProfile<T> vm) {
+		VirtualMachineTO to = toVirtualMachineTO(vm);
+
+		VMInstanceVO vo = _vmDao.findById(vm.getId());
+        if (vo.getLastHostId() == null) {
+            to.setBootArgs(BaremetalManager.DO_PXE);
+        }
+        
+        Map<String, String> details = new HashMap<String, String>();
+        details.put("template", vm.getTemplate().getUrl());
+        to.setDetails(details);
+        
+		// Determine the VM's OS description
+		GuestOSVO guestOS = _guestOsDao.findById(vm.getVirtualMachine().getGuestOSId());
+		to.setOs(guestOS.getDisplayName());
+
+		return to;
+	}
+	
+	@Override
+    public boolean trackVmHostChange() {
+    	return false;
+    }
+}
+
+	
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalTemplateAdapter.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalTemplateAdapter.java
new file mode 100755
index 0000000..15e63b9
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalTemplateAdapter.java
@@ -0,0 +1,217 @@
+// 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.manager;
+
+import java.util.Date;
+import java.util.List;
+
+import javax.ejb.Local;
+
+import org.apache.cloudstack.api.command.user.iso.DeleteIsoCmd;
+import org.apache.cloudstack.api.command.user.iso.RegisterIsoCmd;
+import org.apache.cloudstack.api.command.user.template.RegisterTemplateCmd;
+import org.apache.log4j.Logger;
+
+import com.cloud.configuration.Resource.ResourceType;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.event.EventTypes;
+import com.cloud.event.UsageEventVO;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.resource.ResourceManager;
+import com.cloud.storage.VMTemplateHostVO;
+import com.cloud.storage.VMTemplateStorageResourceAssoc.Status;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.VMTemplateZoneVO;
+import com.cloud.template.TemplateAdapter;
+import com.cloud.template.TemplateAdapterBase;
+import com.cloud.template.TemplateProfile;
+import com.cloud.user.Account;
+import com.cloud.utils.component.Inject;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@Local(value=TemplateAdapter.class)
+public class BareMetalTemplateAdapter extends TemplateAdapterBase implements TemplateAdapter {
+	private final static Logger s_logger = Logger.getLogger(BareMetalTemplateAdapter.class);
+	@Inject HostDao _hostDao;
+	@Inject ResourceManager _resourceMgr;
+	
+	@Override
+	public TemplateProfile prepare(RegisterTemplateCmd cmd) throws ResourceAllocationException {
+		TemplateProfile profile = super.prepare(cmd);
+		
+		if (profile.getZoneId() == null || profile.getZoneId() == -1) {
+			List<DataCenterVO> dcs = _dcDao.listAllIncludingRemoved();
+			for (DataCenterVO dc : dcs) {
+				List<HostVO> pxeServers = _resourceMgr.listAllHostsInOneZoneByType(Host.Type.BaremetalPxe, dc.getId());
+				if (pxeServers.size() == 0) {
+					throw new CloudRuntimeException("Please add PXE server before adding baremetal template in zone " + dc.getName());
+				}
+			}
+		} else {
+			List<HostVO> pxeServers = _resourceMgr.listAllHostsInOneZoneByType(Host.Type.BaremetalPxe, profile.getZoneId());
+			if (pxeServers.size() == 0) {
+				throw new CloudRuntimeException("Please add PXE server before adding baremetal template in zone " + profile.getZoneId());
+			}
+		}
+		
+		return profile;
+	}
+	
+	@Override
+	public TemplateProfile prepare(RegisterIsoCmd cmd) throws ResourceAllocationException {
+		throw new CloudRuntimeException("Baremetal doesn't support ISO template");
+	}
+	
+	private void templateCreateUsage(VMTemplateVO template, HostVO host) {
+		if (template.getAccountId() != Account.ACCOUNT_ID_SYSTEM) {
+			UsageEventVO usageEvent = new UsageEventVO(EventTypes.EVENT_TEMPLATE_CREATE, template.getAccountId(), host.getDataCenterId(),
+					template.getId(), template.getName(), null, template.getSourceTemplateId(), 0L);
+			_usageEventDao.persist(usageEvent);
+		}
+	}
+	
+	@Override
+	public VMTemplateVO create(TemplateProfile profile) {
+		VMTemplateVO template = persistTemplate(profile);
+		Long zoneId = profile.getZoneId();
+		
+		/* There is no secondary storage vm for baremetal, we use pxe server id.
+		 * Tempalte is not bound to pxeserver right now, and we assume the pxeserver
+		 * cannot be removed once it was added. so we use host id of first found pxe
+		 * server as reference in template_host_ref.
+		 * This maybe a FIXME in future.
+		 */
+		VMTemplateHostVO vmTemplateHost = null;
+		if (zoneId == null || zoneId == -1) {
+			List<DataCenterVO> dcs = _dcDao.listAllIncludingRemoved();
+			for (DataCenterVO dc : dcs) {
+				HostVO pxe = _resourceMgr.listAllHostsInOneZoneByType(Host.Type.BaremetalPxe, dc.getId()).get(0);
+
+				vmTemplateHost = _tmpltHostDao.findByHostTemplate(dc.getId(), template.getId());
+				if (vmTemplateHost == null) {
+					vmTemplateHost = new VMTemplateHostVO(pxe.getId(), template.getId(), new Date(), 100,
+							Status.DOWNLOADED, null, null, null, null, template.getUrl());
+					_tmpltHostDao.persist(vmTemplateHost);
+					templateCreateUsage(template, pxe);
+				}
+			}
+		} else {
+			HostVO pxe = _resourceMgr.listAllHostsInOneZoneByType(Host.Type.BaremetalPxe, zoneId).get(0);
+			vmTemplateHost = new VMTemplateHostVO(pxe.getId(), template.getId(), new Date(), 100,
+					Status.DOWNLOADED, null, null, null, null, template.getUrl());
+			_tmpltHostDao.persist(vmTemplateHost);
+			templateCreateUsage(template, pxe);
+		}
+		
+		_resourceLimitMgr.incrementResourceCount(profile.getAccountId(), ResourceType.template);
+		return template;
+	}
+
+	public TemplateProfile prepareDelete(DeleteIsoCmd cmd) {
+		throw new CloudRuntimeException("Baremetal doesn't support ISO, how the delete get here???");
+	}
+	
+	@Override @DB
+	public boolean delete(TemplateProfile profile) {
+		VMTemplateVO template = profile.getTemplate();
+    	Long templateId = template.getId();
+    	boolean success = true;
+    	String zoneName;
+    	boolean isAllZone;
+    	
+    	if (!template.isCrossZones() && profile.getZoneId() != null) {
+    		isAllZone = false;
+    		zoneName = profile.getZoneId().toString();
+    	} else {
+    		zoneName = "all zones";
+    		isAllZone = true;
+    	}
+    	
+    	s_logger.debug("Attempting to mark template host refs for template: " + template.getName() + " as destroyed in zone: " + zoneName);
+    	Account account = _accountDao.findByIdIncludingRemoved(template.getAccountId());
+    	String eventType = EventTypes.EVENT_TEMPLATE_DELETE;
+    	List<VMTemplateHostVO> templateHostVOs = _tmpltHostDao.listByTemplateId(templateId);
+    	
+		for (VMTemplateHostVO vo : templateHostVOs) {
+			VMTemplateHostVO lock = null;
+			try {
+				HostVO pxeServer = _hostDao.findById(vo.getHostId());
+				if (!isAllZone && pxeServer.getDataCenterId() != profile.getZoneId()) {
+					continue;
+				}
+
+				lock = _tmpltHostDao.acquireInLockTable(vo.getId());
+				if (lock == null) {
+					s_logger.debug("Failed to acquire lock when deleting templateHostVO with ID: " + vo.getId());
+					success = false;
+					break;
+				}
+
+				vo.setDestroyed(true);
+				_tmpltHostDao.update(vo.getId(), vo);
+				VMTemplateZoneVO templateZone = _tmpltZoneDao.findByZoneTemplate(pxeServer.getDataCenterId(), templateId);
+				if (templateZone != null) {
+					_tmpltZoneDao.remove(templateZone.getId());
+				}
+
+				UsageEventVO usageEvent = new UsageEventVO(eventType, account.getId(), pxeServer.getDataCenterId(), templateId, null);
+				_usageEventDao.persist(usageEvent);
+			} finally {
+				if (lock != null) {
+					_tmpltHostDao.releaseFromLockTable(lock.getId());
+				}
+			}
+		}
+    	
+    	s_logger.debug("Successfully marked template host refs for template: " + template.getName() + " as destroyed in zone: " + zoneName);
+	
+    	// If there are no more non-destroyed template host entries for this template, delete it
+		if (success && (_tmpltHostDao.listByTemplateId(templateId).size() == 0)) {
+			long accountId = template.getAccountId();
+			
+			VMTemplateVO lock = _tmpltDao.acquireInLockTable(templateId);
+
+			try {
+				if (lock == null) {
+					s_logger.debug("Failed to acquire lock when deleting template with ID: " + templateId);
+					success = false;
+				} else if (_tmpltDao.remove(templateId)) {
+					// Decrement the number of templates
+				    _resourceLimitMgr.decrementResourceCount(accountId, ResourceType.template);
+				}
+
+			} finally {
+				if (lock != null) {
+					_tmpltDao.releaseFromLockTable(lock.getId());
+				}
+			}
+			s_logger.debug("Removed template: " + template.getName() + " because all of its template host refs were marked as destroyed.");
+		}
+		
+    	return success;
+	}
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManager.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManager.java
new file mode 100755
index 0000000..1599050
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManager.java
@@ -0,0 +1,28 @@
+// 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
+package com.cloud.baremetal.manager;
+
+import com.cloud.network.Network.Provider;
+import com.cloud.utils.component.Manager;
+
+public interface BaremetalManager extends Manager {

+    public static final String EchoSecurityGroupAgent = "EchoSecurityGroupAgent";
+    public static final String ExternalBaremetalSystemUrl = "ExternalBaremetalSystemUrl";
+    public static final String DO_PXE = "doPxe";
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManagerImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManagerImpl.java
new file mode 100755
index 0000000..5388864
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManagerImpl.java
@@ -0,0 +1,112 @@
+// 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
+package com.cloud.baremetal.manager;
+
+import java.util.Map;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.StopAnswer;
+import com.cloud.agent.manager.Commands;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.utils.component.Inject;
+import com.cloud.utils.fsm.StateListener;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineGuru;
+import com.cloud.vm.VirtualMachineManager;
+import com.cloud.vm.VirtualMachineName;
+import com.cloud.vm.VirtualMachine.Event;
+import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.dao.UserVmDao;
+import com.cloud.vm.VirtualMachineProfile;
+
+@Local(value = {BaremetalManager.class})
+public class BaremetalManagerImpl implements BaremetalManager,  StateListener<State, VirtualMachine.Event, VirtualMachine> {
+	private static final Logger s_logger = Logger.getLogger(BaremetalManagerImpl.class);
+	
+	@Inject
+	protected HostDao _hostDao;
+	
+	@Override
+	public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+		VirtualMachine.State.getStateMachine().registerListener(this);
+		return true;
+	}
+
+	@Override
+	public boolean start() {
+		return true;
+	}
+
+	@Override
+	public boolean stop() {
+		return true;
+	}
+
+	@Override
+	public String getName() {
+		return "Baremetal Manager";
+	}
+
+	@Override
+    public boolean preStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) {
+	    return false;
+    }
+
+	@Override
+    public boolean postStateTransitionEvent(State oldState, Event event, State newState, VirtualMachine vo, boolean status, Object opaque) {
+		if (newState != State.Starting && newState != State.Error && newState != State.Expunging) {
+			return true;
+		}
+		
+		if (vo.getHypervisorType() != HypervisorType.BareMetal) {
+		    return true;
+		}
+		
+		HostVO host = _hostDao.findById(vo.getHostId());
+		if (host == null) {
+			s_logger.debug("Skip oldState " + oldState + " to " + "newState " + newState + " transimtion");
+			return true;
+		}
+		_hostDao.loadDetails(host);
+		
+		if (newState == State.Starting) {
+			host.setDetail("vmName", vo.getInstanceName());
+			s_logger.debug("Add vmName " + host.getDetail("vmName") + " to host " + host.getId() + " details");
+		} else {
+			if (host.getDetail("vmName") != null && host.getDetail("vmName").equalsIgnoreCase(vo.getInstanceName())) {
+				s_logger.debug("Remove vmName " + host.getDetail("vmName") + " from host " + host.getId() + " details");
+				host.getDetails().remove("vmName");
+			}
+		}
+		_hostDao.saveDetails(host);
+		
+		
+		return true;
+    }
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalDhcpCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalDhcpCmd.java
new file mode 100755
index 0000000..6a26fe2
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalDhcpCmd.java
@@ -0,0 +1,149 @@
+// 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
+package com.cloud.baremetal.networkservice;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.BaseCmd.CommandType;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.PlugService;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.log4j.Logger;
+
+import com.cloud.baremetal.database.BaremetalDhcpVO;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.UserContext;
+
+public class AddBaremetalDhcpCmd extends BaseAsyncCmd {
+    private static final String s_name = "addexternaldhcpresponse";
+    public static final Logger s_logger = Logger.getLogger(AddBaremetalDhcpCmd.class);
+    
+    @PlugService BaremetalDhcpManager mgr;
+    
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+    @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.LONG, required=true, description="the Physical Network ID")
+    private Long physicalNetworkId;
+    
+    @Parameter(name=ApiConstants.POD_ID, type=CommandType.LONG, required = true, description="Pod Id")
+    private Long podId;
+    
+    @Parameter(name=ApiConstants.DHCP_SERVER_TYPE, type=CommandType.STRING, required = true, description="Type of dhcp device")
+    private String dhcpType;
+    
+    @Parameter(name=ApiConstants.URL, type=CommandType.STRING, required = true, description="URL of the external dhcp appliance.")
+    private String url;
+
+    @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required = true, description="Credentials to reach external dhcp device")
+    private String username;
+    
+    @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required = true, description="Credentials to reach external dhcp device")
+    private String password;
+    
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_BAREMETAL_DHCP_SERVER_ADD;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Adding an external DHCP server";
+    }
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
+            ResourceAllocationException, NetworkRuleConflictException {
+        try {
+            BaremetalDhcpVO vo = mgr.addDchpServer(this);
+            BaremetalDhcpResponse response = mgr.generateApiResponse(vo);
+            response.setObjectName(s_name);
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+        } catch (Exception e) {
+            s_logger.warn("Unable to add external dhcp server with url: " + getUrl(), e);
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
+        }
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return UserContext.current().getCaller().getId();
+    }
+
+    public Long getPodId() {
+        return podId;
+    }
+
+    public void setPodId(Long podId) {
+        this.podId = podId;
+    }
+
+    public String getDhcpType() {
+        return dhcpType;
+    }
+
+    public void setDhcpType(String dhcpType) {
+        this.dhcpType = dhcpType;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public Long getPhysicalNetworkId() {
+        return physicalNetworkId;
+    }
+
+    public void setPhysicalNetworkId(Long physicalNetworkId) {
+        this.physicalNetworkId = physicalNetworkId;
+    }
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalKickStartPxeCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalKickStartPxeCmd.java
new file mode 100755
index 0000000..4c3d0b2
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalKickStartPxeCmd.java
@@ -0,0 +1,36 @@
+// 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
+package com.cloud.baremetal.networkservice;

+

+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseCmd.CommandType;
+import org.apache.cloudstack.api.Parameter;
+

+public class AddBaremetalKickStartPxeCmd extends AddBaremetalPxeCmd {

+    @Parameter(name=ApiConstants.TFTP_DIR, type=CommandType.STRING, required = true, description="Tftp root directory of PXE server")

+    private String tftpDir;

+

+    public String getTftpDir() {

+        return tftpDir;

+    }

+

+    public void setTftpDir(String tftpDir) {

+        this.tftpDir = tftpDir;

+    }
+}

diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxeCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxeCmd.java
new file mode 100755
index 0000000..a1d72a3
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxeCmd.java
@@ -0,0 +1,144 @@
+// 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
+package com.cloud.baremetal.networkservice;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.BaseCmd.CommandType;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.PlugService;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.log4j.Logger;
+
+import com.cloud.baremetal.database.BaremetalPxeVO;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.user.UserContext;
+
+public class AddBaremetalPxeCmd extends BaseAsyncCmd {
+    private static final String s_name = "addexternalpxeresponse";
+    public static final Logger s_logger = Logger.getLogger(AddBaremetalPxeCmd.class);
+    
+    @PlugService BaremetalPxeManager pxeMgr;
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+    @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.LONG, required=true, description="the Physical Network ID")
+    private Long physicalNetworkId;
+    
+    @Parameter(name=ApiConstants.POD_ID, type=CommandType.LONG, description="Pod Id")
+    private Long podId;
+    
+    @Parameter(name=ApiConstants.URL, type=CommandType.STRING, required = true, description="URL of the external pxe device")
+    private String url;
+
+    @Parameter(name=ApiConstants.PXE_SERVER_TYPE, type=CommandType.STRING, required = true, description="type of pxe device")
+    private String deviceType;
+    
+    @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required = true, description="Credentials to reach external pxe device")
+    private String username;
+    
+    @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required = true, description="Credentials to reach external pxe device")
+    private String password;
+    
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_BAREMETAL_PXE_SERVER_ADD;
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Adding an external pxe server";
+    }
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
+            ResourceAllocationException, NetworkRuleConflictException {
+        try {
+            BaremetalPxeVO vo = pxeMgr.addPxeServer(this);
+        } catch (Exception e) {
+            s_logger.warn("Unable to add external pxe server with url: " + getUrl(), e);
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage()); 
+        }
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return UserContext.current().getCaller().getId();
+    }
+
+    public Long getPhysicalNetworkId() {
+        return physicalNetworkId;
+    }
+
+    public void setPhysicalNetworkId(Long physicalNetworkId) {
+        this.physicalNetworkId = physicalNetworkId;
+    }
+
+    public Long getPodId() {
+        return podId;
+    }
+
+    public void setPodId(Long podId) {
+        this.podId = podId;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public void setUrl(String url) {
+        this.url = url;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public void setUsername(String username) {
+        this.username = username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public void setPassword(String password) {
+        this.password = password;
+    }
+
+    public String getDeviceType() {
+        return deviceType;
+    }
+
+    public void setDeviceType(String deviceType) {
+        this.deviceType = deviceType;
+    }
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxePingServerCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxePingServerCmd.java
new file mode 100755
index 0000000..70796f3
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/AddBaremetalPxePingServerCmd.java
@@ -0,0 +1,80 @@
+// 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
+package com.cloud.baremetal.networkservice;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.Parameter;
+
+public class AddBaremetalPxePingServerCmd extends AddBaremetalPxeCmd {
+
+    @Parameter(name=ApiConstants.PING_STORAGE_SERVER_IP, type=CommandType.STRING, required = true, description="PING storage server ip")
+    private String pingStorageServerIp;
+    
+    @Parameter(name=ApiConstants.PING_DIR, type=CommandType.STRING, required = true, description="Root directory on PING storage server")
+    private String pingDir;
+    
+    @Parameter(name=ApiConstants.TFTP_DIR, type=CommandType.STRING, required = true, description="Tftp root directory of PXE server")
+    private String tftpDir;
+    
+    @Parameter(name=ApiConstants.PING_CIFS_USERNAME, type=CommandType.STRING, description="Username of PING storage server")
+    private String pingStorageServerUserName;
+    
+    @Parameter(name=ApiConstants.PING_CIFS_PASSWORD, type=CommandType.STRING, description="Password of PING storage server")
+    private String pingStorageServerPassword;
+
+    public String getPingStorageServerIp() {
+        return pingStorageServerIp;
+    }
+
+    public void setPingStorageServerIp(String pingStorageServerIp) {
+        this.pingStorageServerIp = pingStorageServerIp;
+    }
+
+    public String getPingDir() {
+        return pingDir;
+    }
+
+    public void setPingDir(String pingDir) {
+        this.pingDir = pingDir;
+    }
+
+    public String getTftpDir() {
+        return tftpDir;
+    }
+
+    public void setTftpDir(String tftpDir) {
+        this.tftpDir = tftpDir;
+    }
+
+    public String getPingStorageServerUserName() {
+        return pingStorageServerUserName;
+    }
+
+    public void setPingStorageServerUserName(String pingStorageServerUserName) {
+        this.pingStorageServerUserName = pingStorageServerUserName;
+    }
+
+    public String getPingStorageServerPassword() {
+        return pingStorageServerPassword;
+    }
+
+    public void setPingStorageServerPassword(String pingStorageServerPassword) {
+        this.pingStorageServerPassword = pingStorageServerPassword;
+    }
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalPingServiceImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalPingServiceImpl.java
new file mode 100755
index 0000000..1f3defb
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalPingServiceImpl.java
@@ -0,0 +1,300 @@
+// 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.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.baremetal.IpmISetBootDevCommand;
+import com.cloud.agent.api.baremetal.IpmISetBootDevCommand.BootDev;
+import com.cloud.agent.api.baremetal.PreparePxeServerAnswer;
+import com.cloud.agent.api.baremetal.PreparePxeServerCommand;
+import com.cloud.agent.api.baremetal.prepareCreateTemplateCommand;
+import com.cloud.baremetal.database.BaremetalPxeDao;
+import com.cloud.baremetal.database.BaremetalPxeVO;
+import com.cloud.baremetal.networkservice.BaremetalPxeManager.BaremetalPxeType;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.HostPodVO;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDetailsDao;
+import com.cloud.network.PhysicalNetworkServiceProvider;
+import com.cloud.network.PhysicalNetworkVO;
+import com.cloud.network.dao.PhysicalNetworkDao;
+import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
+import com.cloud.network.dao.PhysicalNetworkServiceProviderVO;
+import com.cloud.resource.ResourceManager;
+import com.cloud.resource.ServerResource;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.component.Inject;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.SearchCriteria.Op;
+import com.cloud.utils.db.SearchCriteria2;
+import com.cloud.utils.db.SearchCriteriaService;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.NicVO;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VirtualMachineProfile;
+
+@Local(value=BaremetalPxeService.class)
+public class BareMetalPingServiceImpl extends BareMetalPxeServiceBase implements BaremetalPxeService {
+	private static final Logger s_logger = Logger.getLogger(BareMetalPingServiceImpl.class);
+	@Inject ResourceManager _resourceMgr;
+	@Inject PhysicalNetworkDao _physicalNetworkDao;
+	@Inject PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao;
+	@Inject HostDetailsDao _hostDetailsDao;
+	@Inject BaremetalPxeDao _pxeDao;
+	
+	
+	@Override
+	public boolean prepare(VirtualMachineProfile<UserVmVO> profile, NicProfile pxeNic, DeployDestination dest, ReservationContext context) {
+	    SearchCriteriaService<BaremetalPxeVO, BaremetalPxeVO> sc = SearchCriteria2.create(BaremetalPxeVO.class);
+        sc.addAnd(sc.getEntity().getDeviceType(), Op.EQ, BaremetalPxeType.PING.toString());
+        sc.addAnd(sc.getEntity().getPodId(), Op.EQ, dest.getPod().getId());
+        BaremetalPxeVO pxeVo = sc.find();
+        if (pxeVo == null) {
+            throw new CloudRuntimeException("No PING PXE server found in pod: " + dest.getPod().getId() + ", you need to add it before starting VM");
+        }
+        long pxeServerId = pxeVo.getHostId();
+        
+	    String mac = pxeNic.getMacAddress();
+	    String ip = pxeNic.getIp4Address();
+	    String gateway = pxeNic.getGateway();
+	    String mask = pxeNic.getNetmask();
+	    String dns = pxeNic.getDns1();
+	    if (dns == null) {
+	    	dns = pxeNic.getDns2();
+	    }
+
+		try {
+			String tpl = profile.getTemplate().getUrl();
+			assert tpl != null : "How can a null template get here!!!";
+			PreparePxeServerCommand cmd = new PreparePxeServerCommand(ip, mac, mask, gateway, dns, tpl,
+					profile.getVirtualMachine().getInstanceName(), dest.getHost().getName());
+			PreparePxeServerAnswer ans = (PreparePxeServerAnswer) _agentMgr.send(pxeServerId, cmd);
+			if (!ans.getResult()) {
+				s_logger.warn("Unable tot program PXE server: " + pxeVo.getId() + " because " + ans.getDetails());
+				return false;
+			}
+			
+			IpmISetBootDevCommand bootCmd = new IpmISetBootDevCommand(BootDev.pxe);
+			Answer anw = _agentMgr.send(dest.getHost().getId(), bootCmd);
+			if (!anw.getResult()) {
+				s_logger.warn("Unable to set host: " + dest.getHost().getId() + " to PXE boot because " + anw.getDetails());
+			}
+			
+			return anw.getResult();
+		} catch (Exception e) {
+			s_logger.warn("Cannot prepare PXE server", e);
+			return false;
+		}
+	}
+
+	
+    @Override
+    public boolean prepareCreateTemplate(Long pxeServerId, UserVm vm, String templateUrl) {        
+        List<NicVO> nics = _nicDao.listByVmId(vm.getId());
+        if (nics.size() != 1) {
+            throw new CloudRuntimeException("Wrong nic number " + nics.size() + " of vm " + vm.getId());
+        }
+        
+        /* use last host id when VM stopped */
+        Long hostId = (vm.getHostId() == null ? vm.getLastHostId() : vm.getHostId());
+        HostVO host = _hostDao.findById(hostId);
+        DataCenterVO dc = _dcDao.findById(host.getDataCenterId());
+        NicVO nic = nics.get(0);
+        String mask = nic.getNetmask();
+        String mac = nic.getMacAddress();
+        String ip = nic.getIp4Address();
+        String gateway = nic.getGateway();
+        String dns = dc.getDns1();
+        if (dns == null) {
+            dns = dc.getDns2();
+        }
+        
+        try {
+            prepareCreateTemplateCommand cmd = new prepareCreateTemplateCommand(ip, mac, mask, gateway, dns, templateUrl);
+            Answer ans = _agentMgr.send(pxeServerId, cmd);
+            return ans.getResult();
+        } catch (Exception e) {
+            s_logger.debug("Prepare for creating baremetal template failed", e);
+            return false;
+        }
+    }
+
+
+    @Override
+    @DB
+    public BaremetalPxeVO addPxeServer(AddBaremetalPxeCmd cmd) {
+        AddBaremetalPxePingServerCmd pcmd = (AddBaremetalPxePingServerCmd)cmd;
+        
+        PhysicalNetworkVO pNetwork = null;
+        long zoneId;
+        
+        if (cmd.getPhysicalNetworkId() == null || cmd.getUrl() == null || cmd.getUsername() == null || cmd.getPassword() == null) {
+            throw new IllegalArgumentException("At least one of the required parameters(physical network id, url, username, password) is null");
+        } 
+        
+        pNetwork = _physicalNetworkDao.findById(cmd.getPhysicalNetworkId());
+        if (pNetwork == null) {
+            throw new IllegalArgumentException("Could not find phyical network with ID: " + cmd.getPhysicalNetworkId());
+        }
+        zoneId = pNetwork.getDataCenterId();
+        
+        PhysicalNetworkServiceProviderVO ntwkSvcProvider = _physicalNetworkServiceProviderDao.findByServiceProvider(pNetwork.getId(), BaremetalPxeManager.BAREMETAL_PXE_SERVICE_PROVIDER.getName());
+        if (ntwkSvcProvider == null) {
+            throw new CloudRuntimeException("Network Service Provider: " + BaremetalPxeManager.BAREMETAL_PXE_SERVICE_PROVIDER.getName() +
+                    " is not enabled in the physical network: " + cmd.getPhysicalNetworkId() + "to add this device");
+        } else if (ntwkSvcProvider.getState() == PhysicalNetworkServiceProvider.State.Shutdown) {
+            throw new CloudRuntimeException("Network Service Provider: " + ntwkSvcProvider.getProviderName() +
+                    " is in shutdown state in the physical network: " + cmd.getPhysicalNetworkId() + "to add this device");
+        }
+        
+        HostPodVO pod = _podDao.findById(cmd.getPodId());
+        if (pod == null) {
+            throw new IllegalArgumentException("Could not find pod with ID: " + cmd.getPodId());
+        } 
+        
+        List<HostVO> pxes = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.BaremetalPxe, null, cmd.getPodId(), zoneId);
+        if (pxes.size() != 0) {
+            throw new IllegalArgumentException("Already had a PXE server in Pod: " + cmd.getPodId() + " zone: " + zoneId);
+        }
+        
+        String storageServerIp = pcmd.getPingStorageServerIp();
+        if (storageServerIp == null) {
+            throw new IllegalArgumentException("No IP for storage server specified");
+        }
+        String pingDir = pcmd.getPingDir();
+        if (pingDir == null) {
+            throw new IllegalArgumentException("No direcotry for storage server specified");
+        }
+        String tftpDir = pcmd.getTftpDir();
+        if (tftpDir == null) {
+            throw new IllegalArgumentException("No TFTP directory specified");
+        }
+        
+        String cifsUsername = pcmd.getPingStorageServerUserName();
+        if (cifsUsername == null || cifsUsername.equalsIgnoreCase("")) {
+            cifsUsername = "xxx";
+        }
+        String cifsPassword = pcmd.getPingStorageServerPassword();
+        if (cifsPassword == null || cifsPassword.equalsIgnoreCase("")) {
+            cifsPassword = "xxx";
+        }
+        
+        
+        URI uri;
+        try {
+            uri = new URI(cmd.getUrl());
+        } catch (Exception e) {
+            s_logger.debug(e);
+            throw new IllegalArgumentException(e.getMessage());
+        }
+        String ipAddress = uri.getHost();
+        
+        String guid = getPxeServerGuid(Long.toString(zoneId)  + "-" + pod.getId(), BaremetalPxeType.PING.toString(), ipAddress);
+        
+        ServerResource resource = null;
+        Map params = new HashMap<String, String>();
+        params.put(BaremetalPxeService.PXE_PARAM_ZONE, Long.toString(zoneId));
+        params.put(BaremetalPxeService.PXE_PARAM_POD, String.valueOf(pod.getId()));
+        params.put(BaremetalPxeService.PXE_PARAM_IP, ipAddress);
+        params.put(BaremetalPxeService.PXE_PARAM_USERNAME, cmd.getUsername());
+        params.put(BaremetalPxeService.PXE_PARAM_PASSWORD, cmd.getPassword());
+        params.put(BaremetalPxeService.PXE_PARAM_PING_STORAGE_SERVER_IP, storageServerIp);
+        params.put(BaremetalPxeService.PXE_PARAM_PING_ROOT_DIR, pingDir);
+        params.put(BaremetalPxeService.PXE_PARAM_TFTP_DIR, tftpDir);
+        params.put(BaremetalPxeService.PXE_PARAM_PING_STORAGE_SERVER_USERNAME, cifsUsername);
+        params.put(BaremetalPxeService.PXE_PARAM_PING_STORAGE_SERVER_PASSWORD, cifsPassword);
+        params.put(BaremetalPxeService.PXE_PARAM_GUID, guid);
+        
+        resource = new BaremetalPingPxeResource();
+        try {
+            resource.configure("PING PXE resource", params);
+        } catch (Exception e) {
+            s_logger.debug(e);
+            throw new CloudRuntimeException(e.getMessage());
+        }
+        
+        Host pxeServer = _resourceMgr.addHost(zoneId, resource, Host.Type.BaremetalPxe, params);
+        if (pxeServer == null) {
+            throw new CloudRuntimeException("Cannot add PXE server as a host");
+        }
+        
+        BaremetalPxeVO vo = new BaremetalPxeVO();
+        Transaction txn = Transaction.currentTxn();
+        vo.setHostId(pxeServer.getId());
+        vo.setNetworkServiceProviderId(ntwkSvcProvider.getId());
+        vo.setPodId(pod.getId());
+        vo.setPhysicalNetworkId(pcmd.getPhysicalNetworkId());
+        vo.setDeviceType(BaremetalPxeType.PING.toString());
+        txn.start();
+        _pxeDao.persist(vo);
+        txn.commit();
+        return vo;
+    }
+
+    @Override
+    public BaremetalPxeResponse getApiResponse(BaremetalPxeVO vo) {
+        BaremetalPxePingResponse response = new BaremetalPxePingResponse();
+        response.setId(String.valueOf(vo.getId()));
+        response.setPhysicalNetworkId(String.valueOf(vo.getPhysicalNetworkId()));
+        response.setPodId(String.valueOf(vo.getPodId()));
+        Map<String, String> details = _hostDetailsDao.findDetails(vo.getHostId());
+        response.setPingStorageServerIp(details.get(BaremetalPxeService.PXE_PARAM_PING_STORAGE_SERVER_IP));
+        response.setPingDir(details.get(BaremetalPxeService.PXE_PARAM_PING_ROOT_DIR));
+        response.setTftpDir(details.get(BaremetalPxeService.PXE_PARAM_TFTP_DIR));
+        return response;
+    }
+
+
+    @Override
+    public List<BaremetalPxeResponse> listPxeServers(ListBaremetalPxePingServersCmd cmd) {
+        SearchCriteriaService<BaremetalPxeVO, BaremetalPxeVO> sc = SearchCriteria2.create(BaremetalPxeVO.class);
+        sc.addAnd(sc.getEntity().getDeviceType(), Op.EQ, BaremetalPxeType.PING.toString());
+        if (cmd.getPodId() != null) {
+            sc.addAnd(sc.getEntity().getPodId(), Op.EQ, cmd.getPodId());
+            if (cmd.getId() != null) {
+                sc.addAnd(sc.getEntity().getId(), Op.EQ, cmd.getId());
+            }
+        }
+        List<BaremetalPxeVO> vos = sc.list();
+        List<BaremetalPxeResponse> responses = new ArrayList<BaremetalPxeResponse>(vos.size());
+        for (BaremetalPxeVO vo : vos) {
+            responses.add(getApiResponse(vo));
+        }
+        return responses;
+    }
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalPxeServiceBase.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalPxeServiceBase.java
new file mode 100644
index 0000000..85a9b3c
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalPxeServiceBase.java
@@ -0,0 +1,68 @@
+// 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.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import com.cloud.agent.AgentManager;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.HostPodDao;
+import com.cloud.host.dao.HostDao;
+import com.cloud.utils.component.Inject;
+import com.cloud.vm.dao.NicDao;
+
+public abstract class BareMetalPxeServiceBase implements BaremetalPxeService {
+	protected String _name;
+	@Inject DataCenterDao _dcDao;
+	@Inject HostDao _hostDao;
+	@Inject AgentManager _agentMgr;
+	@Inject HostPodDao _podDao;
+	@Inject NicDao _nicDao;
+	
+	@Override
+	public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+		_name = name;
+		return true;
+	}
+
+	@Override
+	public String getName() {
+		return _name;
+	}
+
+	@Override
+	public boolean start() {
+		return true;
+	}
+
+	@Override
+	public boolean stop() {
+		return true;
+	}
+
+	protected String getPxeServerGuid(String zoneId, String name, String ip) {
+		return zoneId + "-" + name + "-" + ip;
+	}
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
new file mode 100755
index 0000000..d615d1d
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BareMetalResourceBase.java
@@ -0,0 +1,618 @@
+// 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.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+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;
+import com.cloud.agent.api.to.VirtualMachineTO;
+import com.cloud.baremetal.manager.BaremetalManager;
+import com.cloud.host.Host.Type;
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.resource.ServerResource;
+import com.cloud.server.ManagementServer;
+import com.cloud.utils.component.ComponentLocator;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.utils.script.OutputInterpreter;
+import com.cloud.utils.script.Script;
+import com.cloud.utils.script.Script2;
+import com.cloud.utils.script.Script2.ParamType;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.State;
+import com.cloud.vm.dao.VMInstanceDao;
+
+import edu.emory.mathcs.backport.java.util.concurrent.TimeUnit;
+
+@Local(value = ServerResource.class)
+public class BareMetalResourceBase implements ServerResource {
+	private static final Logger s_logger = Logger.getLogger(BareMetalResourceBase.class);
+	protected HashMap<String, State> _vms = new HashMap<String, State>(2);
+	protected String _name;
+	protected String _uuid;
+	protected String _zone;
+	protected String _pod;
+	protected Long hostId;
+	protected String _cluster;
+	protected long _memCapacity;
+	protected long _cpuCapacity;
+	protected long _cpuNum;
+	protected String _mac;
+	protected String _username;
+	protected String _password;
+	protected String _ip;

+	protected boolean _isEchoScAgent;
+	protected IAgentControl _agentControl;
+	protected Script2 _pingCommand;
+	protected Script2 _setPxeBootCommand;
+	protected Script2 _setDiskBootCommand;
+	protected Script2 _rebootCommand;
+	protected Script2 _getStatusCommand;
+	protected Script2 _powerOnCommand;
+	protected Script2 _powerOffCommand;
+	protected Script2 _forcePowerOffCommand;
+	protected Script2 _bootOrRebootCommand;
+	protected String _vmName;
+	protected VMInstanceDao vmDao;
+
+	private void changeVmState(String vmName, VirtualMachine.State state) {
+		synchronized (_vms) {
+			_vms.put(vmName, state);
+		}
+	}
+
+	private State removeVmState(String vmName) {
+		synchronized (_vms) {
+			return _vms.remove(vmName);
+		}
+	}
+
+	@Override
+	public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+		_name = name;
+		_uuid = (String) params.get("guid");
+		try {
+			_memCapacity = Long.parseLong((String) params.get(ApiConstants.MEMORY)) * 1024L * 1024L;
+			_cpuCapacity = Long.parseLong((String) params.get(ApiConstants.CPU_SPEED));
+			_cpuNum = Long.parseLong((String) params.get(ApiConstants.CPU_NUMBER));
+		} catch (NumberFormatException e) {
+			throw new ConfigurationException(String.format("Unable to parse number of CPU or memory capacity "
+			        + "or cpu capacity(cpu number = %1$s memCapacity=%2$s, cpuCapacity=%3$s", (String) params.get(ApiConstants.CPU_NUMBER),
+			        (String) params.get(ApiConstants.MEMORY), (String) params.get(ApiConstants.CPU_SPEED)));
+		}
+
+		_zone = (String) params.get("zone");
+		_pod = (String) params.get("pod");
+		_cluster = (String) params.get("cluster");
+		hostId = (Long) params.get("hostId");
+		_ip = (String) params.get(ApiConstants.PRIVATE_IP);
+		_mac = (String) params.get(ApiConstants.HOST_MAC);
+		_username = (String) params.get(ApiConstants.USERNAME);
+		_password = (String) params.get(ApiConstants.PASSWORD);
+		_vmName = (String) params.get("vmName");

+		String echoScAgent = (String) params.get(BaremetalManager.EchoSecurityGroupAgent);
+
+		if (_pod == null) {
+			throw new ConfigurationException("Unable to get the pod");
+		}
+
+		if (_cluster == null) {
+			throw new ConfigurationException("Unable to get the pod");
+		}
+		
+		if (_ip == null) {
+			throw new ConfigurationException("Unable to get the host address");
+		}
+
+		if (_mac.equalsIgnoreCase("unknown")) {
+			throw new ConfigurationException("Unable to get the host mac address");
+		}
+
+		if (_mac.split(":").length != 6) {
+			throw new ConfigurationException("Wrong MAC format(" + _mac
+			        + "). It must be in format of for example 00:11:ba:33:aa:dd which is not case sensitive");
+		}
+
+		if (_uuid == null) {
+			throw new ConfigurationException("Unable to get the uuid");
+		}

+		
+		if (echoScAgent != null) {

+		    _isEchoScAgent = Boolean.valueOf(echoScAgent);
+		}
+
+		String injectScript = "scripts/util/ipmi.py";
+		String scriptPath = Script.findScript("", injectScript);
+		if (scriptPath == null) {
+			throw new ConfigurationException("Cannot find ping script " + scriptPath);
+		}
+		_pingCommand = new Script2(scriptPath, s_logger);
+		_pingCommand.add("ping");
+		_pingCommand.add("hostname=" + _ip);
+		_pingCommand.add("usrname=" + _username);
+		_pingCommand.add("password=" + _password, ParamType.PASSWORD);
+
+		_setPxeBootCommand = new Script2(scriptPath, s_logger);
+		_setPxeBootCommand.add("boot_dev");
+		_setPxeBootCommand.add("hostname=" + _ip);
+		_setPxeBootCommand.add("usrname=" + _username);
+		_setPxeBootCommand.add("password=" + _password, ParamType.PASSWORD);
+		_setPxeBootCommand.add("dev=pxe");
+
+		_setDiskBootCommand = new Script2(scriptPath, s_logger);
+		_setDiskBootCommand.add("boot_dev");
+		_setDiskBootCommand.add("hostname=" + _ip);
+		_setDiskBootCommand.add("usrname=" + _username);
+		_setDiskBootCommand.add("password=" + _password, ParamType.PASSWORD);
+		_setDiskBootCommand.add("dev=disk");
+
+		_rebootCommand = new Script2(scriptPath, s_logger);
+		_rebootCommand.add("reboot");
+		_rebootCommand.add("hostname=" + _ip);
+		_rebootCommand.add("usrname=" + _username);
+		_rebootCommand.add("password=" + _password, ParamType.PASSWORD);
+
+		_getStatusCommand = new Script2(scriptPath, s_logger);
+		_getStatusCommand.add("ping");
+		_getStatusCommand.add("hostname=" + _ip);
+		_getStatusCommand.add("usrname=" + _username);
+		_getStatusCommand.add("password=" + _password, ParamType.PASSWORD);
+
+		_powerOnCommand = new Script2(scriptPath, s_logger);
+		_powerOnCommand.add("power");
+		_powerOnCommand.add("hostname=" + _ip);
+		_powerOnCommand.add("usrname=" + _username);
+		_powerOnCommand.add("password=" + _password, ParamType.PASSWORD);
+		_powerOnCommand.add("action=on");
+
+		_powerOffCommand = new Script2(scriptPath, s_logger);
+		_powerOffCommand.add("power");
+		_powerOffCommand.add("hostname=" + _ip);
+		_powerOffCommand.add("usrname=" + _username);
+		_powerOffCommand.add("password=" + _password, ParamType.PASSWORD);
+		_powerOffCommand.add("action=soft");
+
+		_forcePowerOffCommand = new Script2(scriptPath, s_logger);
+		_forcePowerOffCommand.add("power");
+		_forcePowerOffCommand.add("hostname=" + _ip);
+		_forcePowerOffCommand.add("usrname=" + _username);
+		_forcePowerOffCommand.add("password=" + _password, ParamType.PASSWORD);
+		_forcePowerOffCommand.add("action=off");
+
+		_bootOrRebootCommand = new Script2(scriptPath, s_logger);
+		_bootOrRebootCommand.add("boot_or_reboot");
+		_bootOrRebootCommand.add("hostname=" + _ip);
+		_bootOrRebootCommand.add("usrname=" + _username);
+		_bootOrRebootCommand.add("password=" + _password, ParamType.PASSWORD);
+
+		return true;
+	}
+
+	protected boolean doScript(Script cmd) {
+		return doScript(cmd, null);
+	}
+
+	protected boolean doScript(Script cmd, OutputInterpreter interpreter) {
+		int retry = 5;
+		String res = null;
+		while (retry-- > 0) {
+			if (interpreter == null) {
+				res = cmd.execute();
+			} else {
+				res = cmd.execute(interpreter);
+			}
+			if (res != null && res.startsWith("Error: Unable to establish LAN")) {
+				s_logger.warn("IPMI script timeout(" + cmd.toString() + "), will retry " + retry + " times");
+				continue;
+			} else if (res == null) {
+				return true;
+			} else {
+				break;
+			}
+		}
+
+		s_logger.warn("IPMI Scirpt failed due to " + res + "(" + cmd.toString() + ")");
+		return false;
+	}
+
+	@Override
+	public boolean start() {
+		return true;
+	}
+
+	@Override
+	public boolean stop() {
+		return true;
+	}
+
+	@Override
+	public String getName() {
+		return _name;
+	}
+
+	@Override
+	public Type getType() {
+		return com.cloud.host.Host.Type.Routing;
+	}
+
+	protected State getVmState() {
+		OutputInterpreter.AllLinesParser interpreter = new OutputInterpreter.AllLinesParser();
+		if (!doScript(_getStatusCommand, interpreter)) {
+			s_logger.warn("Cannot get power status of " + _name + ", assume VM state was not changed");
+			return null;
+		}
+		if (isPowerOn(interpreter.getLines())) {
+			return State.Running;
+		} else {
+			return State.Stopped;
+		}
+	}
+
+    protected Map<String, State> fullSync() {
+        Map<String, State> states = new HashMap<String, State>();
+        if (hostId != null) {
+            ComponentLocator locator = ComponentLocator.getLocator(ManagementServer.Name);
+            vmDao = locator.getDao(VMInstanceDao.class);
+            final List<? extends VMInstanceVO> vms = vmDao.listByHostId(hostId);
+            for (VMInstanceVO vm : vms) {
+                states.put(vm.getInstanceName(), vm.getState());
+            }
+        }
+        /*
+         * Map<String, State> changes = new HashMap<String, State>();
+         * 
+         * if (_vmName != null) { State state = getVmState(); if (state != null)
+         * { changes.put(_vmName, state); } }
+         */
+
+        return states;
+    }
+
+	@Override
+	public StartupCommand[] initialize() {
+		StartupRoutingCommand cmd = new StartupRoutingCommand(0, 0, 0, 0, null, Hypervisor.HypervisorType.BareMetal, new HashMap<String, String>(), null);
+		cmd.setDataCenter(_zone);
+		cmd.setPod(_pod);
+		cmd.setCluster(_cluster);
+		cmd.setGuid(_uuid);
+		cmd.setName(_ip);
+		cmd.setPrivateIpAddress(_ip);
+		cmd.setStorageIpAddress(_ip);
+		cmd.setVersion(BareMetalResourceBase.class.getPackage().getImplementationVersion());
+		cmd.setCpus((int) _cpuNum);
+		cmd.setSpeed(_cpuCapacity);
+		cmd.setMemory(_memCapacity);
+		cmd.setPrivateMacAddress(_mac);
+		cmd.setPublicMacAddress(_mac);
+		cmd.setStateChanges(fullSync());
+		return new StartupCommand[] { cmd };
+	}
+
+	private boolean ipmiPing() {
+		return doScript(_pingCommand);
+	}
+
+	@Override
+	public PingCommand getCurrentStatus(long id) {
+		try {
+			if (!ipmiPing()) {
+				Thread.sleep(1000);
+				if (!ipmiPing()) {
+					s_logger.warn("Cannot ping ipmi nic " + _ip);
+					return null;
+				}
+			}
+		} catch (Exception e) {
+			s_logger.debug("Cannot ping ipmi nic " + _ip, e);
+			return null;
+		}
+
+		return new PingRoutingCommand(getType(), id, deltaSync());
+	}
+
+	protected Answer execute(IpmISetBootDevCommand cmd) {
+		Script bootCmd = null;
+		if (cmd.getBootDev() == BootDev.disk) {
+			bootCmd = _setDiskBootCommand;
+		} else if (cmd.getBootDev() == BootDev.pxe) {
+			bootCmd = _setPxeBootCommand;
+		} else {
+			throw new CloudRuntimeException("Unkonwn boot dev " + cmd.getBootDev());
+		}
+
+		String bootDev = cmd.getBootDev().name();
+		if (!doScript(bootCmd)) {
+			s_logger.warn("Set " + _ip + " boot dev to " + bootDev + "failed");
+			return new Answer(cmd, false, "Set " + _ip + " boot dev to " + bootDev + "failed");
+		}
+
+		s_logger.warn("Set " + _ip + " boot dev to " + bootDev + "Success");
+		return new Answer(cmd, true, "Set " + _ip + " boot dev to " + bootDev + "Success");
+	}
+
+	protected MaintainAnswer execute(MaintainCommand cmd) {
+		return new MaintainAnswer(cmd, false);
+	}
+
+	protected PrepareForMigrationAnswer execute(PrepareForMigrationCommand cmd) {
+		return new PrepareForMigrationAnswer(cmd);
+	}
+
+	protected MigrateAnswer execute(MigrateCommand cmd) {
+		if (!doScript(_powerOffCommand)) {
+			return new MigrateAnswer(cmd, false, "IPMI power off failed", null);
+		}
+		return new MigrateAnswer(cmd, true, "success", null);
+	}
+
+	protected CheckVirtualMachineAnswer execute(final CheckVirtualMachineCommand cmd) {
+		return new CheckVirtualMachineAnswer(cmd, State.Stopped, null);
+	}
+
+	protected Answer execute(IpmiBootorResetCommand cmd) {
+		if (!doScript(_bootOrRebootCommand)) {
+			return new Answer(cmd, false, "IPMI boot or reboot failed");
+		}
+		return new Answer(cmd, true, "Success");
+
+	}
+
+	protected CheckNetworkAnswer execute(CheckNetworkCommand cmd) {
+		return new CheckNetworkAnswer(cmd, true, "Success");
+	}
+	
+	protected Answer execute(SecurityGroupRulesCmd cmd) {

+	    SecurityGroupHttpClient hc = new SecurityGroupHttpClient();

+	    return hc.call(cmd.getGuestIp(), cmd);
+	}
+
+    @Override
+    public Answer executeRequest(Command cmd) {
+        try {
+            if (cmd instanceof ReadyCommand) {
+                return execute((ReadyCommand) cmd);
+            } else if (cmd instanceof StartCommand) {
+                return execute((StartCommand) cmd);
+            } else if (cmd instanceof StopCommand) {
+                return execute((StopCommand) cmd);
+            } else if (cmd instanceof RebootCommand) {
+                return execute((RebootCommand) cmd);
+            } else if (cmd instanceof IpmISetBootDevCommand) {
+                return execute((IpmISetBootDevCommand) cmd);
+            } else if (cmd instanceof MaintainCommand) {
+                return execute((MaintainCommand) cmd);
+            } else if (cmd instanceof PrepareForMigrationCommand) {
+                return execute((PrepareForMigrationCommand) cmd);
+            } else if (cmd instanceof MigrateCommand) {
+                return execute((MigrateCommand) cmd);
+            } else if (cmd instanceof CheckVirtualMachineCommand) {
+                return execute((CheckVirtualMachineCommand) cmd);
+            } else if (cmd instanceof IpmiBootorResetCommand) {
+                return execute((IpmiBootorResetCommand) cmd);
+            } else if (cmd instanceof SecurityGroupRulesCmd) {
+                return execute((SecurityGroupRulesCmd) cmd);
+            } else if (cmd instanceof CheckNetworkCommand) {
+                return execute((CheckNetworkCommand) cmd);
+            } else {
+                return Answer.createUnsupportedCommandAnswer(cmd);
+            }
+        } catch (Throwable t) {
+            s_logger.debug(t.getMessage(), t);
+            return new Answer(cmd, false, t.getMessage());
+        }
+    }
+
+	protected boolean isPowerOn(String str) {
+		if (str.startsWith("Chassis Power is on")) {
+			return true;
+		} else if (str.startsWith("Chassis Power is off")) {
+			return false;
+		} else {
+			throw new CloudRuntimeException("Cannot parse IPMI power status " + str);
+		}
+	}
+
+	protected RebootAnswer execute(final RebootCommand cmd) {
+		if (!doScript(_rebootCommand)) {
+			return new RebootAnswer(cmd, "IPMI reboot failed", false);
+		}
+
+		return new RebootAnswer(cmd, "reboot succeeded", true);
+	}
+
+	protected StopAnswer execute(final StopCommand cmd) {
+		boolean success = false;
+		int count = 0;
+		Script powerOff = _powerOffCommand;
+
+		while (count < 10) {
+			if (!doScript(powerOff)) {
+				break;
+			}
+
+			try {
+				Thread.sleep(1000);
+			} catch (InterruptedException e) {
+				break;
+			}
+
+			OutputInterpreter.AllLinesParser interpreter = new OutputInterpreter.AllLinesParser();
+			if (!doScript(_getStatusCommand, interpreter)) {
+				s_logger.warn("Cannot get power status of " + _name + ", assume VM state was not changed");
+				break;
+			}
+
+			if (!isPowerOn(interpreter.getLines())) {
+				success = true;
+				break;
+			} else {
+				powerOff = _forcePowerOffCommand;
+			}
+
+			count++;
+		}
+
+		return success ? new StopAnswer(cmd, "Success", 0, true) : new StopAnswer(cmd, "IPMI power off failed", false);
+	}
+
+	protected StartAnswer execute(StartCommand cmd) {
+		VirtualMachineTO vm = cmd.getVirtualMachine();
+		State state = State.Stopped;
+
+		try {
+			changeVmState(vm.getName(), State.Starting);
+
+			OutputInterpreter.AllLinesParser interpreter = new OutputInterpreter.AllLinesParser();
+			if (!doScript(_getStatusCommand, interpreter)) {
+				return new StartAnswer(cmd, "Cannot get current power status of " + _name);
+			}
+
+			if (isPowerOn(interpreter.getLines())) {
+				if (!doScript(_rebootCommand)) {
+					return new StartAnswer(cmd, "IPMI reboot failed");
+				}
+			} else {
+				if (!doScript(_powerOnCommand)) {
+					return new StartAnswer(cmd, "IPMI power on failed");
+				}
+			}

+			
+			if (_isEchoScAgent) {

+			    SecurityGroupHttpClient hc = new SecurityGroupHttpClient();

+			    boolean echoRet = hc.echo(vm.getNics()[0].getIp(), TimeUnit.MINUTES.toMillis(30), TimeUnit.MINUTES.toMillis(1));

+			    if (!echoRet) {
+			        return new StartAnswer(cmd, String.format("Call security group agent on vm[%s] timeout", vm.getNics()[0].getIp()));

+			    }
+			}
+
+			s_logger.debug("Start bare metal vm " + vm.getName() + "successfully");
+			state = State.Running;
+			_vmName = vm.getName();
+			return new StartAnswer(cmd);
+		} finally {
+			if (state != State.Stopped) {
+				changeVmState(vm.getName(), state);
+			} else {
+				removeVmState(vm.getName());
+			}
+		}
+	}
+
+	protected HashMap<String, State> deltaSync() {
+		final HashMap<String, State> changes = new HashMap<String, State>();
+		/*
+		 * Disable sync until we find a way that only tracks status but not does
+		 * action
+		 * 
+		 * The scenario is: Baremetal will reboot host when creating template.
+		 * Given most servers take a long time to boot up, there would be a
+		 * period that mgmt server finds the host is stopped through fullsync.
+		 * Then mgmt server updates database with marking the host as stopped,
+		 * after that, the host comes up and full sync then indicates it's
+		 * running. Because in database the host is already stopped, mgmt server
+		 * sends out a stop command. As a result, creating image gets never
+		 * happened.
+		 * 
+		 * if (_vmName == null) { return null; }
+		 * 
+		 * State newState = getVmState(); if (newState == null) {
+		 * s_logger.warn("Cannot get power state of VM " + _vmName); return
+		 * null; }
+		 * 
+		 * final State oldState = removeVmState(_vmName); if (oldState == null)
+		 * { changeVmState(_vmName, newState); changes.put(_vmName, newState); }
+		 * else if (oldState == State.Starting) { if (newState == State.Running)
+		 * { changeVmState(_vmName, newState); } else if (newState ==
+		 * State.Stopped) { s_logger.debug("Ignoring vm " + _vmName +
+		 * " because of a lag in starting the vm."); } } else if (oldState ==
+		 * State.Migrating) {
+		 * s_logger.warn("How can baremetal VM get into migrating state???"); }
+		 * else if (oldState == State.Stopping) { if (newState == State.Stopped)
+		 * { changeVmState(_vmName, newState); } else if (newState ==
+		 * State.Running) { s_logger.debug("Ignoring vm " + _vmName +
+		 * " because of a lag in stopping the vm. "); } } else if (oldState !=
+		 * newState) { changeVmState(_vmName, newState); changes.put(_vmName,
+		 * newState); }
+		 */
+		return changes;
+
+	}
+
+	protected ReadyAnswer execute(ReadyCommand cmd) {
+		// derived resource should check if the PXE server is ready
+		s_logger.debug("Bare metal resource " + _name + " is ready");
+		return new ReadyAnswer(cmd);
+	}
+
+	@Override
+	public void disconnected() {
+
+	}
+
+	@Override
+	public IAgentControl getAgentControl() {
+		return _agentControl;
+	}
+
+	@Override
+	public void setAgentControl(IAgentControl agentControl) {
+		_agentControl = agentControl;
+	}
+
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetaNetworkGuru.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetaNetworkGuru.java
new file mode 100755
index 0000000..5414106
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetaNetworkGuru.java
@@ -0,0 +1,173 @@
+// 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
+package com.cloud.baremetal.networkservice;

+

+import java.net.URI;
+
+import javax.ejb.Local;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.log4j.Logger;
+
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.Pod;
+import com.cloud.dc.PodVlanMapVO;
+import com.cloud.dc.Vlan;
+import com.cloud.dc.Vlan.VlanType;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.PodVlanMapDao;
+import com.cloud.dc.dao.VlanDao;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.exception.InsufficientVirtualNetworkCapcityException;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.network.IPAddressVO;
+import com.cloud.network.Network;
+import com.cloud.network.NetworkManager;
+import com.cloud.network.Networks.AddressFormat;
+import com.cloud.network.Networks.BroadcastDomainType;
+import com.cloud.network.addr.PublicIp;
+import com.cloud.network.dao.IPAddressDao;
+import com.cloud.network.guru.DirectPodBasedNetworkGuru;
+import com.cloud.network.guru.NetworkGuru;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.utils.component.Inject;
+import com.cloud.utils.db.Transaction;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+

+@Local(value = { NetworkGuru.class })

+public class BaremetaNetworkGuru extends DirectPodBasedNetworkGuru {

+    private static final Logger s_logger = Logger.getLogger(BaremetaNetworkGuru.class);

+    @Inject

+    private HostDao _hostDao;
+    @Inject
+    DataCenterDao _dcDao;
+    @Inject
+    VlanDao _vlanDao;
+    @Inject
+    NetworkManager _networkMgr;
+    @Inject
+    IPAddressDao _ipAddressDao;
+    @Inject
+    NetworkOfferingDao _networkOfferingDao;
+    @Inject
+    PodVlanMapDao _podVlanDao;

+

+    @Override

+    public void reserve(NicProfile nic, Network network, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest, ReservationContext context)

+            throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException {

+        if (dest.getHost().getHypervisorType() != HypervisorType.BareMetal) {

+            super.reserve(nic, network, vm, dest, context);

+            return;

+        }

+

+        HostVO host = _hostDao.findById(dest.getHost().getId());
+        _hostDao.loadDetails(host);

+        String intentIp = host.getDetail(ApiConstants.IP_ADDRESS);

+        if (intentIp == null) {

+            super.reserve(nic, network, vm, dest, context);

+            return;

+        }
+        

+        String oldIp = nic.getIp4Address();

+        boolean getNewIp = false;

+        if (oldIp == null) {

+            getNewIp = true;

+        } else {

+            // we need to get a new ip address if we try to deploy a vm in a

+            // different pod

+            IPAddressVO ipVO = _ipAddressDao.findByIpAndSourceNetworkId(network.getId(), oldIp);

+            if (ipVO != null) {

+                PodVlanMapVO mapVO = _podVlanDao.listPodVlanMapsByVlan(ipVO.getVlanId());

+                if (mapVO.getPodId() != dest.getPod().getId()) {

+                    Transaction txn = Transaction.currentTxn();

+                    txn.start();

+

+                    // release the old ip here

+                    _networkMgr.markIpAsUnavailable(ipVO.getId());

+                    _ipAddressDao.unassignIpAddress(ipVO.getId());

+

+                    txn.commit();

+

+                    nic.setIp4Address(null);

+                    getNewIp = true;

+                }

+            }

+        }

+

+        if (getNewIp) {

+            // we don't set reservationStrategy to Create because we need this

+            // method to be called again for the case when vm fails to deploy in

+            // Pod1, and we try to redeploy it in Pod2

+            getBaremetalIp(nic, dest.getPod(), vm, network, intentIp);

+        }

+

+        DataCenter dc = _dcDao.findById(network.getDataCenterId());

+        nic.setDns1(dc.getDns1());

+        nic.setDns2(dc.getDns2());

+

+        /*

+         * Pod pod = dest.getPod(); Pair<String, Long> ip =

+         * _dcDao.allocatePrivateIpAddress(dest.getDataCenter().getId(),

+         * dest.getPod().getId(), nic.getId(), context.getReservationId(),

+         * intentIp); if (ip == null) { throw new

+         * InsufficientAddressCapacityException

+         * ("Unable to get a management ip address", Pod.class, pod.getId()); }

+         * 

+         * nic.setIp4Address(ip.first());

+         * nic.setMacAddress(NetUtils.long2Mac(NetUtils

+         * .createSequenceBasedMacAddress(ip.second())));

+         * nic.setGateway(pod.getGateway()); nic.setFormat(AddressFormat.Ip4);

+         * String netmask = NetUtils.getCidrNetmask(pod.getCidrSize());

+         * nic.setNetmask(netmask);

+         * nic.setBroadcastType(BroadcastDomainType.Native);

+         * nic.setBroadcastUri(null); nic.setIsolationUri(null);

+         */

+

+        s_logger.debug("Allocated a nic " + nic + " for " + vm);

+    }

+
+    private void getBaremetalIp(NicProfile nic, Pod pod, VirtualMachineProfile<? extends VirtualMachine> vm, Network network, String requiredIp)

+            throws InsufficientVirtualNetworkCapcityException, InsufficientAddressCapacityException, ConcurrentOperationException {

+        DataCenter dc = _dcDao.findById(pod.getDataCenterId());

+        if (nic.getIp4Address() == null) {

+            s_logger.debug(String.format("Requiring ip address: %s", nic.getIp4Address()));

+            PublicIp ip = _networkMgr.assignPublicIpAddress(dc.getId(), pod.getId(), vm.getOwner(), VlanType.DirectAttached, network.getId(), requiredIp, false);

+            nic.setIp4Address(ip.getAddress().toString());

+            nic.setFormat(AddressFormat.Ip4);

+            nic.setGateway(ip.getGateway());

+            nic.setNetmask(ip.getNetmask());

+            if (ip.getVlanTag() != null && ip.getVlanTag().equalsIgnoreCase(Vlan.UNTAGGED)) {

+                nic.setIsolationUri(URI.create("ec2://" + Vlan.UNTAGGED));

+                nic.setBroadcastUri(URI.create("vlan://" + Vlan.UNTAGGED));

+                nic.setBroadcastType(BroadcastDomainType.Native);

+            }

+            nic.setReservationId(String.valueOf(ip.getVlanTag()));

+            nic.setMacAddress(ip.getMacAddress());

+        }

+        nic.setDns1(dc.getDns1());

+        nic.setDns2(dc.getDns2());

+    }

+}

diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java
new file mode 100755
index 0000000..968aa6d
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpElement.java
@@ -0,0 +1,178 @@
+// 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
+package com.cloud.baremetal.networkservice;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.baremetal.database.BaremetalDhcpVO;
+import com.cloud.baremetal.database.BaremetalPxeVO;
+import com.cloud.dc.Pod;
+import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.Host;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.network.Network;
+import com.cloud.network.PhysicalNetworkServiceProvider;
+import com.cloud.network.Network.Capability;
+import com.cloud.network.Network.GuestType;
+import com.cloud.network.Network.Provider;
+import com.cloud.network.Network.Service;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.element.DhcpServiceProvider;
+import com.cloud.network.element.IpDeployer;
+import com.cloud.network.element.NetworkElement;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.utils.component.AdapterBase;
+import com.cloud.utils.component.Inject;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.SearchCriteria.Op;
+import com.cloud.utils.db.SearchCriteria2;
+import com.cloud.utils.db.SearchCriteriaService;
+import com.cloud.utils.db.Transaction;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.NicVO;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.Type;
+import com.cloud.vm.dao.NicDao;
+import com.cloud.vm.VirtualMachineProfile;
+
+@Local(value = NetworkElement.class)
+public class BaremetalDhcpElement extends AdapterBase implements DhcpServiceProvider {
+    private static final Logger s_logger = Logger.getLogger(BaremetalDhcpElement.class);
+    private static final Map<Service, Map<Capability, String>> capabilities;
+    
+    @Inject NicDao _nicDao;
+    @Inject BaremetalDhcpManager _dhcpMgr;
+    
+    static {
+        Capability cap = new Capability(BaremetalDhcpManager.BAREMETAL_DHCP_SERVICE_CAPABITLITY);
+        Map<Capability, String> baremetalCaps = new HashMap<Capability, String>();
+        baremetalCaps.put(cap, null);
+        capabilities = new HashMap<Service, Map<Capability, String>>();
+        capabilities.put(Service.Dhcp, baremetalCaps);
+    }
+    
+    @Override
+    public Map<Service, Map<Capability, String>> getCapabilities() {
+        return capabilities;
+    }
+
+    @Override
+    public Provider getProvider() {
+        return BaremetalDhcpManager.BAREMETAL_DHCP_SERVICE_PROVIDER;
+    }
+
+    private boolean canHandle(DeployDestination dest, TrafficType trafficType, GuestType networkType) {
+        Pod pod = dest.getPod();
+        if (pod != null && dest.getDataCenter().getNetworkType() == NetworkType.Basic && trafficType == TrafficType.Guest) {
+            SearchCriteriaService<BaremetalDhcpVO, BaremetalDhcpVO> sc = SearchCriteria2.create(BaremetalDhcpVO.class);
+            sc.addAnd(sc.getEntity().getPodId(), Op.EQ, pod.getId());
+            return sc.find() != null;
+        }
+        
+        return false;
+    }
+    
+    @Override
+    public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context)
+            throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
+        if (offering.isSystemOnly() || !canHandle(dest, offering.getTrafficType(), network.getGuestType())) {
+            s_logger.debug("BaremetalDhcpElement can not handle networkoffering: " + offering.getName());
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    @DB
+    public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest,
+            ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
+        Host host = dest.getHost();
+        if (vm.getType() != Type.User || vm.getHypervisorType() != HypervisorType.BareMetal) {
+            return false;
+        }
+        
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+        nic.setMacAddress(host.getPrivateMacAddress());
+        NicVO vo = _nicDao.findById(nic.getId());
+        assert vo != null : "Where ths nic " + nic.getId() + " going???";
+        vo.setMacAddress(nic.getMacAddress());
+        _nicDao.update(vo.getId(), vo);
+        txn.commit();
+        return true;
+    }
+
+    @Override
+    public boolean release(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, ReservationContext context)
+            throws ConcurrentOperationException, ResourceUnavailableException {
+        return true;
+    }
+
+    @Override
+    public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException {
+        return true;
+    }
+
+    @Override
+    public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException {
+        return true;
+    }
+
+    @Override
+    public boolean isReady(PhysicalNetworkServiceProvider provider) {
+        return true;
+    }
+
+    @Override
+    public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException,
+            ResourceUnavailableException {
+        return true;
+    }
+
+    @Override
+    public boolean canEnableIndividualServices() {
+        return false;
+    }
+
+    @Override
+    public boolean verifyServicesCombination(Set<Service> services) {
+        return true;
+    }
+    
+    public boolean addDhcpEntry(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest,
+            ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
+        if (vm.getHypervisorType() != HypervisorType.BareMetal || !canHandle(dest, network.getTrafficType(), network.getGuestType())) {
+            return false;
+        }
+        return _dhcpMgr.addVirtualMachineIntoNetwork(network, nic, vm, dest, context);
+    }
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManager.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManager.java
new file mode 100644
index 0000000..a9c63bf
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManager.java
@@ -0,0 +1,58 @@
+// 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.util.List;
+
+import com.cloud.baremetal.database.BaremetalDhcpVO;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.Host;
+import com.cloud.network.Network;
+import com.cloud.network.Network.Provider;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.component.Manager;
+import com.cloud.utils.component.PluggableService;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+
+public interface BaremetalDhcpManager extends Manager, PluggableService {
+    public static enum BaremetalDhcpType {
+        DNSMASQ,
+        DHCPD,
+    }
+	
+	boolean addVirtualMachineIntoNetwork(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> profile, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException;
+	
+	BaremetalDhcpVO addDchpServer(AddBaremetalDhcpCmd cmd);
+	
+	BaremetalDhcpResponse generateApiResponse(BaremetalDhcpVO vo);
+	
+	List<BaremetalDhcpResponse> listBaremetalDhcps(ListBaremetalDhcpCmd cmd);
+	
+	public static final String BAREMETAL_DHCP_SERVICE_CAPABITLITY = "BaremetalDhcp";
+	public static final String BAREMETAL_DHCP_SERVICE_PROPERTIES = "baremetaldhcp_commands.properties";
+	public static final Provider BAREMETAL_DHCP_SERVICE_PROVIDER = new Provider("BaremetalDhcpProvider", true);
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java
new file mode 100755
index 0000000..ae8482c
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpManagerImpl.java
@@ -0,0 +1,323 @@
+// 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.net.URI;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.AgentManager;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.agent.api.StartupExternalDhcpCommand;
+import com.cloud.agent.api.routing.DhcpEntryCommand;
+import com.cloud.baremetal.database.BaremetalDhcpDao;
+import com.cloud.baremetal.database.BaremetalDhcpVO;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.HostPodVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.dc.dao.HostPodDao;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.Host;
+import com.cloud.host.Host.Type;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.network.Network;
+import com.cloud.network.PhysicalNetworkServiceProvider;
+import com.cloud.network.PhysicalNetworkVO;
+import com.cloud.network.dao.PhysicalNetworkDao;
+import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;
+import com.cloud.network.dao.PhysicalNetworkServiceProviderVO;
+import com.cloud.resource.ResourceManager;
+import com.cloud.resource.ResourceStateAdapter;
+import com.cloud.resource.ServerResource;
+import com.cloud.resource.UnableDeleteHostException;
+import com.cloud.utils.component.Inject;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.SearchCriteria.Op;
+import com.cloud.utils.db.SearchCriteria2;
+import com.cloud.utils.db.SearchCriteriaService;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.dao.NicDao;
+import com.cloud.vm.dao.UserVmDao;
+
+@Local(value = { BaremetalDhcpManager.class })
+public class BaremetalDhcpManagerImpl implements BaremetalDhcpManager, ResourceStateAdapter {
+    private static final org.apache.log4j.Logger s_logger = Logger.getLogger(BaremetalDhcpManagerImpl.class);
+    protected String _name;
+    @Inject
+    DataCenterDao _dcDao;
+    @Inject
+    HostDao _hostDao;
+    @Inject
+    AgentManager _agentMgr;
+    @Inject
+    HostPodDao _podDao;
+    @Inject
+    UserVmDao _userVmDao;
+    @Inject
+    ResourceManager _resourceMgr;
+    @Inject
+    NicDao _nicDao;
+    @Inject
+    PhysicalNetworkDao _physicalNetworkDao;
+    @Inject
+    PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao;
+    @Inject
+    BaremetalDhcpDao _extDhcpDao;
+
+    @Override
+    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+        _resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this);
+        return true;
+    }
+
+    @Override
+    public boolean start() {
+        return true;
+    }
+
+    @Override
+    public boolean stop() {
+        _resourceMgr.unregisterResourceStateAdapter(this.getClass().getSimpleName());
+        return true;
+    }
+
+    @Override
+    public String getName() {
+        return _name;
+    }
+
+    protected String getDhcpServerGuid(String zoneId, String name, String ip) {
+        return zoneId + "-" + name + "-" + ip;
+    }
+
+    @Override
+    public boolean addVirtualMachineIntoNetwork(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> profile,
+            DeployDestination dest, ReservationContext context) throws ResourceUnavailableException {
+        Long zoneId = profile.getVirtualMachine().getDataCenterIdToDeployIn();
+        Long podId = profile.getVirtualMachine().getPodIdToDeployIn();
+        List<HostVO> hosts = _resourceMgr.listAllUpAndEnabledHosts(Type.BaremetalDhcp, null, podId, zoneId);
+        if (hosts.size() == 0) {
+            throw new CloudRuntimeException("No external Dhcp found in zone " + zoneId + " pod " + podId);
+        }
+
+        if (hosts.size() > 1) {
+            throw new CloudRuntimeException("Something wrong, more than 1 external Dhcp found in zone " + zoneId + " pod " + podId);
+        }
+
+        HostVO h = hosts.get(0);
+        String dns = nic.getDns1();
+        if (dns == null) {
+            dns = nic.getDns2();
+        }
+        DhcpEntryCommand dhcpCommand = new DhcpEntryCommand(nic.getMacAddress(), nic.getIp4Address(), profile.getVirtualMachine().getHostName(), dns,
+                nic.getGateway());
+        String errMsg = String.format("Set dhcp entry on external DHCP %1$s failed(ip=%2$s, mac=%3$s, vmname=%4$s)", h.getPrivateIpAddress(),
+                nic.getIp4Address(), nic.getMacAddress(), profile.getVirtualMachine().getHostName());
+        // prepareBareMetalDhcpEntry(nic, dhcpCommand);
+        try {
+            Answer ans = _agentMgr.send(h.getId(), dhcpCommand);
+            if (ans.getResult()) {
+                s_logger.debug(String.format("Set dhcp entry on external DHCP %1$s successfully(ip=%2$s, mac=%3$s, vmname=%4$s)", h.getPrivateIpAddress(),
+                        nic.getIp4Address(), nic.getMacAddress(), profile.getVirtualMachine().getHostName()));
+                return true;
+            } else {
+                s_logger.debug(errMsg + " " + ans.getDetails());
+                throw new ResourceUnavailableException(errMsg, DataCenter.class, zoneId);
+            }
+        } catch (Exception e) {
+            s_logger.debug(errMsg, e);
+            throw new ResourceUnavailableException(errMsg + e.getMessage(), DataCenter.class, zoneId);
+        }
+    }
+
+    @Override
+    public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+    @Override
+    public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map<String, String> details,
+            List<String> hostTags) {
+        if (!(startup[0] instanceof StartupExternalDhcpCommand)) {
+            return null;
+        }
+
+        host.setType(Host.Type.BaremetalDhcp);
+        return host;
+    }
+
+    @Override
+    public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
+
+    @Override
+    @DB
+    public BaremetalDhcpVO addDchpServer(AddBaremetalDhcpCmd cmd) {
+        PhysicalNetworkVO pNetwork = null;
+        long zoneId;
+
+        if (cmd.getPhysicalNetworkId() == null || cmd.getUrl() == null || cmd.getUsername() == null || cmd.getPassword() == null) {
+            throw new IllegalArgumentException("At least one of the required parameters(physical network id, url, username, password) is null");
+        }
+
+        pNetwork = _physicalNetworkDao.findById(cmd.getPhysicalNetworkId());
+        if (pNetwork == null) {
+            throw new IllegalArgumentException("Could not find phyical network with ID: " + cmd.getPhysicalNetworkId());
+        }
+        zoneId = pNetwork.getDataCenterId();
+        DataCenterVO zone = _dcDao.findById(zoneId);
+
+        PhysicalNetworkServiceProviderVO ntwkSvcProvider = _physicalNetworkServiceProviderDao.findByServiceProvider(pNetwork.getId(),
+        		BaremetalDhcpManager.BAREMETAL_DHCP_SERVICE_PROVIDER.getName());
+        if (ntwkSvcProvider == null) {
+            throw new CloudRuntimeException("Network Service Provider: " + BaremetalDhcpManager.BAREMETAL_DHCP_SERVICE_PROVIDER.getName() + " is not enabled in the physical network: "
+                    + cmd.getPhysicalNetworkId() + "to add this device");
+        } else if (ntwkSvcProvider.getState() == PhysicalNetworkServiceProvider.State.Shutdown) {
+            throw new CloudRuntimeException("Network Service Provider: " + ntwkSvcProvider.getProviderName()
+                    + " is in shutdown state in the physical network: " + cmd.getPhysicalNetworkId() + "to add this device");
+        }
+
+        HostPodVO pod = _podDao.findById(cmd.getPodId());
+        if (pod == null) {
+            throw new IllegalArgumentException("Could not find pod with ID: " + cmd.getPodId());
+        }
+
+        List<HostVO> dhcps = _resourceMgr.listAllUpAndEnabledHosts(Host.Type.BaremetalDhcp, null, cmd.getPodId(), zoneId);
+        if (dhcps.size() != 0) {
+            throw new IllegalArgumentException("Already had a DHCP server in Pod: " + cmd.getPodId() + " zone: " + zoneId);
+        }
+
+        URI uri;
+        try {
+            uri = new URI(cmd.getUrl());
+        } catch (Exception e) {
+            s_logger.debug(e);
+            throw new IllegalArgumentException(e.getMessage());
+        }
+
+        String ipAddress = uri.getHost();
+        String guid = getDhcpServerGuid(Long.toString(zoneId) + "-" + Long.toString(cmd.getPodId()), "ExternalDhcp", ipAddress);
+        Map params = new HashMap<String, String>();
+        params.put("type", cmd.getDhcpType());
+        params.put("zone", Long.toString(zoneId));
+        params.put("pod", cmd.getPodId().toString());
+        params.put("ip", ipAddress);
+        params.put("username", cmd.getUsername());
+        params.put("password", cmd.getPassword());
+        params.put("guid", guid);
+        params.put("gateway", pod.getGateway());
+        String dns = zone.getDns1();
+        if (dns == null) {
+            dns = zone.getDns2();
+        }
+        params.put("dns", dns);
+
+        ServerResource resource = null;
+        try {
+            if (cmd.getDhcpType().equalsIgnoreCase(BaremetalDhcpType.DNSMASQ.toString())) {
+                resource = new BaremetalDnsmasqResource();
+                resource.configure("Dnsmasq resource", params);
+            } else if (cmd.getDhcpType().equalsIgnoreCase(BaremetalDhcpType.DHCPD.toString())) {
+                resource = new BaremetalDhcpdResource();
+                resource.configure("Dhcpd resource", params);
+            } else {
+                throw new CloudRuntimeException("Unsupport DHCP server type: " + cmd.getDhcpType());
+            }
+        } catch (Exception e) {
+            s_logger.debug(e);
+            throw new CloudRuntimeException(e.getMessage());
+        }
+
+        Host dhcpServer = _resourceMgr.addHost(zoneId, resource, Host.Type.BaremetalDhcp, params);
+        if (dhcpServer == null) {
+            throw new CloudRuntimeException("Cannot add external Dhcp server as a host");
+        }
+
+        BaremetalDhcpVO vo = new BaremetalDhcpVO();
+        vo.setDeviceType(cmd.getDhcpType());
+        vo.setHostId(dhcpServer.getId());
+        vo.setNetworkServiceProviderId(ntwkSvcProvider.getId());
+        vo.setPhysicalNetworkId(cmd.getPhysicalNetworkId());
+        vo.setPodId(cmd.getPodId());
+        Transaction txn = Transaction.currentTxn();
+        txn.start();
+        _extDhcpDao.persist(vo);
+        txn.commit();
+        return vo;
+    }
+
+    @Override
+    public BaremetalDhcpResponse generateApiResponse(BaremetalDhcpVO vo) {
+        BaremetalDhcpResponse response = new BaremetalDhcpResponse();
+        response.setDeviceType(vo.getDeviceType());
+        response.setId(String.valueOf(vo.getId()));
+        response.setPhysicalNetworkId(String.valueOf(vo.getPhysicalNetworkId()));
+        response.setProviderId(String.valueOf(vo.getNetworkServiceProviderId()));
+        return response;
+    }
+
+    @Override
+    public List<BaremetalDhcpResponse> listBaremetalDhcps(ListBaremetalDhcpCmd cmd) {
+        SearchCriteriaService<BaremetalDhcpVO, BaremetalDhcpVO> sc = SearchCriteria2.create(BaremetalDhcpVO.class);
+        if (cmd.getDeviceType() != null) {
+        	sc.addAnd(sc.getEntity().getDeviceType(), Op.EQ, cmd.getDeviceType());
+        }
+        if (cmd.getPodId() != null) {
+            sc.addAnd(sc.getEntity().getPodId(), Op.EQ, cmd.getPodId());
+            if (cmd.getId() != null) {
+                sc.addAnd(sc.getEntity().getId(), Op.EQ, cmd.getId());
+            }
+        }
+        List<BaremetalDhcpVO> vos = sc.list();
+        List<BaremetalDhcpResponse> responses = new ArrayList<BaremetalDhcpResponse>(vos.size());
+        for (BaremetalDhcpVO vo : vos) {
+            responses.add(generateApiResponse(vo));
+        }
+        return responses;
+    }
+
+	@Override
+	public List<Class<?>> getCommands() {
+		return null;
+	}
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResourceBase.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResourceBase.java
new file mode 100644
index 0000000..0541415
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResourceBase.java
@@ -0,0 +1,174 @@
+// 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.util.HashMap;
+import java.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.IAgentControl;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.PingCommand;
+import com.cloud.agent.api.PingRoutingCommand;
+import com.cloud.agent.api.ReadyAnswer;
+import com.cloud.agent.api.ReadyCommand;
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.agent.api.StartupExternalDhcpCommand;
+import com.cloud.agent.api.StartupPxeServerCommand;
+import com.cloud.host.Host.Type;
+import com.cloud.resource.ServerResource;
+import com.cloud.utils.script.Script;
+import com.cloud.utils.ssh.SSHCmdHelper;
+import com.cloud.vm.VirtualMachine.State;
+import com.trilead.ssh2.SCPClient;
+
+public class BaremetalDhcpResourceBase implements ServerResource {
+	private static final Logger s_logger = Logger.getLogger(BaremetalDhcpResourceBase.class);
+	String _name;
+	String _guid;
+	String _username;
+	String _password;
+	String _ip;
+	String _zoneId;
+	String _podId;
+	String _gateway;
+	String _dns;
+	
+	@Override
+	public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+		_name = name;
+		_guid = (String)params.get("guid");
+		_ip = (String)params.get("ip");
+		_username = (String)params.get("username");
+		_password = (String)params.get("password");
+		_zoneId = (String)params.get("zone");
+		_podId = (String)params.get("pod");
+		_gateway = (String)params.get("gateway");
+		_dns = (String)params.get("dns");
+		
+		if (_guid == null) {
+			throw new ConfigurationException("No Guid specified");
+		}
+		
+		if (_zoneId == null) {
+			throw new ConfigurationException("No Zone specified");
+		}
+		
+		if (_podId == null) {
+			throw new ConfigurationException("No Pod specified");
+		}
+		
+		if (_ip == null) {
+			throw new ConfigurationException("No IP specified");
+		}
+		
+		if (_username == null) {
+			throw new ConfigurationException("No username specified");
+		}
+		
+		if (_password == null) {
+			throw new ConfigurationException("No password specified");
+		}
+		
+		if (_gateway == null) {
+			throw new ConfigurationException("No gateway specified");
+		}
+		
+		if (_dns == null) {
+			throw new ConfigurationException("No dns specified");
+		}
+		
+		return true;
+	}
+
+	@Override
+	public boolean start() {
+		return true;
+	}
+
+	@Override
+	public boolean stop() {
+		return true;
+	}
+
+	@Override
+	public String getName() {
+		return _name;
+	}
+
+	@Override
+	public Type getType() {
+		return Type.BaremetalDhcp;
+	}
+
+	@Override
+	public StartupCommand[] initialize() {
+		StartupExternalDhcpCommand cmd = new StartupExternalDhcpCommand();
+		cmd.setName(_name);
+		cmd.setDataCenter(_zoneId);
+		cmd.setPod(_podId);
+		cmd.setPrivateIpAddress(_ip);
+		cmd.setStorageIpAddress("");
+		cmd.setVersion("");
+		cmd.setGuid(_guid);
+		return new StartupCommand[]{cmd};
+	}
+
+	@Override
+	public PingCommand getCurrentStatus(long id) {
+		//TODO: check server
+		return new PingRoutingCommand(getType(), id, new HashMap<String, State>());
+	}
+
+	protected ReadyAnswer execute(ReadyCommand cmd) {
+		s_logger.debug("External DHCP resource " + _name + " is ready");
+		return new ReadyAnswer(cmd);
+	}
+	
+	@Override
+	public Answer executeRequest(Command cmd) {
+		if (cmd instanceof ReadyCommand) {
+			return execute((ReadyCommand) cmd);
+		} else {
+			return Answer.createUnsupportedCommandAnswer(cmd);
+		}
+	}
+
+	@Override
+	public void disconnected() {
+	}
+
+	@Override
+	public IAgentControl getAgentControl() {
+		return null;
+	}
+
+	@Override
+	public void setAgentControl(IAgentControl agentControl) {
+	}
+
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResponse.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResponse.java
new file mode 100755
index 0000000..952ac41
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpResponse.java
@@ -0,0 +1,71 @@
+// 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
+package com.cloud.baremetal.networkservice;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+
+public class BaremetalDhcpResponse extends BaseResponse {
+    @SerializedName(ApiConstants.ID) @Param(description="device id of ")
+    private String id;
+    
+    @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Param(description="the physical network to which this external dhcp device belongs to")
+    private String physicalNetworkId;
+    
+    @SerializedName(ApiConstants.PROVIDER) @Param(description="name of the provider")
+    private String providerId;
+    
+    @SerializedName(ApiConstants.DHCP_SERVER_TYPE) @Param(description="name of the provider")
+    private String deviceType;
+
+    public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getPhysicalNetworkId() {
+		return physicalNetworkId;
+	}
+
+	public void setPhysicalNetworkId(String physicalNetworkId) {
+		this.physicalNetworkId = physicalNetworkId;
+	}
+
+	public String getProviderId() {
+		return providerId;
+	}
+
+	public void setProviderId(String providerId) {
+		this.providerId = providerId;
+	}
+
+	public String getDeviceType() {
+        return deviceType;
+    }
+
+    public void setDeviceType(String deviceType) {
+        this.deviceType = deviceType;
+    }
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpdResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpdResource.java
new file mode 100755
index 0000000..a27a6f2
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDhcpdResource.java
@@ -0,0 +1,139 @@
+// 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.util.HashMap;
+import java.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.PingCommand;
+import com.cloud.agent.api.PingRoutingCommand;
+import com.cloud.agent.api.routing.DhcpEntryCommand;
+import com.cloud.utils.script.Script;
+import com.cloud.utils.ssh.SSHCmdHelper;
+import com.cloud.vm.VirtualMachine.State;
+import com.trilead.ssh2.SCPClient;
+
+public class BaremetalDhcpdResource extends BaremetalDhcpResourceBase {
+	private static final Logger s_logger = Logger.getLogger(BaremetalDhcpdResource.class);
+	
+	public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+		com.trilead.ssh2.Connection sshConnection = null;
+		try {
+			super.configure(name, params);
+			s_logger.debug(String.format("Trying to connect to DHCP server(IP=%1$s, username=%2$s, password=%3$s)", _ip, _username, "******"));
+			sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password);
+			if (sshConnection == null) {
+				throw new ConfigurationException(
+						String.format("Cannot connect to DHCP server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, "******"));
+			}
+
+			if (!SSHCmdHelper.sshExecuteCmd(sshConnection, "[ -f '/usr/sbin/dhcpd' ]")) {
+				throw new ConfigurationException("Cannot find dhcpd.conf /etc/dhcpd.conf at  on " + _ip);
+			}
+
+			SCPClient scp = new SCPClient(sshConnection);
+
+			String editHosts = "scripts/network/exdhcp/dhcpd_edithosts.py";
+			String editHostsPath = Script.findScript("", editHosts);
+			if (editHostsPath == null) {
+				throw new ConfigurationException("Can not find script dnsmasq_edithosts.sh at " + editHosts);
+			}
+			scp.put(editHostsPath, "/usr/bin/", "0755");
+			
+			String prepareDhcpdScript = "scripts/network/exdhcp/prepare_dhcpd.sh";
+			String prepareDhcpdScriptPath = Script.findScript("", prepareDhcpdScript);
+			if (prepareDhcpdScriptPath == null) {
+				throw new ConfigurationException("Can not find prepare_dhcpd.sh at " + prepareDhcpdScriptPath);
+			}
+			scp.put(prepareDhcpdScriptPath, "/usr/bin/", "0755");
+			
+			//TODO: tooooooooooooooo ugly here!!!
+			String[] ips = _ip.split("\\.");
+			ips[3] = "0";
+			StringBuffer buf = new StringBuffer();
+			int i;
+			for (i=0;i<ips.length-1;i++) {
+				buf.append(ips[i]).append(".");
+			}
+			buf.append(ips[i]);
+			String subnet = buf.toString();
+			String cmd = String.format("sh /usr/bin/prepare_dhcpd.sh %1$s", subnet);
+			if (!SSHCmdHelper.sshExecuteCmd(sshConnection, cmd)) {
+				throw new ConfigurationException("prepare Dhcpd at " + _ip + " failed, command:" + cmd);
+			}	
+			
+			s_logger.debug("Dhcpd resource configure successfully");
+			return true;
+		} catch (Exception e) {
+			s_logger.debug("Dhcpd resorce configure failed", e);
+			throw new ConfigurationException(e.getMessage());
+		} finally {
+			SSHCmdHelper.releaseSshConnection(sshConnection);
+		}
+	}
+	
+	@Override
+	public PingCommand getCurrentStatus(long id) {
+		com.trilead.ssh2.Connection sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password);
+		if (sshConnection == null) {
+			return null;
+		} else {
+			SSHCmdHelper.releaseSshConnection(sshConnection);
+			return new PingRoutingCommand(getType(), id, new HashMap<String, State>());
+		}
+	}
+	
+	Answer execute(DhcpEntryCommand cmd) {
+		com.trilead.ssh2.Connection sshConnection = null;
+		try {
+			sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password);
+			if (sshConnection == null) {
+				return new Answer(cmd, false, "ssh authenticate failed");
+			}
+			String addDhcp = String.format("python /usr/bin/dhcpd_edithosts.py %1$s %2$s %3$s %4$s %5$s %6$s",
+					cmd.getVmMac(), cmd.getVmIpAddress(), cmd.getVmName(), cmd.getDns(), cmd.getGateway(), cmd.getNextServer());
+			if (!SSHCmdHelper.sshExecuteCmd(sshConnection, addDhcp)) {
+				return new Answer(cmd, false, "add Dhcp entry failed");
+			} else {
+				return new Answer(cmd);
+			}
+		} finally {
+			SSHCmdHelper.releaseSshConnection(sshConnection);
+		}
+	}
+	
+	@Override
+	public Answer executeRequest(Command cmd) {
+		if (cmd instanceof DhcpEntryCommand) {
+			return execute((DhcpEntryCommand)cmd);
+		} else {
+			return super.executeRequest(cmd);
+		}
+	}
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java
new file mode 100644
index 0000000..6841c525
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalDnsmasqResource.java
@@ -0,0 +1,129 @@
+// 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.IOException;
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.PingCommand;
+import com.cloud.agent.api.PingRoutingCommand;
+import com.cloud.agent.api.routing.DhcpEntryCommand;
+import com.cloud.utils.script.Script;
+import com.cloud.utils.ssh.SSHCmdHelper;
+import com.cloud.vm.VirtualMachine.State;
+import com.trilead.ssh2.SCPClient;
+
+public class BaremetalDnsmasqResource extends BaremetalDhcpResourceBase {
+	private static final Logger s_logger = Logger.getLogger(BaremetalDnsmasqResource.class);
+
+	public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+		com.trilead.ssh2.Connection sshConnection = null;
+		try {
+			super.configure(name, params);
+			s_logger.debug(String.format("Trying to connect to DHCP server(IP=%1$s, username=%2$s, password=%3$s)", _ip, _username, _password));
+			sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password);
+			if (sshConnection == null) {
+				throw new ConfigurationException(
+						String.format("Cannot connect to DHCP server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, _password));
+			}
+
+			if (!SSHCmdHelper.sshExecuteCmd(sshConnection, "[ -f '/usr/sbin/dnsmasq' ]")) {
+				throw new ConfigurationException("Cannot find dnsmasq at /usr/sbin/dnsmasq on " + _ip);
+			}
+
+			SCPClient scp = new SCPClient(sshConnection);
+			
+			String editHosts = "scripts/network/exdhcp/dnsmasq_edithosts.sh";
+			String editHostsPath = Script.findScript("", editHosts);
+			if (editHostsPath == null) {
+				throw new ConfigurationException("Can not find script dnsmasq_edithosts.sh at " + editHosts);
+			}
+			scp.put(editHostsPath, "/usr/bin/", "0755");
+			
+			String prepareDnsmasq = "scripts/network/exdhcp/prepare_dnsmasq.sh";
+			String prepareDnsmasqPath = Script.findScript("", prepareDnsmasq);
+			if (prepareDnsmasqPath == null) {
+				throw new ConfigurationException("Can not find script prepare_dnsmasq.sh at " + prepareDnsmasq);
+			}
+			scp.put(prepareDnsmasqPath, "/usr/bin/", "0755");
+			
+			String prepareCmd = String.format("sh /usr/bin/prepare_dnsmasq.sh %1$s %2$s %3$s", _gateway, _dns, _ip);
+			if (!SSHCmdHelper.sshExecuteCmd(sshConnection, prepareCmd)) {
+				throw new ConfigurationException("prepare dnsmasq at " + _ip + " failed");
+			}
+			
+			s_logger.debug("Dnsmasq resource configure successfully");
+			return true;
+		} catch (Exception e) {
+			s_logger.debug("Dnsmasq resorce configure failed", e);
+			throw new ConfigurationException(e.getMessage());
+		} finally {
+			SSHCmdHelper.releaseSshConnection(sshConnection);
+		}
+	}
+	
+	@Override
+	public PingCommand getCurrentStatus(long id) {
+		com.trilead.ssh2.Connection sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password);
+		if (sshConnection == null) {
+			return null;
+		} else {
+			SSHCmdHelper.releaseSshConnection(sshConnection);
+			return new PingRoutingCommand(getType(), id, new HashMap<String, State>());
+		}
+	}
+
+	Answer execute(DhcpEntryCommand cmd) {
+		com.trilead.ssh2.Connection sshConnection = null;
+		try {
+			sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password);
+			if (sshConnection == null) {
+				return new Answer(cmd, false, "ssh authenticate failed");
+			}
+			String addDhcp = String.format("/usr/bin/dnsmasq_edithosts.sh %1$s %2$s %3$s", cmd.getVmMac(), cmd.getVmIpAddress(), cmd.getVmName());
+			if (!SSHCmdHelper.sshExecuteCmd(sshConnection, addDhcp)) {
+				return new Answer(cmd, false, "add Dhcp entry failed");
+			} else {
+				return new Answer(cmd);
+			}
+		} finally {
+			SSHCmdHelper.releaseSshConnection(sshConnection);
+		}
+	}
+	
+	@Override
+	public Answer executeRequest(Command cmd) {
+		if (cmd instanceof DhcpEntryCommand) {
+			return execute((DhcpEntryCommand)cmd);
+		} else {
+			return super.executeRequest(cmd);
+		}
+	}
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java
new file mode 100755
index 0000000..938b3ac
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartPxeResource.java
@@ -0,0 +1,201 @@
+// 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
+package com.cloud.baremetal.networkservice;

+

+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.PingCommand;
+import com.cloud.agent.api.PingRoutingCommand;
+import com.cloud.agent.api.routing.VmDataCommand;
+import com.cloud.utils.script.Script;
+import com.cloud.utils.ssh.SSHCmdHelper;
+import com.cloud.vm.VirtualMachine.State;
+import com.trilead.ssh2.SCPClient;
+

+public class BaremetalKickStartPxeResource extends BaremetalPxeResourceBase {

+    private static final Logger s_logger = Logger.getLogger(BaremetalKickStartPxeResource.class);

+    private static final String _name = "BaremetalKickStartPxeResource";

+    String _tftpDir;

+

+    @Override

+    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {

+        super.configure(name, params);

+        _tftpDir = (String) params.get(BaremetalPxeService.PXE_PARAM_TFTP_DIR);

+        if (_tftpDir == null) {

+            throw new ConfigurationException("No tftp directory specified");

+        }

+

+        com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22);

+

+        s_logger.debug(String.format("Trying to connect to kickstart PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, "******"));

+        try {

+            sshConnection.connect(null, 60000, 60000);

+            if (!sshConnection.authenticateWithPassword(_username, _password)) {

+                s_logger.debug("SSH Failed to authenticate");

+                throw new ConfigurationException(String.format("Cannot connect to kickstart PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username,

+                        "******"));

+            }

+

+            String cmd = String.format("[ -f /%1$s/pxelinux.0 ]", _tftpDir);

+            if (!SSHCmdHelper.sshExecuteCmd(sshConnection, cmd)) {

+                throw new ConfigurationException("Miss files in TFTP directory at " + _tftpDir + " check if pxelinux.0 are here");

+            }

+

+            SCPClient scp = new SCPClient(sshConnection);

+            String prepareScript = "scripts/network/ping/prepare_kickstart_bootfile.py";

+            String prepareScriptPath = Script.findScript("", prepareScript);

+            if (prepareScriptPath == null) {

+                throw new ConfigurationException("Can not find prepare_kickstart_bootfile.py at " + prepareScriptPath);

+            }

+            scp.put(prepareScriptPath, "/usr/bin/", "0755");

+
+            String cpScript = "scripts/network/ping/prepare_kickstart_kernel_initrd.py";

+            String cpScriptPath = Script.findScript("", cpScript);

+            if (cpScriptPath == null) {

+                throw new ConfigurationException("Can not find prepare_kickstart_kernel_initrd.py at " + cpScriptPath);

+            }

+            scp.put(cpScriptPath, "/usr/bin/", "0755");

+            

+            String userDataScript = "scripts/network/ping/baremetal_user_data.py";

+            String userDataScriptPath = Script.findScript("", userDataScript);

+            if (userDataScriptPath == null) {

+                throw new ConfigurationException("Can not find baremetal_user_data.py at " + userDataScriptPath);

+            }

+            scp.put(userDataScriptPath, "/usr/bin/", "0755");

+

+            return true;

+        } catch (Exception e) {

+            throw new ConfigurationException(e.getMessage());

+        } finally {

+            if (sshConnection != null) {

+                sshConnection.close();

+            }

+        }

+    }
+    

+    @Override

+    public PingCommand getCurrentStatus(long id) {

+        com.trilead.ssh2.Connection sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password);

+        if (sshConnection == null) {

+            return null;

+        } else {

+            SSHCmdHelper.releaseSshConnection(sshConnection);

+            return new PingRoutingCommand(getType(), id, new HashMap<String, State>());

+        }

+    }
+    
+    private Answer execute(VmDataCommand cmd) {

+        com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22);

+        try {

+            List<String[]> vmData = cmd.getVmData();

+            StringBuilder sb = new StringBuilder();

+            for (String[] data : vmData) {

+                String folder = data[0];

+                String file = data[1];

+                String contents = (data[2] == null) ? "none" : data[2];

+                sb.append(cmd.getVmIpAddress());

+                sb.append(",");

+                sb.append(folder);

+                sb.append(",");

+                sb.append(file);

+                sb.append(",");

+                sb.append(contents);

+                sb.append(";");

+            }

+            String arg = StringUtils.stripEnd(sb.toString(), ";");

+            

+            sshConnection.connect(null, 60000, 60000);

+            if (!sshConnection.authenticateWithPassword(_username, _password)) {

+                s_logger.debug("SSH Failed to authenticate");

+                throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username,

+                        _password));

+            }

+            

+            String script = String.format("python /usr/bin/baremetal_user_data.py '%s'", arg);

+            if (!SSHCmdHelper.sshExecuteCmd(sshConnection, script)) {

+                return new Answer(cmd, false, "Failed to add user data, command:" + script);

+            }

+            

+            return new Answer(cmd, true, "Success");

+        }  catch (Exception e){

+            s_logger.debug("Prepare for creating baremetal template failed", e);

+            return new Answer(cmd, false, e.getMessage());

+        } finally {

+            if (sshConnection != null) {

+                sshConnection.close();

+            }

+        }

+    }
+    

+    @Override

+    public Answer executeRequest(Command cmd) {

+        if (cmd instanceof PrepareKickstartPxeServerCommand) {

+            return execute((PrepareKickstartPxeServerCommand) cmd);

+        } else if (cmd instanceof VmDataCommand) {

+            return execute((VmDataCommand)cmd);

+        } else {

+            return super.executeRequest(cmd);

+        }

+    }

+

+    private Answer execute(PrepareKickstartPxeServerCommand cmd) {

+        com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22);

+        try {

+            sshConnection.connect(null, 60000, 60000);

+            if (!sshConnection.authenticateWithPassword(_username, _password)) {

+                s_logger.debug("SSH Failed to authenticate");

+                throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username,

+                        _password));

+            }
+            
+            String copyTo = String.format("%s/%s", _tftpDir, cmd.getTemplateUuid());
+            String script = String.format("python /usr/bin/prepare_kickstart_kernel_initrd.py %s %s", cmd.getRepo(), copyTo);

+            
+            if (!SSHCmdHelper.sshExecuteCmd(sshConnection, script)) {

+                return new Answer(cmd, false, "prepare kickstart at pxe server " + _ip + " failed, command:" + script);

+            }   

+            

+            String kernelPath = String.format("%s/vmlinuz", cmd.getTemplateUuid());

+            String initrdPath = String.format("%s/initrd.img", cmd.getTemplateUuid());

+            script = String.format("python /usr/bin/prepare_kickstart_bootfile.py %s %s %s %s %s %s", _tftpDir, cmd.getMac(), kernelPath, initrdPath, cmd.getKsFile(), cmd.getMac());

+            if (!SSHCmdHelper.sshExecuteCmd(sshConnection, script)) {

+                return new Answer(cmd, false, "prepare kickstart at pxe server " + _ip + " failed, command:" + script);

+            }   

+            

+            s_logger.debug("Prepare kickstart PXE server successfully");

+            return new Answer(cmd, true, "Success");

+        }  catch (Exception e){

+            s_logger.debug("Prepare for kickstart server failed", e);

+            return new Answer(cmd, false, e.getMessage());

+        } finally {

+            if (sshConnection != null) {

+                sshConnection.close();

+            }

+        }

+    }

+}

diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java
new file mode 100755
index 0000000..4a2369b
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalKickStartServiceImpl.java
@@ -0,0 +1,238 @@
+// 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
+package com.cloud.baremetal.networkservice;

+

+import java.net.URI;

+import java.util.ArrayList;

+import java.util.HashMap;

+import java.util.List;

+import java.util.Map;

+

+import javax.ejb.Local;

+

+import org.apache.log4j.Logger;

+

+import com.cloud.agent.api.Answer;

+import com.cloud.agent.api.baremetal.IpmISetBootDevCommand;

+import com.cloud.agent.api.baremetal.IpmISetBootDevCommand.BootDev;

+import com.cloud.baremetal.database.BaremetalPxeDao;

+import com.cloud.baremetal.database.BaremetalPxeVO;

+import com.cloud.baremetal.networkservice.BaremetalPxeManager.BaremetalPxeType;

+import com.cloud.deploy.DeployDestination;

+import com.cloud.host.Host;

+import com.cloud.host.HostVO;

+import com.cloud.host.dao.HostDetailsDao;

+import com.cloud.network.NetworkVO;

+import com.cloud.network.PhysicalNetworkServiceProvider;

+import com.cloud.network.PhysicalNetworkVO;

+import com.cloud.network.dao.NetworkDao;

+import com.cloud.network.dao.PhysicalNetworkDao;

+import com.cloud.network.dao.PhysicalNetworkServiceProviderDao;

+import com.cloud.network.dao.PhysicalNetworkServiceProviderVO;

+import com.cloud.resource.ResourceManager;

+import com.cloud.resource.ServerResource;

+import com.cloud.storage.VMTemplateVO;

+import com.cloud.storage.dao.VMTemplateDao;

+import com.cloud.uservm.UserVm;

+import com.cloud.utils.component.Inject;

+import com.cloud.utils.db.DB;

+import com.cloud.utils.db.SearchCriteria.Op;

+import com.cloud.utils.db.SearchCriteria2;

+import com.cloud.utils.db.SearchCriteriaService;

+import com.cloud.utils.db.Transaction;

+import com.cloud.utils.exception.CloudRuntimeException;

+import com.cloud.vm.NicProfile;

+import com.cloud.vm.ReservationContext;

+import com.cloud.vm.UserVmVO;

+import com.cloud.vm.VirtualMachineProfile;

+

+@Local(value = BaremetalPxeService.class)

+public class BaremetalKickStartServiceImpl extends BareMetalPxeServiceBase implements BaremetalPxeService {

+    private static final Logger s_logger = Logger.getLogger(BaremetalKickStartServiceImpl.class);

+    @Inject

+    ResourceManager _resourceMgr;

+    @Inject

+    PhysicalNetworkDao _physicalNetworkDao;

+    @Inject

+    PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao;

+    @Inject

+    HostDetailsDao _hostDetailsDao;

+    @Inject

+    BaremetalPxeDao _pxeDao;

+    @Inject
+    NetworkDao _nwDao;

+    @Inject
+    VMTemplateDao _tmpDao;
+

+    @Override

+    public boolean prepare(VirtualMachineProfile<UserVmVO> profile, NicProfile nic, DeployDestination dest, ReservationContext context) {
+        NetworkVO nwVO = _nwDao.findById(nic.getNetworkId());
+        SearchCriteriaService<BaremetalPxeVO, BaremetalPxeVO> sc = SearchCriteria2.create(BaremetalPxeVO.class);

+        sc.addAnd(sc.getEntity().getDeviceType(), Op.EQ, BaremetalPxeType.KICK_START.toString());
+        sc.addAnd(sc.getEntity().getPhysicalNetworkId(), Op.EQ, nwVO.getPhysicalNetworkId());

+        BaremetalPxeVO pxeVo = sc.find();

+        if (pxeVo == null) {

+            throw new CloudRuntimeException("No kickstart PXE server found in pod: " + dest.getPod().getId() + ", you need to add it before starting VM");

+        }
+        VMTemplateVO template = _tmpDao.findById(profile.getTemplateId());

+

+        try {

+            String tpl = profile.getTemplate().getUrl();

+            assert tpl != null : "How can a null template get here!!!";

+            String[] tpls = tpl.split(";");

+            assert tpls.length == 2 : "Template is not correctly encoded. " + tpl;

+            PrepareKickstartPxeServerCommand cmd = new PrepareKickstartPxeServerCommand();

+            cmd.setKsFile(tpls[0]);

+            cmd.setRepo(tpls[1]);

+            cmd.setMac(nic.getMacAddress());
+            cmd.setTemplateUuid(template.getUuid());

+            Answer aws = _agentMgr.send(pxeVo.getHostId(), cmd);

+            if (!aws.getResult()) {

+                s_logger.warn("Unable to set host: " + dest.getHost().getId() + " to PXE boot because " + aws.getDetails());

+                return aws.getResult();

+            }
+            

+            IpmISetBootDevCommand bootCmd = new IpmISetBootDevCommand(BootDev.pxe);

+            aws = _agentMgr.send(dest.getHost().getId(), bootCmd);

+            if (!aws.getResult()) {

+                s_logger.warn("Unable to set host: " + dest.getHost().getId() + " to PXE boot because " + aws.getDetails());

+            }
+            

+            return aws.getResult();

+        } catch (Exception e) {

+            s_logger.warn("Cannot prepare PXE server", e);

+            return false;

+        }

+    }

+

+    @Override

+    public boolean prepareCreateTemplate(Long pxeServerId, UserVm vm, String templateUrl) {

+        // TODO Auto-generated method stub

+        return false;

+    }

+

+    @Override
+    @DB

+    public BaremetalPxeVO addPxeServer(AddBaremetalPxeCmd cmd) {

+        AddBaremetalKickStartPxeCmd kcmd = (AddBaremetalKickStartPxeCmd)cmd;

+        PhysicalNetworkVO pNetwork = null;

+        long zoneId;

+        

+        if (cmd.getPhysicalNetworkId() == null || cmd.getUrl() == null || cmd.getUsername() == null || cmd.getPassword() == null) {

+            throw new IllegalArgumentException("At least one of the required parameters(physical network id, url, username, password) is null");

+        } 

+        

+        pNetwork = _physicalNetworkDao.findById(cmd.getPhysicalNetworkId());

+        if (pNetwork == null) {

+            throw new IllegalArgumentException("Could not find phyical network with ID: " + cmd.getPhysicalNetworkId());

+        }

+        zoneId = pNetwork.getDataCenterId();

+        

+        PhysicalNetworkServiceProviderVO ntwkSvcProvider = _physicalNetworkServiceProviderDao.findByServiceProvider(pNetwork.getId(), BaremetalPxeManager.BAREMETAL_PXE_SERVICE_PROVIDER.getName());

+        if (ntwkSvcProvider == null) {

+            throw new CloudRuntimeException("Network Service Provider: " + BaremetalPxeManager.BAREMETAL_PXE_SERVICE_PROVIDER.getName() +

+                    " is not enabled in the physical network: " + cmd.getPhysicalNetworkId() + "to add this device");

+        } else if (ntwkSvcProvider.getState() == PhysicalNetworkServiceProvider.State.Shutdown) {

+            throw new CloudRuntimeException("Network Service Provider: " + ntwkSvcProvider.getProviderName() +

+                    " is in shutdown state in the physical network: " + cmd.getPhysicalNetworkId() + "to add this device");

+        }

+        

+        List<HostVO> pxes = _resourceMgr.listAllHostsInOneZoneByType(Host.Type.BaremetalPxe, zoneId);

+        if (!pxes.isEmpty()) {

+            throw new IllegalArgumentException("Already had a PXE server zone: " + zoneId);
+        }

+        

+        String tftpDir = kcmd.getTftpDir();

+        if (tftpDir == null) {

+            throw new IllegalArgumentException("No TFTP directory specified");

+        }

+        

+        URI uri;

+        try {

+            uri = new URI(cmd.getUrl());

+        } catch (Exception e) {

+            s_logger.debug(e);

+            throw new IllegalArgumentException(e.getMessage());

+        }

+        String ipAddress = uri.getHost();

+        

+        String guid = getPxeServerGuid(Long.toString(zoneId), BaremetalPxeType.KICK_START.toString(), ipAddress);

+        

+        ServerResource resource = null;

+        Map params = new HashMap<String, String>();

+        params.put(BaremetalPxeService.PXE_PARAM_ZONE, Long.toString(zoneId));

+        params.put(BaremetalPxeService.PXE_PARAM_IP, ipAddress);

+        params.put(BaremetalPxeService.PXE_PARAM_USERNAME, cmd.getUsername());

+        params.put(BaremetalPxeService.PXE_PARAM_PASSWORD, cmd.getPassword());

+        params.put(BaremetalPxeService.PXE_PARAM_TFTP_DIR, tftpDir);

+        params.put(BaremetalPxeService.PXE_PARAM_GUID, guid);
+        resource = new BaremetalKickStartPxeResource();
+        try {
+            resource.configure("KickStart PXE resource", params);

+        } catch (Exception e) {

+            throw new CloudRuntimeException(e.getMessage(), e);

+        }
+        

+        Host pxeServer = _resourceMgr.addHost(zoneId, resource, Host.Type.BaremetalPxe, params);

+        if (pxeServer == null) {

+            throw new CloudRuntimeException("Cannot add PXE server as a host");

+        }
+        

+        BaremetalPxeVO vo = new BaremetalPxeVO();

+        Transaction txn = Transaction.currentTxn();

+        vo.setHostId(pxeServer.getId());

+        vo.setNetworkServiceProviderId(ntwkSvcProvider.getId());

+        vo.setPhysicalNetworkId(kcmd.getPhysicalNetworkId());

+        vo.setDeviceType(BaremetalPxeType.KICK_START.toString());

+        txn.start();

+        _pxeDao.persist(vo);

+        txn.commit();

+        return vo;

+    }

+

+    @Override

+    public BaremetalPxeResponse getApiResponse(BaremetalPxeVO vo) {

+        BaremetalPxeKickStartResponse response = new BaremetalPxeKickStartResponse();

+        response.setId(String.valueOf(vo.getId()));

+        response.setPhysicalNetworkId(String.valueOf(vo.getPhysicalNetworkId()));

+        response.setPodId(String.valueOf(vo.getPodId()));

+        Map<String, String> details = _hostDetailsDao.findDetails(vo.getHostId());

+        response.setTftpDir(details.get(BaremetalPxeService.PXE_PARAM_TFTP_DIR));

+        return response;

+    }

+

+    @Override

+    public List<BaremetalPxeResponse> listPxeServers(ListBaremetalPxePingServersCmd cmd) {

+        SearchCriteriaService<BaremetalPxeVO, BaremetalPxeVO> sc = SearchCriteria2.create(BaremetalPxeVO.class);

+        sc.addAnd(sc.getEntity().getDeviceType(), Op.EQ, BaremetalPxeType.KICK_START.toString());

+        if (cmd.getPodId() != null) {

+            sc.addAnd(sc.getEntity().getPodId(), Op.EQ, cmd.getPodId());

+            if (cmd.getId() != null) {

+                sc.addAnd(sc.getEntity().getId(), Op.EQ, cmd.getId());

+            }

+        }

+        List<BaremetalPxeVO> vos = sc.list();

+        List<BaremetalPxeResponse> responses = new ArrayList<BaremetalPxeResponse>(vos.size());

+        for (BaremetalPxeVO vo : vos) {

+            responses.add(getApiResponse(vo));

+        }

+        return responses;

+    }

+

+}

diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java
new file mode 100755
index 0000000..2fb5415
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPingPxeResource.java
@@ -0,0 +1,260 @@
+// 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.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.PingCommand;
+import com.cloud.agent.api.PingRoutingCommand;
+import com.cloud.agent.api.baremetal.PreparePxeServerAnswer;
+import com.cloud.agent.api.baremetal.PreparePxeServerCommand;
+import com.cloud.agent.api.baremetal.prepareCreateTemplateCommand;
+import com.cloud.agent.api.routing.VmDataCommand;
+import com.cloud.utils.script.Script;
+import com.cloud.utils.ssh.SSHCmdHelper;
+import com.cloud.vm.VirtualMachine.State;
+import com.trilead.ssh2.SCPClient;
+
+public class BaremetalPingPxeResource extends BaremetalPxeResourceBase {
+	private static final Logger s_logger = Logger.getLogger(BaremetalPingPxeResource.class);
+	private static final String _name = "BaremetalPingPxeResource";
+	String _storageServer;
+	String _pingDir;
+	String _share;
+	String _dir;
+	String _tftpDir;
+	String _cifsUserName;
+	String _cifsPassword;
+	
+	@Override
+	public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+		super.configure(name, params);
+		_storageServer = (String)params.get(BaremetalPxeService.PXE_PARAM_PING_STORAGE_SERVER_IP);
+		_pingDir = (String)params.get(BaremetalPxeService.PXE_PARAM_PING_ROOT_DIR);
+		_tftpDir = (String)params.get(BaremetalPxeService.PXE_PARAM_TFTP_DIR);
+		_cifsUserName = (String)params.get(BaremetalPxeService.PXE_PARAM_PING_STORAGE_SERVER_USERNAME);
+		_cifsPassword = (String)params.get(BaremetalPxeService.PXE_PARAM_PING_STORAGE_SERVER_PASSWORD);
+		
+		if (_podId == null) {
+		    throw new ConfigurationException("No Pod specified");
+		}
+		
+		if (_storageServer == null) {
+			throw new ConfigurationException("No stroage server specified");
+		}
+		
+		if (_tftpDir == null) {
+			throw new ConfigurationException("No tftp directory specified");
+		}
+		
+		if (_pingDir == null) {
+			throw new ConfigurationException("No PING directory specified");
+		}
+		
+		if (_cifsUserName == null || _cifsUserName.equalsIgnoreCase("")) {
+			_cifsUserName = "xxx";
+		}
+		
+		if (_cifsPassword == null || _cifsPassword.equalsIgnoreCase("")) {
+			_cifsPassword = "xxx";
+		}
+		
+		String pingDirs[]= _pingDir.split("/");
+		if (pingDirs.length != 2) {
+			throw new ConfigurationException("PING dir should have format like myshare/direcotry, eg: windows/64bit");
+		}
+		_share = pingDirs[0];
+		_dir = pingDirs[1];
+		
+		com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22);
+		
+		s_logger.debug(String.format("Trying to connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username, "******"));
+		try {
+			sshConnection.connect(null, 60000, 60000);
+			if (!sshConnection.authenticateWithPassword(_username, _password)) {
+				s_logger.debug("SSH Failed to authenticate");
+				throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username,
+						"******"));
+			}
+			
+			String cmd = String.format("[ -f /%1$s/pxelinux.0 ] && [ -f /%2$s/kernel ] && [ -f /%3$s/initrd.gz ] ", _tftpDir, _tftpDir, _tftpDir);
+			if (!SSHCmdHelper.sshExecuteCmd(sshConnection, cmd)) {
+				throw new ConfigurationException("Miss files in TFTP directory at " + _tftpDir + " check if pxelinux.0, kernel initrd.gz are here");
+			}
+			
+			SCPClient scp = new SCPClient(sshConnection);	
+			String prepareScript = "scripts/network/ping/prepare_tftp_bootfile.py";
+			String prepareScriptPath = Script.findScript("", prepareScript);
+			if (prepareScriptPath == null) {
+				throw new ConfigurationException("Can not find prepare_tftp_bootfile.py at " + prepareScriptPath);
+			}
+			scp.put(prepareScriptPath, "/usr/bin/", "0755");
+			
+			String userDataScript = "scripts/network/ping/baremetal_user_data.py";
+			String userDataScriptPath = Script.findScript("", userDataScript);
+			if (userDataScriptPath == null) {
+				throw new ConfigurationException("Can not find baremetal_user_data.py at " + userDataScriptPath);
+			}
+			scp.put(userDataScriptPath, "/usr/bin/", "0755");
+			
+			return true;
+		} catch (Exception e) {
+			throw new ConfigurationException(e.getMessage());
+		} finally {
+			if (sshConnection != null) {
+				sshConnection.close();
+			}
+		}
+	}
+	
+	@Override
+	public PingCommand getCurrentStatus(long id) {
+		com.trilead.ssh2.Connection sshConnection = SSHCmdHelper.acquireAuthorizedConnection(_ip, _username, _password);
+		if (sshConnection == null) {
+			return null;
+		} else {
+			SSHCmdHelper.releaseSshConnection(sshConnection);
+			return new PingRoutingCommand(getType(), id, new HashMap<String, State>());
+		}
+	}
+	
+	protected PreparePxeServerAnswer execute(PreparePxeServerCommand cmd) {
+		com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22);
+		try {
+			sshConnection.connect(null, 60000, 60000);
+			if (!sshConnection.authenticateWithPassword(_username, _password)) {
+				s_logger.debug("SSH Failed to authenticate");
+				throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username,
+						_password));
+			}
+			
+			String script = String.format("python /usr/bin/prepare_tftp_bootfile.py restore %1$s %2$s %3$s %4$s %5$s %6$s %7$s %8$s %9$s %10$s %11$s",
+					_tftpDir, cmd.getMac(), _storageServer, _share, _dir, cmd.getTemplate(), _cifsUserName, _cifsPassword, cmd.getIp(), cmd.getNetMask(), cmd.getGateWay());
+			if (!SSHCmdHelper.sshExecuteCmd(sshConnection, script)) {
+				return new PreparePxeServerAnswer(cmd, "prepare PING at " + _ip + " failed, command:" + script);
+			}	
+			s_logger.debug("Prepare Ping PXE server successfully");
+			
+			return new PreparePxeServerAnswer(cmd);
+		} catch (Exception e){
+			s_logger.debug("Prepare PING pxe server failed", e);
+			return new PreparePxeServerAnswer(cmd, e.getMessage());
+		} finally {
+			if (sshConnection != null) {
+				sshConnection.close();
+			}
+		}
+	}
+	
+	protected Answer execute(prepareCreateTemplateCommand cmd) {
+       com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22);
+        try {
+            sshConnection.connect(null, 60000, 60000);
+            if (!sshConnection.authenticateWithPassword(_username, _password)) {
+                s_logger.debug("SSH Failed to authenticate");
+                throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username,
+                        _password));
+            }
+            
+            String script = String.format("python /usr/bin/prepare_tftp_bootfile.py backup %1$s %2$s %3$s %4$s %5$s %6$s %7$s %8$s %9$s %10$s %11$s",
+                    _tftpDir, cmd.getMac(), _storageServer, _share, _dir, cmd.getTemplate(), _cifsUserName, _cifsPassword, cmd.getIp(), cmd.getNetMask(), cmd.getGateWay());
+            if (!SSHCmdHelper.sshExecuteCmd(sshConnection, script)) {
+                return new Answer(cmd, false, "prepare for creating template failed, command:" + script);
+            }
+            s_logger.debug("Prepare for creating template successfully");
+            
+            return new Answer(cmd, true, "Success");
+        }  catch (Exception e){
+            s_logger.debug("Prepare for creating baremetal template failed", e);
+            return new Answer(cmd, false, e.getMessage());
+        } finally {
+            if (sshConnection != null) {
+                sshConnection.close();
+            }
+        }
+	}
+	
+	@Override
+	public Answer executeRequest(Command cmd) {
+		if (cmd instanceof PreparePxeServerCommand) {
+			return execute((PreparePxeServerCommand) cmd);
+		} else if (cmd instanceof prepareCreateTemplateCommand) {
+		    return execute((prepareCreateTemplateCommand)cmd);
+		} else if (cmd instanceof VmDataCommand) {
+		    return execute((VmDataCommand)cmd);
+		} else {
+			return super.executeRequest(cmd);
+		}
+	}
+
+    private Answer execute(VmDataCommand cmd) {
+        com.trilead.ssh2.Connection sshConnection = new com.trilead.ssh2.Connection(_ip, 22);
+        try {
+            List<String[]> vmData = cmd.getVmData();
+            StringBuilder sb = new StringBuilder();
+            for (String[] data : vmData) {
+                String folder = data[0];
+                String file = data[1];
+                String contents = (data[2] == null) ? "none" : data[2];
+                sb.append(cmd.getVmIpAddress());
+                sb.append(",");
+                sb.append(folder);
+                sb.append(",");
+                sb.append(file);
+                sb.append(",");
+                sb.append(contents);
+                sb.append(";");
+            }
+            String arg = org.apache.commons.lang.StringUtils.stripEnd(sb.toString(), ";");
+            
+            sshConnection.connect(null, 60000, 60000);
+            if (!sshConnection.authenticateWithPassword(_username, _password)) {
+                s_logger.debug("SSH Failed to authenticate");
+                throw new ConfigurationException(String.format("Cannot connect to PING PXE server(IP=%1$s, username=%2$s, password=%3$s", _ip, _username,
+                        _password));
+            }
+            
+            String script = String.format("python /usr/bin/baremetal_user_data.py '%s'", arg);
+            if (!SSHCmdHelper.sshExecuteCmd(sshConnection, script)) {
+                return new Answer(cmd, false, "Failed to add user data, command:" + script);
+            }
+            
+            return new Answer(cmd, true, "Success");
+        }  catch (Exception e){
+            s_logger.debug("Prepare for creating baremetal template failed", e);
+            return new Answer(cmd, false, e.getMessage());
+        } finally {
+            if (sshConnection != null) {
+                sshConnection.close();
+            }
+        }
+    }
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeElement.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeElement.java
new file mode 100755
index 0000000..99b9c43
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeElement.java
@@ -0,0 +1,178 @@
+// 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
+package com.cloud.baremetal.networkservice;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ejb.Local;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.baremetal.database.BaremetalPxeVO;
+import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.dc.Pod;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.network.Network;
+import com.cloud.network.Network.Capability;
+import com.cloud.network.Network.GuestType;
+import com.cloud.network.Network.Provider;
+import com.cloud.network.Network.Service;
+import com.cloud.network.Networks.TrafficType;
+import com.cloud.network.PhysicalNetworkServiceProvider;
+import com.cloud.network.element.NetworkElement;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.utils.component.AdapterBase;
+import com.cloud.utils.component.Inject;
+import com.cloud.utils.db.DB;
+import com.cloud.utils.db.SearchCriteria.Op;
+import com.cloud.utils.db.SearchCriteria2;
+import com.cloud.utils.db.SearchCriteriaService;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.NicVO;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachine.Type;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.dao.NicDao;
+import com.cloud.vm.dao.VMInstanceDao;
+
+@Local(value = NetworkElement.class)
+public class BaremetalPxeElement extends AdapterBase implements NetworkElement {
+    private static final Logger s_logger = Logger.getLogger(BaremetalPxeElement.class);
+    private static final Map<Service, Map<Capability, String>> capabilities;
+    
+    @Inject BaremetalPxeManager _pxeMgr;;
+    @Inject VMInstanceDao _vmDao;
+    @Inject NicDao _nicDao;
+    
+    static {
+        Capability cap = new Capability(BaremetalPxeManager.BAREMETAL_PXE_CAPABILITY);
+        Map<Capability, String> baremetalCaps = new HashMap<Capability, String>();
+        baremetalCaps.put(cap, null);
+        capabilities = new HashMap<Service, Map<Capability, String>>();
+        capabilities.put(BaremetalPxeManager.BAREMETAL_PXE_SERVICE, baremetalCaps);
+    }
+    
+    @Override
+    public Map<Service, Map<Capability, String>> getCapabilities() {
+        return capabilities;
+    }
+
+    @Override
+    public Provider getProvider() {
+    	return BaremetalPxeManager.BAREMETAL_PXE_SERVICE_PROVIDER;
+    }
+
+    private boolean canHandle(DeployDestination dest, TrafficType trafficType, GuestType networkType) {
+        Pod pod = dest.getPod();
+        if (pod != null && dest.getDataCenter().getNetworkType() == NetworkType.Basic && trafficType == TrafficType.Guest) {
+            SearchCriteriaService<BaremetalPxeVO, BaremetalPxeVO> sc = SearchCriteria2.create(BaremetalPxeVO.class);
+            sc.addAnd(sc.getEntity().getPodId(), Op.EQ, pod.getId());
+            return sc.find() != null;
+        }
+        
+        return false;
+    }
+    
+    @Override
+    public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context)
+            throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
+        if (offering.isSystemOnly() || !canHandle(dest, offering.getTrafficType(), network.getGuestType())) {
+            s_logger.debug("BaremetalPxeElement can not handle network offering: " + offering.getName());
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    @DB
+    public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest,
+            ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {
+        if (vm.getType() != Type.User || vm.getHypervisorType() != HypervisorType.BareMetal) {
+            return false;
+        }
+        
+        VMInstanceVO vo = _vmDao.findById(vm.getId());
+        if (vo.getLastHostId() == null) {
+            Transaction txn = Transaction.currentTxn();
+            txn.start();
+            nic.setMacAddress(dest.getHost().getPrivateMacAddress());
+            NicVO nicVo = _nicDao.findById(nic.getId());
+            assert vo != null : "Where ths nic " + nic.getId() + " going???";
+            nicVo.setMacAddress(nic.getMacAddress());
+            _nicDao.update(nicVo.getId(), nicVo);
+            txn.commit();
+            
+        	/*This vm is just being created */
+        	if (!_pxeMgr.prepare(vm, nic, dest, context)) {
+        	    throw new CloudRuntimeException("Cannot prepare pxe server");
+        	}
+        }
+        
+        return false;
+    }
+
+    @Override
+    public boolean release(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, ReservationContext context)
+            throws ConcurrentOperationException, ResourceUnavailableException {
+        return true;
+    }
+
+    @Override
+    public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException {
+        return true;
+    }
+
+    @Override
+    public boolean isReady(PhysicalNetworkServiceProvider provider) {
+        return true;
+    }
+
+    @Override
+    public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException,
+            ResourceUnavailableException {
+        return true;
+    }
+
+    @Override
+    public boolean canEnableIndividualServices() {
+        return false;
+    }
+
+    @Override
+    public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean verifyServicesCombination(Set<Service> services) {
+        // TODO Auto-generated method stub
+        return false;
+    }
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeKickStartResponse.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeKickStartResponse.java
new file mode 100755
index 0000000..09c6cc6
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeKickStartResponse.java
@@ -0,0 +1,37 @@
+// 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
+package com.cloud.baremetal.networkservice;

+

+import org.apache.cloudstack.api.ApiConstants;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+

+public class BaremetalPxeKickStartResponse extends BaremetalPxeResponse {

+    @SerializedName(ApiConstants.TFTP_DIR) @Param(description="Tftp root directory of PXE server")

+    private String tftpDir;

+

+    public String getTftpDir() {

+        return tftpDir;

+    }

+

+    public void setTftpDir(String tftpDir) {

+        this.tftpDir = tftpDir;

+    }

+}

diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManager.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManager.java
new file mode 100755
index 0000000..e0a5162
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManager.java
@@ -0,0 +1,65 @@
+// 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.util.List;
+
+import com.cloud.baremetal.database.BaremetalPxeVO;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.host.HostVO;
+import com.cloud.network.Network;
+import com.cloud.network.Network.Provider;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.component.Manager;
+import com.cloud.utils.component.PluggableService;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VirtualMachineProfile;
+
+public interface BaremetalPxeManager extends Manager, PluggableService {
+    public enum BaremetalPxeType {
+        PING,
+        KICK_START,
+    }
+    
+	boolean prepare(VirtualMachineProfile profile, NicProfile nic, DeployDestination dest, ReservationContext context);
+
+	boolean prepareCreateTemplate(Long pxeServerId, UserVm vm, String templateUrl);
+	
+	BaremetalPxeType getPxeServerType(HostVO host);
+	
+	BaremetalPxeVO addPxeServer(AddBaremetalPxeCmd cmd);
+	
+	BaremetalPxeResponse getApiResponse(BaremetalPxeVO vo);
+	
+	List<BaremetalPxeResponse> listPxeServers(ListBaremetalPxePingServersCmd cmd);
+	
+	boolean addUserData(NicProfile nic, VirtualMachineProfile<UserVm> vm);
+		
+	public static final Network.Service BAREMETAL_PXE_SERVICE = new Network.Service("BaremetalPxeService");
+	public static final String BAREMETAL_PXE_CAPABILITY = "BaremetalPxe";
+	public static final String BAREMETAL_PXE_SERVICE_PROPERTIES = "baremetalpxe_commands.properties";
+	public static final Provider BAREMETAL_PXE_SERVICE_PROVIDER = new Provider("BaremetalPxeProvider", true);;
+	public static final Provider BAREMETAL_USERDATA_PROVIDER = new Provider("BaremetaUserdataProvider", true);
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManagerImpl.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManagerImpl.java
new file mode 100755
index 0000000..94010ec
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeManagerImpl.java
@@ -0,0 +1,242 @@
+// 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.util.List;
+import java.util.Map;
+
+import javax.ejb.Local;
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.AgentManager;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.agent.api.StartupPxeServerCommand;
+import com.cloud.agent.api.routing.VmDataCommand;
+import com.cloud.baremetal.database.BaremetalPxeVO;
+import com.cloud.configuration.dao.ConfigurationDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.network.PhysicalNetworkVO;
+import com.cloud.network.dao.PhysicalNetworkDao;
+import com.cloud.resource.ResourceManager;
+import com.cloud.resource.ResourceStateAdapter;
+import com.cloud.resource.ServerResource;
+import com.cloud.resource.UnableDeleteHostException;
+import com.cloud.service.dao.ServiceOfferingDao;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.StringUtils;
+import com.cloud.utils.component.Adapters;
+import com.cloud.utils.component.Inject;
+import com.cloud.utils.db.SearchCriteria.Op;
+import com.cloud.utils.db.SearchCriteria2;
+import com.cloud.utils.db.SearchCriteriaService;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.NicVO;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.dao.NicDao;
+import com.cloud.vm.dao.UserVmDao;
+
+@Local(value = {BaremetalPxeManager.class})
+public class BaremetalPxeManagerImpl implements BaremetalPxeManager, ResourceStateAdapter {
+	private static final org.apache.log4j.Logger s_logger = Logger.getLogger(BaremetalPxeManagerImpl.class);
+	protected String _name;
+	@Inject DataCenterDao _dcDao;
+	@Inject HostDao _hostDao;
+	@Inject AgentManager _agentMgr;
+	@Inject ResourceManager _resourceMgr;
+	@Inject(adapter=BaremetalPxeService.class)
+	protected Adapters<BaremetalPxeService> _services;
+	@Inject UserVmDao _vmDao;
+	@Inject ServiceOfferingDao _serviceOfferingDao;
+	@Inject NicDao _nicDao;
+	@Inject ConfigurationDao _configDao;
+	@Inject PhysicalNetworkDao _phynwDao;
+	
+	@Override
+	public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+		_name = name;
+		_resourceMgr.registerResourceStateAdapter(this.getClass().getSimpleName(), this);
+		return true;
+	}
+
+	@Override
+	public boolean start() {
+		return true;
+	}
+
+	@Override
+	public boolean stop() {
+    	_resourceMgr.unregisterResourceStateAdapter(this.getClass().getSimpleName());
+		return true;
+	}
+
+	@Override
+	public String getName() {
+		return _name;
+	}
+
+	protected BaremetalPxeService getServiceByType(String type) {
+		BaremetalPxeService _service;
+		_service = _services.get(type);
+		if (_service == null) {
+			throw new CloudRuntimeException("Cannot find PXE service for " + type);
+		}
+		return _service;
+	}
+	
+	@Override
+	public boolean prepare(VirtualMachineProfile profile, NicProfile nic, DeployDestination dest, ReservationContext context) {
+	    //TODO: select type from template
+	    BaremetalPxeType type = BaremetalPxeType.KICK_START;
+		return getServiceByType(type.toString()).prepare(profile, nic, dest, context);
+	}
+
+    @Override
+    public boolean prepareCreateTemplate(Long pxeServerId, UserVm vm, String templateUrl) {
+	    //TODO: select type from template
+	    BaremetalPxeType type = BaremetalPxeType.PING;
+        return getServiceByType(type.toString()).prepareCreateTemplate(pxeServerId, vm, templateUrl);
+    }
+    
+    @Override
+    public BaremetalPxeType getPxeServerType(HostVO host) {
+        if (host.getResource().equalsIgnoreCase(BaremetalPingPxeResource.class.getName())) {
+            return BaremetalPxeType.PING;
+        } else {
+            throw new CloudRuntimeException("Unkown PXE server resource " + host.getResource());
+        }
+    }
+
+	@Override
+    public HostVO createHostVOForConnectedAgent(HostVO host, StartupCommand[] cmd) {
+	    // TODO Auto-generated method stub
+	    return null;
+    }
+
+	@Override
+    public HostVO createHostVOForDirectConnectAgent(HostVO host, StartupCommand[] startup, ServerResource resource, Map<String, String> details,
+            List<String> hostTags) {
+        if (!(startup[0] instanceof StartupPxeServerCommand)) {
+            return null;
+        }
+        
+        host.setType(Host.Type.BaremetalPxe);
+        return host;
+    }
+
+	@Override
+    public DeleteHostAnswer deleteHost(HostVO host, boolean isForced, boolean isForceDeleteStorage) throws UnableDeleteHostException {
+	    // TODO Auto-generated method stub
+	    return null;
+    }
+
+    @Override
+    public BaremetalPxeVO addPxeServer(AddBaremetalPxeCmd cmd) {
+        return getServiceByType(cmd.getDeviceType()).addPxeServer(cmd);
+    }
+
+    @Override
+    public BaremetalPxeResponse getApiResponse(BaremetalPxeVO vo) {
+        return getServiceByType(vo.getDeviceType()).getApiResponse(vo);
+    }
+
+    @Override
+    public List<BaremetalPxeResponse> listPxeServers(ListBaremetalPxePingServersCmd cmd) {
+        return getServiceByType(BaremetalPxeManager.BaremetalPxeType.PING.toString()).listPxeServers(cmd);
+    }
+
+    @Override
+    public boolean addUserData(NicProfile nic, VirtualMachineProfile<UserVm> profile) {
+        UserVmVO vm = (UserVmVO) profile.getVirtualMachine();
+        _vmDao.loadDetails(vm);
+        
+        String serviceOffering = _serviceOfferingDao.findByIdIncludingRemoved(vm.getServiceOfferingId()).getDisplayText();
+        String zoneName = _dcDao.findById(vm.getDataCenterIdToDeployIn()).getName();
+        NicVO nvo = _nicDao.findById(nic.getId());
+        VmDataCommand cmd = new VmDataCommand(nvo.getIp4Address(), vm.getInstanceName());
+        cmd.addVmData("userdata", "user-data", vm.getUserData());
+        cmd.addVmData("metadata", "service-offering", StringUtils.unicodeEscape(serviceOffering));
+        cmd.addVmData("metadata", "availability-zone", StringUtils.unicodeEscape(zoneName));
+        cmd.addVmData("metadata", "local-ipv4", nic.getIp4Address());
+        cmd.addVmData("metadata", "local-hostname", StringUtils.unicodeEscape(vm.getInstanceName()));
+        cmd.addVmData("metadata", "public-ipv4", nic.getIp4Address());
+        cmd.addVmData("metadata", "public-hostname",  StringUtils.unicodeEscape(vm.getInstanceName()));
+        cmd.addVmData("metadata", "instance-id", String.valueOf(vm.getId()));
+        cmd.addVmData("metadata", "vm-id", String.valueOf(vm.getInstanceName()));
+        cmd.addVmData("metadata", "public-keys", null);
+        String cloudIdentifier = _configDao.getValue("cloud.identifier");
+        if (cloudIdentifier == null) {
+            cloudIdentifier = "";
+        } else {
+            cloudIdentifier = "CloudStack-{" + cloudIdentifier + "}";
+        }
+        cmd.addVmData("metadata", "cloud-identifier", cloudIdentifier);
+        
+        List<PhysicalNetworkVO> phys = _phynwDao.listByZone(vm.getDataCenterIdToDeployIn());
+        if (phys.isEmpty()) {
+            throw new CloudRuntimeException(String.format("Cannot find physical network in zone %s", vm.getDataCenterIdToDeployIn()));
+        }
+        if (phys.size() > 1) {
+            throw new CloudRuntimeException(String.format("Baremetal only supports one physical network in zone, but zone %s has %s physical networks", vm.getDataCenterIdToDeployIn(), phys.size()));
+        }
+        PhysicalNetworkVO phy = phys.get(0);
+        
+        SearchCriteriaService<BaremetalPxeVO, BaremetalPxeVO> sc = SearchCriteria2.create(BaremetalPxeVO.class);
+        //TODO: handle both kickstart and PING
+        //sc.addAnd(sc.getEntity().getPodId(), Op.EQ, vm.getPodIdToDeployIn());
+        sc.addAnd(sc.getEntity().getPhysicalNetworkId(), Op.EQ, phy.getId());
+        BaremetalPxeVO pxeVo = sc.find();
+        if (pxeVo == null) {
+            throw new CloudRuntimeException("No PXE server found in pod: " + vm.getPodIdToDeployIn() + ", you need to add it before starting VM");
+        }
+        
+        try {
+            Answer ans = _agentMgr.send(pxeVo.getHostId(), cmd);
+            if (!ans.getResult()) {
+                s_logger.debug(String.format("Add userdata to vm:%s failed because %s", vm.getInstanceName(), ans.getDetails()));
+                return false;
+            } else {
+                return true;
+            }
+        } catch (Exception e) {
+            s_logger.debug(String.format("Add userdata to vm:%s failed", vm.getInstanceName()), e);
+            return false;
+        }
+    }
+
+	@Override
+	public List<Class<?>> getCommands() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxePingResponse.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxePingResponse.java
new file mode 100755
index 0000000..adbf053
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxePingResponse.java
@@ -0,0 +1,59 @@
+// 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
+package com.cloud.baremetal.networkservice;
+
+import org.apache.cloudstack.api.ApiConstants;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+
+public class BaremetalPxePingResponse extends BaremetalPxeResponse {
+    @SerializedName(ApiConstants.PING_STORAGE_SERVER_IP) @Param(description="PING storage server ip")
+    private String pingStorageServerIp;
+    
+    @SerializedName(ApiConstants.PING_DIR) @Param(description="Root directory on PING storage server")
+    private String pingDir;
+    
+    @SerializedName(ApiConstants.TFTP_DIR) @Param(description="Tftp root directory of PXE server")
+    private String tftpDir;
+
+    public String getPingStorageServerIp() {
+        return pingStorageServerIp;
+    }
+
+    public void setPingStorageServerIp(String pingStorageServerIp) {
+        this.pingStorageServerIp = pingStorageServerIp;
+    }
+
+    public String getPingDir() {
+        return pingDir;
+    }
+
+    public void setPingDir(String pingDir) {
+        this.pingDir = pingDir;
+    }
+
+    public String getTftpDir() {
+        return tftpDir;
+    }
+
+    public void setTftpDir(String tftpDir) {
+        this.tftpDir = tftpDir;
+    }
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeResourceBase.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeResourceBase.java
new file mode 100755
index 0000000..34175c8
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeResourceBase.java
@@ -0,0 +1,157 @@
+// 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.util.Map;
+
+import javax.naming.ConfigurationException;
+
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.IAgentControl;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.PingCommand;
+import com.cloud.agent.api.ReadyAnswer;
+import com.cloud.agent.api.ReadyCommand;
+import com.cloud.agent.api.StartupCommand;
+import com.cloud.agent.api.StartupPxeServerCommand;
+import com.cloud.host.Host.Type;
+import com.cloud.resource.ServerResource;
+
+public class BaremetalPxeResourceBase implements ServerResource {
+	private static final Logger s_logger = Logger.getLogger(BaremetalPxeResourceBase.class);
+	String _name;
+	String _guid;
+	String _username;
+	String _password;
+	String _ip;
+	String _zoneId;
+	String _podId;
+	
+	@Override
+	public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+		_name = name;
+		_guid = (String)params.get(BaremetalPxeService.PXE_PARAM_GUID);
+		_ip = (String)params.get(BaremetalPxeService.PXE_PARAM_IP);
+		_username = (String)params.get(BaremetalPxeService.PXE_PARAM_USERNAME);
+		_password = (String)params.get(BaremetalPxeService.PXE_PARAM_PASSWORD);
+		_zoneId = (String)params.get(BaremetalPxeService.PXE_PARAM_ZONE);
+		_podId = (String)params.get(BaremetalPxeService.PXE_PARAM_POD);
+
+		if (_guid == null) {
+			throw new ConfigurationException("No Guid specified");
+		}
+		
+		if (_zoneId == null) {
+			throw new ConfigurationException("No Zone specified");
+		}
+		
+		if (_ip == null) {
+			throw new ConfigurationException("No IP specified");
+		}
+		
+		if (_username == null) {
+			throw new ConfigurationException("No username specified");
+		}
+		
+		if (_password == null) {
+			throw new ConfigurationException("No password specified");
+		}
+		
+		return true;
+	}
+	
+	protected ReadyAnswer execute(ReadyCommand cmd) {
+		s_logger.debug("Pxe resource " + _name + " is ready");
+		return new ReadyAnswer(cmd);
+	}
+
+	@Override
+	public boolean start() {
+		return true;
+	}
+
+	@Override
+	public boolean stop() {
+		return true;
+	}
+
+	@Override
+	public String getName() {
+		// TODO Auto-generated method stub
+		return _name;
+	}
+
+	@Override
+	public Type getType() {
+		return Type.BaremetalPxe;
+	}
+
+	@Override
+	public StartupCommand[] initialize() {
+		StartupPxeServerCommand cmd = new StartupPxeServerCommand();
+		cmd.setName(_name);
+		cmd.setDataCenter(_zoneId);
+		cmd.setPod(_podId);
+		cmd.setPrivateIpAddress(_ip);
+		cmd.setStorageIpAddress("");
+		cmd.setVersion("");
+		cmd.setGuid(_guid);
+		return new StartupCommand[]{cmd};
+	}
+
+	@Override
+	public PingCommand getCurrentStatus(long id) {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public void disconnected() {
+		// TODO Auto-generated method stub
+
+	}
+
+	@Override
+	public IAgentControl getAgentControl() {
+		// TODO Auto-generated method stub
+		return null;
+	}
+
+	@Override
+	public void setAgentControl(IAgentControl agentControl) {
+		// TODO Auto-generated method stub
+
+	}
+	
+	@Override
+	public Answer executeRequest(Command cmd) {
+		if (cmd instanceof ReadyCommand) {
+			return execute((ReadyCommand) cmd);
+		} else {
+			return Answer.createUnsupportedCommandAnswer(cmd);
+		}
+	}
+
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeResponse.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeResponse.java
new file mode 100755
index 0000000..2103020
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeResponse.java
@@ -0,0 +1,71 @@
+// 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
+package com.cloud.baremetal.networkservice;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseResponse;
+
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+
+public class BaremetalPxeResponse extends BaseResponse {
+    @SerializedName(ApiConstants.ID) @Param(description="device id of ")
+    private String id;
+    
+    @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Param(description="the physical network to which this external dhcp device belongs to")
+    private String physicalNetworkId;
+    
+    @SerializedName(ApiConstants.PROVIDER) @Param(description="name of the provider")
+    private String providerId;
+    
+    @SerializedName(ApiConstants.POD_ID) @Param(description="pod id where the device is in")
+    private String podId;
+
+	public String getId() {
+		return id;
+	}
+
+	public void setId(String id) {
+		this.id = id;
+	}
+
+	public String getPhysicalNetworkId() {
+		return physicalNetworkId;
+	}
+
+	public void setPhysicalNetworkId(String physicalNetworkId) {
+		this.physicalNetworkId = physicalNetworkId;
+	}
+
+	public String getProviderId() {
+		return providerId;
+	}
+
+	public void setProviderId(String providerId) {
+		this.providerId = providerId;
+	}
+
+	public String getPodId() {
+		return podId;
+	}
+
+	public void setPodId(String podId) {
+		this.podId = podId;
+	}
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeService.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeService.java
new file mode 100644
index 0000000..8504f82
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalPxeService.java
@@ -0,0 +1,61 @@
+// 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.util.List;
+
+import com.cloud.baremetal.database.BaremetalPxeVO;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.host.Host;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.component.Adapter;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.UserVmVO;
+import com.cloud.vm.VirtualMachineProfile;
+
+public interface BaremetalPxeService extends Adapter {
+	
+	public boolean prepare(VirtualMachineProfile<UserVmVO> profile, NicProfile nic, DeployDestination dest, ReservationContext context);
+
+    public boolean prepareCreateTemplate(Long pxeServerId, UserVm vm, String templateUrl);
+    
+    BaremetalPxeVO addPxeServer(AddBaremetalPxeCmd cmd);
+	
+    BaremetalPxeResponse getApiResponse(BaremetalPxeVO vo);
+	
+	List<BaremetalPxeResponse> listPxeServers(ListBaremetalPxePingServersCmd cmd);
+	
+	public static final String PXE_PARAM_TYPE = "type";
+	public static final String PXE_PARAM_ZONE = "zone";
+	public static final String PXE_PARAM_POD = "pod";
+	public static final String PXE_PARAM_IP = "ip";
+	public static final String PXE_PARAM_GUID = "guid";
+	public static final String PXE_PARAM_TFTP_DIR = "tftpDir";
+	public static final String PXE_PARAM_USERNAME = "username";
+	public static final String PXE_PARAM_PASSWORD = "password";
+	public static final String PXE_PARAM_PING_STORAGE_SERVER_IP = "pingStorageServerIp";
+	public static final String PXE_PARAM_PING_ROOT_DIR = "pingDir";
+	public static final String PXE_PARAM_PING_STORAGE_SERVER_USERNAME = "pingStorageServerUserName";
+	public static final String PXE_PARAM_PING_STORAGE_SERVER_PASSWORD = "pingStorageServerPassword";	
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalUserdataElement.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalUserdataElement.java
new file mode 100755
index 0000000..d1f0e8b
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/BaremetalUserdataElement.java
@@ -0,0 +1,169 @@
+// 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
+package com.cloud.baremetal.networkservice;

+

+import java.util.HashMap;
+

+import java.util.List;

+import java.util.Map;

+import java.util.Set;

+

+import javax.ejb.Local;

+

+import com.cloud.baremetal.manager.BaremetalManager;

+import com.cloud.dc.DataCenter.NetworkType;

+import com.cloud.deploy.DeployDestination;

+import com.cloud.exception.ConcurrentOperationException;

+import com.cloud.exception.InsufficientCapacityException;

+import com.cloud.exception.ResourceUnavailableException;

+import com.cloud.hypervisor.Hypervisor.HypervisorType;

+import com.cloud.network.Network;

+import com.cloud.network.Network.Capability;

+import com.cloud.network.Network.GuestType;

+import com.cloud.network.Network.Provider;

+import com.cloud.network.Network.Service;

+import com.cloud.network.Networks.TrafficType;

+import com.cloud.network.PhysicalNetworkServiceProvider;

+import com.cloud.network.element.IpDeployer;

+import com.cloud.network.element.NetworkElement;

+import com.cloud.network.element.UserDataServiceProvider;

+import com.cloud.offering.NetworkOffering;

+import com.cloud.uservm.UserVm;

+import com.cloud.utils.component.AdapterBase;

+import com.cloud.utils.component.Inject;

+import com.cloud.vm.NicProfile;

+import com.cloud.vm.ReservationContext;

+import com.cloud.vm.VirtualMachine;

+import com.cloud.vm.VirtualMachineProfile;
+

+@Local(value = NetworkElement.class)

+public class BaremetalUserdataElement extends AdapterBase implements NetworkElement, UserDataServiceProvider {

+    private static Map<Service, Map<Capability, String>> capabilities;
+    
+    @Inject

+    private BaremetalPxeManager pxeMgr;
+    
+    static {

+        capabilities = new HashMap<Service, Map<Capability, String>>();
+        capabilities.put(Service.UserData, null);

+    }
+    
+    private boolean canHandle(DeployDestination dest)  {

+        if (dest.getDataCenter().getNetworkType() == NetworkType.Basic && dest.getHost().getHypervisorType() == HypervisorType.BareMetal) {

+            return true;

+        }
+        return false;

+    }
+    

+    @Override

+    public boolean addPasswordAndUserdata(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest,

+            ReservationContext context) throws ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException {
+        if (!canHandle(dest)) {

+            return false;

+        }
+        

+        if (vm.getType() != VirtualMachine.Type.User) {

+            return false;

+        }
+        

+        return pxeMgr.addUserData(nic, (VirtualMachineProfile<UserVm>) vm);

+    }

+

+    @Override

+    public boolean savePassword(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm) throws ResourceUnavailableException {

+        // TODO Auto-generated method stub

+        return false;

+    }

+

+    @Override

+    public Map<Service, Map<Capability, String>> getCapabilities() {

+        return capabilities;

+    }

+

+    @Override

+    public Provider getProvider() {

+        return BaremetalPxeManager.BAREMETAL_USERDATA_PROVIDER;

+    }

+

+    @Override

+    public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context)

+            throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {

+        // TODO Auto-generated method stub

+        return false;

+    }

+

+    @Override

+    public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, DeployDestination dest,

+            ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException {

+        // TODO Auto-generated method stub

+        return false;

+    }

+

+    @Override

+    public boolean release(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm, ReservationContext context)

+            throws ConcurrentOperationException, ResourceUnavailableException {

+        // TODO Auto-generated method stub

+        return false;

+    }

+

+    @Override

+    public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException {

+        // TODO Auto-generated method stub

+        return false;

+    }

+

+    @Override

+    public boolean isReady(PhysicalNetworkServiceProvider provider) {

+        return true;

+    }

+

+    @Override

+    public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException,

+            ResourceUnavailableException {

+        // TODO Auto-generated method stub

+        return false;

+    }

+

+    @Override

+    public boolean canEnableIndividualServices() {

+        // TODO Auto-generated method stub

+        return false;

+    }

+

+
+    @Override
+    public boolean saveUserData(Network network, NicProfile nic, VirtualMachineProfile<? extends VirtualMachine> vm)
+            throws ResourceUnavailableException {
+        // TODO Auto-generated method stub
+        return false;
+    }
+
+    @Override
+    public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException {
+        // TODO Auto-generated method stub
+        return false;

+    }

+

+    @Override

+    public boolean verifyServicesCombination(Set<Service> services) {

+        // TODO Auto-generated method stub

+        return false;

+    }

+

+}

diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalDhcpCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalDhcpCmd.java
new file mode 100755
index 0000000..ba5128b
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalDhcpCmd.java
@@ -0,0 +1,102 @@
+// 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
+package com.cloud.baremetal.networkservice;
+
+import java.util.List;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.BaseCmd.CommandType;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.PlugService;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.log4j.Logger;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+
+public class ListBaremetalDhcpCmd extends BaseListCmd {
+    private static final Logger s_logger = Logger.getLogger(ListBaremetalDhcpCmd.class);
+    private static final String s_name = "listexternaldhcpresponse";
+    @PlugService BaremetalDhcpManager _dhcpMgr;
+    
+    // ///////////////////////////////////////////////////
+    // ////////////// API parameters /////////////////////
+    // ///////////////////////////////////////////////////
+    @Parameter(name = ApiConstants.ID, type = CommandType.LONG, description = "DHCP server device ID")
+    private Long id;
+    
+    @Parameter(name = ApiConstants.POD_ID, type = CommandType.LONG, description = "Pod ID where pxe server is in")
+    private Long podId;
+    
+    @Parameter(name = ApiConstants.DHCP_SERVER_TYPE, type = CommandType.STRING, description = "Type of DHCP device")
+    private String deviceType;
+    
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getPodId() {
+        return podId;
+    }
+
+    public void setPodId(Long podId) {
+        this.podId = podId;
+    }
+    
+    public String getDeviceType() {
+        return deviceType;
+    }
+
+    public void setDeviceType(String deviceType) {
+        this.deviceType = deviceType;
+    }
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
+            ResourceAllocationException, NetworkRuleConflictException {
+    	try {
+            ListResponse<BaremetalDhcpResponse> response = new ListResponse<BaremetalDhcpResponse>();
+            List<BaremetalDhcpResponse> dhcpResponses = _dhcpMgr.listBaremetalDhcps(this);
+            response.setResponses(dhcpResponses);
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+    	} catch (Exception e) {
+    		s_logger.debug("Exception happend while executing ListBaremetalDhcpCmd");
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
+    	}
+
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalPxePingServersCmd.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalPxePingServersCmd.java
new file mode 100755
index 0000000..dceb8bf
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/ListBaremetalPxePingServersCmd.java
@@ -0,0 +1,92 @@
+// 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
+package com.cloud.baremetal.networkservice;
+
+import java.util.List;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.BaseCmd.CommandType;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.PlugService;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.log4j.Logger;
+
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.NetworkRuleConflictException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+
+public class ListBaremetalPxePingServersCmd extends BaseListCmd {
+    private static final Logger s_logger = Logger.getLogger(ListBaremetalPxePingServersCmd.class);
+    private static final String s_name = "listpingpxeserverresponse";
+
+    @PlugService
+    BaremetalPxeManager _pxeMgr;
+    // ///////////////////////////////////////////////////
+    // ////////////// API parameters /////////////////////
+    // ///////////////////////////////////////////////////
+
+    @Parameter(name = ApiConstants.ID, type = CommandType.LONG, description = "Ping pxe server device ID")
+    private Long id;
+    
+    @Parameter(name = ApiConstants.POD_ID, type = CommandType.LONG, description = "Pod ID where pxe server is in")
+    private Long podId;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Long getPodId() {
+        return podId;
+    }
+
+    public void setPodId(Long podId) {
+        this.podId = podId;
+    }
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
+            ResourceAllocationException, NetworkRuleConflictException {
+        try {
+            ListResponse<BaremetalPxeResponse> response = new ListResponse<BaremetalPxeResponse>();
+            List<BaremetalPxeResponse> pxeResponses = _pxeMgr.listPxeServers(this);
+            response.setResponses(pxeResponses);
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+        } catch (Exception e) {
+            s_logger.debug("Exception happend while executing ListPingPxeServersCmd" ,e);
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
+        }
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+}
diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/PrepareKickstartPxeServerCommand.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/PrepareKickstartPxeServerCommand.java
new file mode 100755
index 0000000..8951547
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/PrepareKickstartPxeServerCommand.java
@@ -0,0 +1,74 @@
+// 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
+package com.cloud.baremetal.networkservice;

+

+import com.cloud.agent.api.Command;

+

+public class PrepareKickstartPxeServerCommand extends Command {

+    private String ksFile;
+    private String repo;
+    private String templateUuid;

+    private String mac;

+    private String ksDevice;

+    

+    @Override

+    public boolean executeInSequence() {

+        return true;

+    }

+

+    public String getKsFile() {

+        return ksFile;

+    }

+

+    public void setKsFile(String ksFile) {

+        this.ksFile = ksFile;

+    }

+

+    public String getRepo() {

+        return repo;

+    }

+

+    public void setRepo(String repo) {

+        this.repo = repo;

+    }

+

+    public String getTemplateUuid() {

+        return templateUuid;

+    }

+

+    public void setTemplateUuid(String templateUuid) {

+        this.templateUuid = templateUuid;

+    }

+

+    public String getMac() {

+        return mac;

+    }

+

+    public void setMac(String mac) {

+        this.mac = mac;

+    }

+

+    public String getKsDevice() {

+        return ksDevice;

+    }

+

+    public void setKsDevice(String ksDevice) {

+        this.ksDevice = ksDevice;

+    }

+}

diff --git a/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java
new file mode 100755
index 0000000..203fed3
--- /dev/null
+++ b/plugins/hypervisors/baremetal/src/com/cloud/baremetal/networkservice/SecurityGroupHttpClient.java
@@ -0,0 +1,18 @@
+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;

+	}

+

+}

diff --git a/plugins/pom.xml b/plugins/pom.xml
index 7bb60a9..c5b6e58 100644
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -42,6 +42,7 @@
     <module>hypervisors/xen</module>
     <module>hypervisors/kvm</module>
     <module>hypervisors/simulator</module>
+    <module>hypervisors/baremetal</module>
     <module>network-elements/elastic-loadbalancer</module>
     <module>network-elements/ovs</module>
     <module>network-elements/nicira-nvp</module>
diff --git a/server/src/com/cloud/configuration/Config.java b/server/src/com/cloud/configuration/Config.java
index 4ae144e..5e4996b 100755
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -358,7 +358,13 @@
     DetailBatchQuerySize("Advanced", ManagementServer.class, Integer.class, "detail.batch.query.size", "2000", "Default entity detail batch query size for listing", null),
 
 	ConcurrentSnapshotsThresholdPerHost("Advanced", ManagementServer.class, Long.class, "concurrent.snapshots.threshold.perhost",
-	                null, "Limits number of snapshots that can be handled by the host concurrently; default is NULL - unlimited", null);
+	                null, "Limits number of snapshots that can be handled by the host concurrently; default is NULL - unlimited", null),

+	
+	ExternalBaremetalSystemUrl("Advanced", ManagementServer.class, String.class, "external.baremetal.system.url", null, "url of external baremetal system that CloudStack will talk to", null),
+	ExternalBaremetalResourceClassName("Advanced", ManagementServer.class, String.class, "external,baremetal.resource.classname", null, "class name for handling external baremetal resource", null),
+	EnableBaremetalSecurityGroupAgentEcho("Advanced", ManagementServer.class, Boolean.class, "enable.baremetal.securitygroup.agent.echo", "false", "After starting provision process, periodcially echo security agent installed in the template. Treat provisioning as success only if echo successfully", null),
+	IntervalToEchoBaremetalSecurityGroupAgent("Advanced", ManagementServer.class, Integer.class, "interval.baremetal.securitygroup.agent.echo", "10", "Interval to echo baremetal security group agent, in seconds", null),
+	TimeoutToEchoBaremetalSecurityGroupAgent("Advanced", ManagementServer.class, Integer.class, "timeout.baremetal.securitygroup.agent.echo", "3600", "Timeout to echo baremetal security group agent, in seconds, the provisioning process will be treated as a failure", null);
 
 	private final String _category;
 	private final Class<?> _componentClass;