You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ki...@apache.org on 2013/01/31 18:07:19 UTC

[14/43] git commit: refs/heads/regions - CloudStack CLOUDSTACK-774 Supporting kickstart in CloudStack baremetal

CloudStack CLOUDSTACK-774
Supporting kickstart in CloudStack baremetal

merge baremetal feature to master


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

Branch: refs/heads/regions
Commit: 1f7eaf3d61ed780da2df3cbf772c77407dea6f2c
Parents: 867cb4a
Author: frank <fr...@citrix.com>
Authored: Tue Jan 29 17:19:15 2013 -0800
Committer: frank <fr...@citrix.com>
Committed: Tue Jan 29 17:19:57 2013 -0800

----------------------------------------------------------------------
 api/src/com/cloud/event/EventTypes.java            |    6 +
 api/src/com/cloud/host/Host.java                   |    2 +
 .../org/apache/cloudstack/api/ApiConstants.java    |    1 +
 plugins/hypervisors/baremetal/pom.xml              |   37 +
 .../resources/security_group_agent/cs-sgagent      |   51 ++
 .../security_group_agent/__init__.py               |   18 +
 .../security_group_agent/cs_sg_agent.py            |  237 ++++++
 .../security_group_agent/sglib.py                  |  226 ++++++
 .../security_group_agent/xmlobject.py              |   97 +++
 .../resources/security_group_agent/setup.py        |   44 +
 .../cloud/baremetal/database/BaremetalCmdbDao.java |   25 +
 .../baremetal/database/BaremetalCmdbDaoImpl.java   |   29 +
 .../cloud/baremetal/database/BaremetalCmdbVO.java  |  104 +++
 .../cloud/baremetal/database/BaremetalDhcpDao.java |   25 +
 .../baremetal/database/BaremetalDhcpDaoImpl.java   |   42 +
 .../cloud/baremetal/database/BaremetalDhcpVO.java  |  118 +++
 .../cloud/baremetal/database/BaremetalPxeDao.java  |   26 +
 .../baremetal/database/BaremetalPxeDaoImpl.java    |   38 +
 .../cloud/baremetal/database/BaremetalPxeVO.java   |  115 +++
 .../baremetal/manager/AddBaremetalHostCmd.java     |   41 +
 .../baremetal/manager/BareMetalDiscoverer.java     |  280 +++++++
 .../com/cloud/baremetal/manager/BareMetalGuru.java |   87 ++
 .../manager/BareMetalTemplateAdapter.java          |  217 +++++
 .../cloud/baremetal/manager/BaremetalManager.java  |   28 +
 .../baremetal/manager/BaremetalManagerImpl.java    |  112 +++
 .../networkservice/AddBaremetalDhcpCmd.java        |  149 ++++
 .../AddBaremetalKickStartPxeCmd.java               |   36 +
 .../networkservice/AddBaremetalPxeCmd.java         |  144 ++++
 .../AddBaremetalPxePingServerCmd.java              |   80 ++
 .../networkservice/BareMetalPingServiceImpl.java   |  300 +++++++
 .../networkservice/BareMetalPxeServiceBase.java    |   68 ++
 .../networkservice/BareMetalResourceBase.java      |  618 +++++++++++++++
 .../networkservice/BaremetaNetworkGuru.java        |  173 ++++
 .../networkservice/BaremetalDhcpElement.java       |  178 +++++
 .../networkservice/BaremetalDhcpManager.java       |   58 ++
 .../networkservice/BaremetalDhcpManagerImpl.java   |  323 ++++++++
 .../networkservice/BaremetalDhcpResourceBase.java  |  174 ++++
 .../networkservice/BaremetalDhcpResponse.java      |   71 ++
 .../networkservice/BaremetalDhcpdResource.java     |  139 ++++
 .../networkservice/BaremetalDnsmasqResource.java   |  129 +++
 .../BaremetalKickStartPxeResource.java             |  201 +++++
 .../BaremetalKickStartServiceImpl.java             |  238 ++++++
 .../networkservice/BaremetalPingPxeResource.java   |  260 ++++++
 .../networkservice/BaremetalPxeElement.java        |  178 +++++
 .../BaremetalPxeKickStartResponse.java             |   37 +
 .../networkservice/BaremetalPxeManager.java        |   65 ++
 .../networkservice/BaremetalPxeManagerImpl.java    |  242 ++++++
 .../networkservice/BaremetalPxePingResponse.java   |   59 ++
 .../networkservice/BaremetalPxeResourceBase.java   |  157 ++++
 .../networkservice/BaremetalPxeResponse.java       |   71 ++
 .../networkservice/BaremetalPxeService.java        |   61 ++
 .../networkservice/BaremetalUserdataElement.java   |  169 ++++
 .../networkservice/ListBaremetalDhcpCmd.java       |  102 +++
 .../ListBaremetalPxePingServersCmd.java            |   92 +++
 .../PrepareKickstartPxeServerCommand.java          |   74 ++
 .../networkservice/SecurityGroupHttpClient.java    |   18 +
 plugins/pom.xml                                    |    1 +
 server/src/com/cloud/configuration/Config.java     |    8 +-
 58 files changed, 6678 insertions(+), 1 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/api/src/com/cloud/event/EventTypes.java
----------------------------------------------------------------------
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 class EventTypes {
     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";
 }

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/api/src/com/cloud/host/Host.java
----------------------------------------------------------------------
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 @@ public interface Host extends StateObject<Status>, Identity, InternalIdentity {
         ExternalLoadBalancer(false),
         ExternalVirtualSwitchSupervisor(false),
         PxeServer(false),
+        BaremetalPxe(false),
+        BaremetalDhcp(false),
         TrafficMonitor(false),
 
         ExternalDhcp(false),

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/api/src/org/apache/cloudstack/api/ApiConstants.java
----------------------------------------------------------------------
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 class ApiConstants {
     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;

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/pom.xml
----------------------------------------------------------------------
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>

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/resources/security_group_agent/cs-sgagent
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/__init__.py
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/cs_sg_agent.py
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/cs_sg_agent.py b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/cs_sg_agent.py
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

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/sglib.py
----------------------------------------------------------------------
diff --git a/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/sglib.py b/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/sglib.py
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().
+        """

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/resources/security_group_agent/security_group_agent/xmlobject.py
----------------------------------------------------------------------
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

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/resources/security_group_agent/setup.py
----------------------------------------------------------------------
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: -*-
+      """,
+      )

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDao.java
----------------------------------------------------------------------
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> {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbDaoImpl.java
----------------------------------------------------------------------
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 {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalCmdbVO.java
----------------------------------------------------------------------
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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalDhcpDao.java
----------------------------------------------------------------------
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> {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalDhcpDaoImpl.java
----------------------------------------------------------------------
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() {
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalDhcpVO.java
----------------------------------------------------------------------
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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalPxeDao.java
----------------------------------------------------------------------
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> {
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalPxeDaoImpl.java
----------------------------------------------------------------------
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 {
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/database/BaremetalPxeVO.java
----------------------------------------------------------------------
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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/AddBaremetalHostCmd.java
----------------------------------------------------------------------
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;
+    }
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalDiscoverer.java
----------------------------------------------------------------------
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);
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalGuru.java
----------------------------------------------------------------------
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;
+    }
+}
+
+	

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BareMetalTemplateAdapter.java
----------------------------------------------------------------------
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;
+	}
+}

http://git-wip-us.apache.org/repos/asf/incubator-cloudstack/blob/1f7eaf3d/plugins/hypervisors/baremetal/src/com/cloud/baremetal/manager/BaremetalManager.java
----------------------------------------------------------------------
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";
+}