You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ya...@apache.org on 2013/11/06 19:08:41 UTC

[2/5] Squashed commit of the Palo Alto Networks firewall integration plugin.

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/src/com/cloud/network/utils/HttpClientWrapper.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/src/com/cloud/network/utils/HttpClientWrapper.java b/plugins/network-elements/palo-alto/src/com/cloud/network/utils/HttpClientWrapper.java
new file mode 100644
index 0000000..7e40570
--- /dev/null
+++ b/plugins/network-elements/palo-alto/src/com/cloud/network/utils/HttpClientWrapper.java
@@ -0,0 +1,69 @@
+package com.cloud.network.utils;
+
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import org.apache.http.client.HttpClient;
+import org.apache.http.conn.ClientConnectionManager;
+import org.apache.http.conn.scheme.Scheme;
+import org.apache.http.conn.scheme.SchemeRegistry;
+import org.apache.http.conn.ssl.SSLSocketFactory;
+import org.apache.http.conn.ssl.X509HostnameVerifier;
+import org.apache.http.impl.client.DefaultHttpClient;
+
+import java.io.*;
+
+public class HttpClientWrapper {
+ 
+    public static HttpClient wrapClient(HttpClient base) {
+        try {
+            SSLContext ctx = SSLContext.getInstance("TLS");
+            X509TrustManager tm = new X509TrustManager() {
+ 
+                public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
+                }
+ 
+                public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
+                }
+ 
+                public X509Certificate[] getAcceptedIssuers() {
+                    return null;
+                }
+            };
+            X509HostnameVerifier verifier = new X509HostnameVerifier() {
+ 
+                @Override
+                public void verify(String string, SSLSocket ssls) throws IOException {
+                }
+ 
+                @Override
+                public void verify(String string, X509Certificate xc) throws SSLException {
+                }
+ 
+                @Override
+                public void verify(String string, String[] strings, String[] strings1) throws SSLException {
+                }
+ 
+                @Override
+                public boolean verify(String string, SSLSession ssls) {
+                    return true;
+                }
+            };
+            ctx.init(null, new TrustManager[]{tm}, null);
+            SSLSocketFactory ssf = new SSLSocketFactory(ctx);
+            ssf.setHostnameVerifier(verifier);
+            ClientConnectionManager ccm = base.getConnectionManager();
+            SchemeRegistry sr = ccm.getSchemeRegistry();
+            sr.register(new Scheme("https", ssf, 443));
+            return new DefaultHttpClient(ccm, base.getParams());
+        } catch (Exception ex) {
+            ex.printStackTrace();
+            return null;
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/test/com/cloud/network/resource/MockablePaloAltoResource.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/test/com/cloud/network/resource/MockablePaloAltoResource.java b/plugins/network-elements/palo-alto/test/com/cloud/network/resource/MockablePaloAltoResource.java
new file mode 100755
index 0000000..9a9eb6e
--- /dev/null
+++ b/plugins/network-elements/palo-alto/test/com/cloud/network/resource/MockablePaloAltoResource.java
@@ -0,0 +1,460 @@
+// 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.
+package com.cloud.network.resource;
+
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import javax.naming.ConfigurationException;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import com.cloud.agent.IAgentControl;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.ExternalNetworkResourceUsageAnswer;
+import com.cloud.agent.api.ExternalNetworkResourceUsageCommand;
+import com.cloud.agent.api.MaintainAnswer;
+import com.cloud.agent.api.MaintainCommand;
+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.StartupExternalFirewallCommand;
+import com.cloud.agent.api.routing.IpAssocAnswer;
+import com.cloud.agent.api.routing.IpAssocCommand;
+import com.cloud.agent.api.routing.NetworkElementCommand;
+import com.cloud.agent.api.routing.SetFirewallRulesCommand;
+import com.cloud.agent.api.routing.SetPortForwardingRulesCommand;
+import com.cloud.agent.api.routing.SetStaticNatRulesCommand;
+import com.cloud.agent.api.to.FirewallRuleTO;
+import com.cloud.agent.api.to.IpAddressTO;
+import com.cloud.agent.api.to.PortForwardingRuleTO;
+import com.cloud.agent.api.to.StaticNatRuleTO;
+import com.cloud.host.Host;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.FirewallRule.TrafficType;
+import com.cloud.network.rules.FirewallRule.Purpose;
+import com.cloud.resource.ServerResource;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.exception.ExecutionException;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.utils.script.Script;
+
+// http client handling
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.BasicResponseHandler;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.NameValuePair;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.protocol.HTTP;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.net.URLDecoder;
+import javax.xml.xpath.XPathFactory;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import com.cloud.network.utils.HttpClientWrapper;
+
+// for prettyFormat()
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Source;
+import java.io.StringWriter;
+
+
+public class MockablePaloAltoResource extends PaloAltoResource {
+	private HashMap<String, String> context;
+	public void setMockContext(HashMap<String, String> context) {
+		this.context = context;
+	}
+
+	/* Fake the calls to the Palo Alto API */
+    protected String request(PaloAltoMethod method, Map<String, String> params) throws ExecutionException {
+        if (method != PaloAltoMethod.GET && method != PaloAltoMethod.POST) {
+            throw new ExecutionException("Invalid http method used to access the Palo Alto API.");
+        }
+
+        String response = "";
+
+        // 'keygen' request
+        if (params.containsKey("type") && params.get("type").equals("keygen")) {
+            response = "<response status = 'success'><result><key>LUFRPT14MW5xOEo1R09KVlBZNnpnemh0VHRBOWl6TGM9bXcwM3JHUGVhRlNiY0dCR0srNERUQT09</key></result></response>";
+        }
+        
+        // 'config' requests
+        if (params.containsKey("type") && params.get("type").equals("config") && params.containsKey("action")) {
+        	// action = 'get'
+        	if (params.get("action").equals("get")) {
+                // get interface for type
+                // | public_using_ethernet
+                if (params.get("xpath").equals("/config/devices/entry/network/interface/ethernet/entry[@name='ethernet1/1']")) {
+                    if (context.containsKey("public_using_ethernet") && context.get("public_using_ethernet").equals("true")) {
+                        context.put("public_interface_type", "ethernet");
+                        response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"ethernet1/1\" admin=\"admin\" time=\"2013/06/18 13:33:56\"><layer3 admin=\"admin\" time=\"2013/06/18 13:33:56\"><ipv6><neighbor-discovery><router-advertisement><enable>no</enable><min-interval>200</min-interval><max-interval>600</max-interval><hop-limit>64</hop-limit><reachable-time>unspecified</reachable-time><retransmission-timer>unspecified</retransmission-timer><lifetime>1800</lifetime><managed-flag>no</managed-flag><other-flag>no</other-flag><enable-consistency-check>no</enable-consistency-check><link-mtu>unspecified</link-mtu></router-advertisement><enable-dad>no</enable-dad><reachable-time>30</reachable-time><ns-interval>1</ns-interval><dad-attempts>1</dad-attempts></neighbor-discovery><enabled>no</enabled><interface-id>EUI-64</interface-id></ipv6><untagged-sub-interface>no</untagged-sub-interface><units admin=\"admin\" time=\"2013/06/18 13:33:56\">
 <entry name=\"ethernet1/1.9999\" admin=\"admin\" time=\"2013/06/18 13:33:56\"><ipv6><neighbor-discovery><router-advertisement><enable>no</enable><min-interval>200</min-interval><max-interval>600</max-interval><hop-limit>64</hop-limit><reachable-time>unspecified</reachable-time><retransmission-timer>unspecified</retransmission-timer><lifetime>1800</lifetime><managed-flag>no</managed-flag><other-flag>no</other-flag><enable-consistency-check>no</enable-consistency-check><link-mtu>unspecified</link-mtu></router-advertisement><enable-dad>no</enable-dad><reachable-time>30</reachable-time><ns-interval>1</ns-interval><dad-attempts>1</dad-attempts></neighbor-discovery><enabled>no</enabled><interface-id>EUI-64</interface-id></ipv6><ip admin=\"admin\" time=\"2013/06/18 13:33:56\"><entry name=\"192.168.80.254/24\"/></ip><adjust-tcp-mss>no</adjust-tcp-mss><tag>3033</tag></entry></units></layer3><link-speed>auto</link-speed><link-duplex>auto</link-duplex><link-state>auto</link-state></entry></res
 ult></response>";
+                    } else {
+                        response = "<response status=\"success\" code=\"19\"><result/></response>";
+                    }
+                } // | private_using_ethernet
+                if (params.get("xpath").equals("/config/devices/entry/network/interface/ethernet/entry[@name='ethernet1/2']")) {
+                    if (context.containsKey("private_using_ethernet") && context.get("private_using_ethernet").equals("true")) {
+                        context.put("private_interface_type", "ethernet");
+                        response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"ethernet1/2\" admin=\"admin\" time=\"2013/06/18 13:33:57\"><layer3 admin=\"admin\" time=\"2013/06/18 13:33:57\"><ipv6><neighbor-discovery><router-advertisement><enable>no</enable><min-interval>200</min-interval><max-interval>600</max-interval><hop-limit>64</hop-limit><reachable-time>unspecified</reachable-time><retransmission-timer>unspecified</retransmission-timer><lifetime>1800</lifetime><managed-flag>no</managed-flag><other-flag>no</other-flag><enable-consistency-check>no</enable-consistency-check><link-mtu>unspecified</link-mtu></router-advertisement><enable-dad>no</enable-dad><reachable-time>30</reachable-time><ns-interval>1</ns-interval><dad-attempts>1</dad-attempts></neighbor-discovery><enabled>no</enabled><interface-id>EUI-64</interface-id></ipv6><untagged-sub-interface>no</untagged-sub-interface><units admin=\"admin\" time=\"2013/06/18 13:33:57\"/
 ></layer3><link-speed>auto</link-speed><link-duplex>auto</link-duplex><link-state>auto</link-state></entry></result></response>";
+                    } else {
+                        response = "<response status=\"success\" code=\"19\"><result/></response>";
+                    }
+                }
+
+                // get management profile | has_management_profile
+                if (params.get("xpath").equals("/config/devices/entry/network/profiles/interface-management-profile/entry[@name='Ping']")) {
+                    if (context.containsKey("has_management_profile") && context.get("has_management_profile").equals("true")) {
+                        response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"Ping\"><ping>yes</ping></entry></result></response>";
+                    } else {
+                        response = "<response status=\"success\" code=\"19\"><result/></response>";
+                    }
+                }
+
+        		// get public interface IP | has_public_interface
+                if (params.get("xpath").equals("/config/devices/entry/network/interface/ethernet/entry[@name='ethernet1/1']/layer3/units/entry[@name='ethernet1/1.9999']/ip/entry[@name='192.168.80.102/32']")) {
+                    if (context.containsKey("has_public_interface") && context.get("has_public_interface").equals("true")) {
+                        response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"192.168.80.102/32\" admin=\"admin\" time=\"2013/07/05 13:02:37\"/></result></response>";
+                    } else {
+                        response = "<response status=\"success\" code=\"19\"><result/></response>";
+                    }
+                }
+
+                // get private interface | has_private_interface
+                if (params.get("xpath").equals("/config/devices/entry/network/interface/ethernet/entry[@name='ethernet1/2']/layer3/units/entry[@name='ethernet1/2.3954']")) {
+                    if (context.containsKey("has_private_interface") && context.get("has_private_interface").equals("true")) {
+                        response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"ethernet1/2.3954\" admin=\"admin\" time=\"2013/07/05 13:02:36\"><tag admin=\"admin\" time=\"2013/07/05 13:02:36\">3954</tag><ip><entry name=\"10.5.80.1/20\"/></ip><interface-management-profile>Ping</interface-management-profile></entry></result></response>";
+                    } else {
+                        response = "<response status=\"success\" code=\"19\"><result/></response>";
+                    }
+                }
+
+                // get private interface ip
+                if (params.get("xpath").equals("/config/devices/entry/network/interface/ethernet/entry[@name='ethernet1/2']/layer3/units/entry[@name='ethernet1/2.3954']/ip/entry")) {
+                    response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"10.3.96.1/20\"/></result></response>";
+                }
+
+        		// get source nat | has_src_nat_rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='src_nat.3954']")) {
+                    if (context.containsKey("has_src_nat_rule") && context.get("has_src_nat_rule").equals("true")) {
+                        response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"src_nat.3954\" admin=\"admin\" time=\"2013/07/05 13:02:38\"><to admin=\"admin\" time=\"2013/07/05 13:02:38\"><member admin=\"admin\" time=\"2013/07/05 13:02:38\">untrust</member></to><from><member>trust</member></from><source><member>10.5.80.1/20</member></source><destination><member>any</member></destination><service>any</service><nat-type>ipv4</nat-type><to-interface>ethernet1/1.9999</to-interface><source-translation><dynamic-ip-and-port><interface-address><ip>192.168.80.102/32</ip><interface>ethernet1/1.9999</interface></interface-address></dynamic-ip-and-port></source-translation></entry></result></response>";
+                    } else {
+                        response = "<response status=\"success\" code=\"19\"><result/></response>";
+                    }
+                }
+
+                // get isolation firewall rule | has_isolation_fw_rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='isolate_3954']")) {
+                    if (context.containsKey("has_isolation_fw_rule") && context.get("has_isolation_fw_rule").equals("true")) {
+                        response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"isolate_3954\" admin=\"admin\" time=\"2013/07/05 13:02:38\"><from admin=\"admin\" time=\"2013/07/05 13:02:38\"><member admin=\"admin\" time=\"2013/07/05 13:02:38\">trust</member></from><to><member>trust</member></to><source><member>10.5.80.0/20</member></source><destination><member>10.5.80.1</member></destination><application><member>any</member></application><service><member>any</member></service><action>deny</action><negate-source>no</negate-source><negate-destination>yes</negate-destination></entry></result></response>";
+                    } else {
+                        response = "<response status=\"success\" code=\"19\"><result/></response>";
+                    }
+                }
+
+                // get service | has_service
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/service/entry[@name='cs_tcp_80']")) {
+                    if (context.containsKey("has_service_tcp_80") && context.get("has_service_tcp_80").equals("true")) {
+                        response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"cs_tcp_80\"><protocol><tcp><port>80</port></tcp></protocol></entry></result></response>";
+                    } else {
+                        response = "<response status=\"success\" code=\"19\"><result/></response>";
+                    }
+                }
+
+                // get egress firewall rule | has_egress_fw_rule | policy_0
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_0']")) {
+                    if (context.containsKey("has_egress_fw_rule") && context.get("has_egress_fw_rule").equals("true")) {
+                        response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"policy_0\" admin=\"admin\" time=\"2013/07/03 12:43:30\"><from admin=\"admin\" time=\"2013/07/03 12:43:30\"><member admin=\"admin\" time=\"2013/07/03 12:43:30\">trust</member></from><to><member>untrust</member></to><source><member>10.3.96.1/20</member></source><destination><member>any</member></destination><application><member>any</member></application><service><member>cs_tcp_80</member></service><action>allow</action><negate-source>no</negate-source><negate-destination>no</negate-destination></entry></result></response>";
+                    } else {
+                        response = "<response status=\"success\" code=\"19\"><result/></response>";
+                    }
+                }
+
+                // get ingress firewall rule | has_ingress_fw_rule | policy_8
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_8']")) {
+                    if (context.containsKey("has_ingress_fw_rule") && context.get("has_ingress_fw_rule").equals("true")) {
+                        response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"policy_8\" admin=\"admin\" time=\"2013/07/03 13:26:27\"><from admin=\"admin\" time=\"2013/07/03 13:26:27\"><member admin=\"admin\" time=\"2013/07/03 13:26:27\">untrust</member></from><to><member>trust</member></to><source><member>any</member></source><destination><member>192.168.80.103</member></destination><application><member>any</member></application><service><member>cs_tcp_80</member></service><action>allow</action><negate-source>no</negate-source><negate-destination>no</negate-destination></entry></result></response>";
+                    } else {
+                        response = "<response status=\"success\" code=\"19\"><result/></response>";
+                    }
+                }
+
+                // get destination nat rule (port forwarding) | has_dst_nat_rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='dst_nat.192-168-80-103_9']")) {
+                    if (context.containsKey("has_dst_nat_rule") && context.get("has_dst_nat_rule").equals("true")) {
+                        response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"dst_nat.192-168-80-103_9\" admin=\"admin\" time=\"2013/07/03 13:40:50\"><to admin=\"admin\" time=\"2013/07/03 13:40:50\"><member admin=\"admin\" time=\"2013/07/03 13:40:50\">untrust</member></to><from><member>untrust</member></from><source><member>any</member></source><destination><member>192.168.80.103</member></destination><service>cs_tcp_80</service><nat-type>ipv4</nat-type><to-interface>ethernet1/1.9999</to-interface><destination-translation><translated-address>10.3.97.158</translated-address><translated-port>8080</translated-port></destination-translation></entry></result></response>";
+                    } else {
+                        response = "<response status=\"success\" code=\"19\"><result/></response>";
+                    }
+                }
+
+                // get destination nat rules (returns all dst nat rules per ip)
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[destination/member[text()='192.168.80.103']]")) {
+                    if (context.containsKey("has_dst_nat_rule") && context.get("has_dst_nat_rule").equals("true")) {
+                        response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"dst_nat.192-168-80-103_9\" admin=\"admin\" time=\"2013/07/03 13:40:50\"><to admin=\"admin\" time=\"2013/07/03 13:40:50\"><member admin=\"admin\" time=\"2013/07/03 13:40:50\">untrust</member></to><from><member>untrust</member></from><source><member>any</member></source><destination><member>192.168.80.103</member></destination><service>cs_tcp_80</service><nat-type>ipv4</nat-type><to-interface>ethernet1/1.9999</to-interface><destination-translation><translated-address>10.3.97.158</translated-address><translated-port>8080</translated-port></destination-translation></entry></result></response>";
+                    } else {
+                        response = "<response status=\"success\" code=\"19\"><result/></response>";
+                    }
+                }
+
+                // get static nat rule | has_stc_nat_rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='stc_nat.192-168-80-103_0']")) {
+                    if (context.containsKey("has_stc_nat_rule") && context.get("has_stc_nat_rule").equals("true")) {
+                        response = "<response status=\"success\" code=\"19\"><result total-count=\"1\" count=\"1\"><entry name=\"stc_nat.192-168-80-103_0\" admin=\"admin\" time=\"2013/07/03 14:02:23\"><to admin=\"admin\" time=\"2013/07/03 14:02:23\"><member admin=\"admin\" time=\"2013/07/03 14:02:23\">untrust</member></to><from><member>untrust</member></from><source><member>any</member></source><destination><member>192.168.80.103</member></destination><service>any</service><nat-type>ipv4</nat-type><to-interface>ethernet1/1.9999</to-interface><destination-translation><translated-address>10.3.97.158</translated-address></destination-translation></entry></result></response>";
+                    } else {
+                        response = "<response status=\"success\" code=\"19\"><result/></response>";
+                    }
+                }
+
+        	}
+
+        	// action = 'set'
+        	if (params.get("action").equals("set")) {
+                // set management profile
+                if (params.get("xpath").equals("/config/devices/entry/network/profiles/interface-management-profile/entry[@name='Ping']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.put("has_management_profile", "true");
+                }
+
+                // add private interface
+                if (params.get("xpath").equals("/config/devices/entry/network/interface/ethernet/entry[@name='ethernet1/2']/layer3/units/entry[@name='ethernet1/2.3954']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.put("has_private_interface", "true");
+                }
+
+                // add public ip to public interface
+                if (params.get("xpath").equals("/config/devices/entry/network/interface/ethernet/entry[@name='ethernet1/1']/layer3/units/entry[@name='ethernet1/1.9999']/ip")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.put("has_public_interface", "true");
+                }
+
+                // add private interface to zone
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/zone/entry[@name='trust']/network/layer3")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                }
+
+                // add public interface to zone
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/zone/entry[@name='untrust']/network/layer3")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                }
+
+                // set virtual router (public | private)
+                if (params.get("xpath").equals("/config/devices/entry/network/virtual-router/entry[@name='default']/interface")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                }
+
+                // add interface to network (public | private)
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/import/network/interface")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                }
+
+                // add src nat rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='src_nat.3954']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.put("has_src_nat_rule", "true");
+                }
+
+                // add isolation firewall rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='isolate_3954']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.put("has_isolation_fw_rule", "true");
+                }
+
+                // add egress firewall rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_0']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.put("has_egress_fw_rule", "true");
+                }
+
+                // add ingress firewall rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_8']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.put("has_ingress_fw_rule", "true");
+                }
+
+                // add destination nat rule (port forwarding)
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='dst_nat.192-168-80-103_9']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.put("has_dst_nat_rule", "true");
+                }
+
+                // add static nat rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='stc_nat.192-168-80-103_0']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.put("has_stc_nat_rule", "true");
+                }
+
+                // add tcp 80 service
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/service/entry[@name='cs_tcp_80']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.put("has_service_tcp_80", "true");
+                }
+        	}
+
+        	// action = 'delete'
+        	if (params.get("action").equals("delete")) {
+                // remove egress firewall rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_0']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.remove("has_egress_fw_rule");
+                }
+
+                // remove ingress firewall rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='policy_8']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.remove("has_ingress_fw_rule");
+                }
+
+                // remove destination nat rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='dst_nat.192-168-80-103_9']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.remove("has_dst_nat_rule");
+                }
+
+                // remove static nat rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='stc_nat.192-168-80-103_0']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.remove("has_dst_nat_rule");
+                }
+
+                // remove public ip from interface (dst_nat | stc_nat)
+                if (params.get("xpath").equals("/config/devices/entry/network/interface/ethernet/entry[@name='ethernet1/1']/layer3/units/entry[@name='ethernet1/1.9999']/ip/entry[@name='192.168.80.103/32']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                }
+
+                // remove isolation firewall rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='isolate_3954']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.remove("has_isolation_fw_rule");
+                }
+
+                // remove source nat rule
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='src_nat.3954']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.remove("has_src_nat_rule");
+                }
+
+                // remove public source nat ip
+                if (params.get("xpath").equals("/config/devices/entry/network/interface/ethernet/entry[@name='ethernet1/1']/layer3/units/entry[@name='ethernet1/1.9999']/ip/entry[@name='192.168.80.102/32']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.remove("has_public_interface");
+                }
+
+                // remove private interface from the zone
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/zone/entry[@name='trust']/network/layer3/member[text()='ethernet1/2.3954']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                }
+
+                // remove private interface from the virtual router
+                if (params.get("xpath").equals("/config/devices/entry/network/virtual-router/entry[@name='default']/interface/member[text()='ethernet1/2.3954']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                }
+
+                // remove private interface from network
+                if (params.get("xpath").equals("/config/devices/entry/vsys/entry[@name='vsys1']/import/network/interface/member[text()='ethernet1/2.3954']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                }
+
+                // remove private interface
+                if (params.get("xpath").equals("/config/devices/entry/network/interface/ethernet/entry[@name='ethernet1/2']/layer3/units/entry[@name='ethernet1/2.3954']")) {
+                    response = "<response status=\"success\" code=\"20\"><msg>command succeeded</msg></response>";
+                    context.remove("has_private_interface");
+                }
+
+        	}
+        } // end 'config'
+
+        // 'op' requests
+        if (params.containsKey("type") && params.get("type").equals("op")) {
+        	// check if there are pending changes
+        	if (params.get("cmd").equals("<check><pending-changes></pending-changes></check>")) {
+                if (context.containsKey("firewall_has_pending_changes") && context.get("firewall_has_pending_changes").equals("true")) {
+                    response = "<response status=\"success\"><result>yes</result></response>";
+                } else {
+                    response = "<response status=\"success\"><result>no</result></response>";
+                }
+        	}
+
+        	// add a config lock
+        	if (params.get("cmd").equals("<request><config-lock><add></add></config-lock></request>")) {
+                response = "<response status=\"success\"><result>Successfully acquired lock. Other administrators will not be able to modify configuration for scope shared until lock is released</result></response>";
+        	}
+
+            // check job status
+            if (params.get("cmd").equals("<show><jobs><id>1</id></jobs></show>")) {
+                if (context.containsKey("simulate_commit_failure") && context.get("simulate_commit_failure").equals("true")) {
+                    response = "<response status=\"success\"><result><job><tenq>2013/07/10 11:11:49</tenq><id>1</id><user>admin</user><type>Commit</type><status>FIN</status><stoppable>no</stoppable><result>FAIL</result><tfin>11:11:54</tfin><progress>11:11:54</progress><details><line>Bad config</line><line>Commit failed</line></details><warnings></warnings></job></result></response>";
+                } else { 
+                    response = "<response status=\"success\"><result><job><tenq>2013/07/02 14:49:49</tenq><id>1</id><user>admin</user><type>Commit</type><status>FIN</status><stoppable>no</stoppable><result>OK</result><tfin>14:50:02</tfin><progress>14:50:02</progress><details><line>Configuration committed successfully</line></details><warnings></warnings></job></result></response>";
+                }
+            }
+
+        	// load from running config
+        	if (params.get("cmd").equals("<load><config><from>running-config.xml</from></config></load>")) {
+                response = "<response status=\"success\"><result><msg><line>Config loaded from running-config.xml</line></msg></result></response>";
+        	}
+
+        	// remove config lock
+        	if (params.get("cmd").equals("<request><config-lock><remove></remove></config-lock></request>")) {
+                response = "<response status=\"success\"><result>Config lock released for scope shared</result></response>";
+        	}
+        } // end 'op'
+
+        // 'commit' requests
+        if (params.containsKey("type") && params.get("type").equals("commit")) {
+        	// cmd = '<commit></commit>'
+        	if (params.get("cmd").equals("<commit></commit>")) {
+                response = "<response status=\"success\" code=\"19\"><result><msg><line>Commit job enqueued with jobid 1</line></msg><job>1</job></result></response>";
+        	}
+        } // end 'commit'
+
+
+        // print out the details into the console
+        if (context.containsKey("enable_console_output") && context.get("enable_console_output") == "true") {
+            if (params.containsKey("xpath")) {
+                System.out.println("XPATH("+params.get("action")+"): "+params.get("xpath"));
+            }
+            if (params.containsKey("type") && params.get("type").equals("op")) {
+                System.out.println("OP CMD: "+params.get("cmd"));
+            }
+            System.out.println(response+"\n");
+        }
+
+        return response;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/test/com/cloud/network/resource/PaloAltoResourceTest.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/test/com/cloud/network/resource/PaloAltoResourceTest.java b/plugins/network-elements/palo-alto/test/com/cloud/network/resource/PaloAltoResourceTest.java
new file mode 100755
index 0000000..c270473
--- /dev/null
+++ b/plugins/network-elements/palo-alto/test/com/cloud/network/resource/PaloAltoResourceTest.java
@@ -0,0 +1,507 @@
+// 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.
+package com.cloud.network.resource;
+
+// test imports
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.*;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.util.Collections;
+
+// basic imports
+import java.io.BufferedReader;
+import java.io.FileReader;
+import java.io.IOException;
+import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.apache.log4j.Logger;
+import org.w3c.dom.Document;
+import org.w3c.dom.Node;
+import org.w3c.dom.NodeList;
+import org.xml.sax.InputSource;
+import javax.naming.ConfigurationException;
+import javax.xml.parsers.DocumentBuilderFactory;
+
+import com.cloud.agent.IAgentControl;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.Command;
+import com.cloud.agent.api.ExternalNetworkResourceUsageAnswer;
+import com.cloud.agent.api.ExternalNetworkResourceUsageCommand;
+import com.cloud.agent.api.MaintainAnswer;
+import com.cloud.agent.api.MaintainCommand;
+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.StartupExternalFirewallCommand;
+import com.cloud.agent.api.routing.IpAssocAnswer;
+import com.cloud.agent.api.routing.IpAssocCommand;
+import com.cloud.agent.api.routing.NetworkElementCommand;
+import com.cloud.agent.api.routing.SetFirewallRulesCommand;
+import com.cloud.agent.api.routing.SetPortForwardingRulesCommand;
+import com.cloud.agent.api.routing.SetStaticNatRulesCommand;
+import com.cloud.agent.api.to.FirewallRuleTO;
+import com.cloud.agent.api.to.IpAddressTO;
+import com.cloud.agent.api.to.PortForwardingRuleTO;
+import com.cloud.agent.api.to.StaticNatRuleTO;
+import com.cloud.host.Host;
+import com.cloud.network.rules.FirewallRuleVO;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.FirewallRule.TrafficType;
+import com.cloud.network.rules.FirewallRule.Purpose;
+import com.cloud.network.rules.FirewallRule.State;
+import com.cloud.resource.ServerResource;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.exception.ExecutionException;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.utils.script.Script;
+
+// http client handling
+import org.apache.http.client.ResponseHandler;
+import org.apache.http.client.HttpClient;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.impl.client.BasicResponseHandler;
+import org.apache.http.impl.client.DefaultHttpClient;
+import org.apache.http.NameValuePair;
+import org.apache.http.message.BasicNameValuePair;
+import org.apache.http.client.entity.UrlEncodedFormEntity;
+import org.apache.http.protocol.HTTP;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.net.URLDecoder;
+import javax.xml.xpath.XPathFactory;
+import javax.xml.xpath.XPath;
+import javax.xml.xpath.XPathExpression;
+import javax.xml.xpath.XPathConstants;
+import javax.xml.xpath.XPathExpressionException;
+import com.cloud.network.utils.HttpClientWrapper;
+
+// for prettyFormat()
+import javax.xml.transform.stream.StreamSource;
+import javax.xml.transform.stream.StreamResult;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Source;
+import java.io.StringWriter;
+
+public class PaloAltoResourceTest {
+	// configuration data
+	private String _test_name = "PaloAltoTestDevice";
+    private String _test_zoneId = "TestZone";
+    private String _test_ip = "192.168.80.2";
+    private String _test_username = "admin";
+    private String _test_password = "admin";
+    private String _test_publicInterface = "ethernet1/1";
+    private String _test_privateInterface = "ethernet1/2";
+    private String _test_publicZone = "untrust";
+    private String _test_privateZone = "trust";
+    private String _test_virtualRouter = "default";
+
+	MockablePaloAltoResource _resource;
+	Map<String, Object> _resource_params;
+	HashMap<String, String> _context;
+	
+	@Before
+	public void setUp() {
+		_resource = new MockablePaloAltoResource();
+		_resource_params = new HashMap<String, Object>(); // params to be passed to configure()
+		_resource_params.put("name", _test_name);
+		_resource_params.put("zoneId", _test_zoneId);
+		_resource_params.put("ip", _test_ip);
+		_resource_params.put("username", _test_username);
+		_resource_params.put("password", _test_password);
+		_resource_params.put("publicinterface", _test_publicInterface);
+		_resource_params.put("privateinterface", _test_privateInterface);
+		_resource_params.put("publicnetwork", _test_publicZone);
+		_resource_params.put("privatenetwork", _test_privateZone);
+		_resource_params.put("pavr", _test_virtualRouter);
+		_resource_params.put("guid", "aaaaa-bbbbb-ccccc");
+
+		_context = new HashMap<String, String>(); // global context
+		_context.put("name", _test_name);
+		_context.put("zone_id", _test_zoneId);
+		_context.put("ip", _test_ip);
+		_context.put("username", _test_username);
+		_context.put("password", _test_password);
+		_context.put("public_interface", _test_publicInterface);
+		_context.put("private_interface", _test_privateInterface);
+		_context.put("public_zone", _test_publicZone);
+		_context.put("private_zone", _test_privateZone);
+		_context.put("pa_vr", _test_virtualRouter);
+		// --
+		_context.put("public_using_ethernet", "true");
+		_context.put("private_using_ethernet", "true");
+		_context.put("has_management_profile", "true");
+		_context.put("enable_console_output", "false"); // CHANGE TO "true" TO ENABLE CONSOLE LOGGING OF TESTS
+		_resource.setMockContext(_context);
+	}
+
+	@Test (expected=ConfigurationException.class)
+	public void resourceConfigureFailure() throws ConfigurationException {
+		_resource.configure("PaloAltoResource", new HashMap<String, Object>());
+	}
+	
+	@Test 
+	public void resourceConfigureWithoutManagementProfile() throws ConfigurationException {
+		if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+			System.out.println("\nTEST: resourceConfigureWithoutManagementProfile");
+	        System.out.println("---------------------------------------------------");
+	    }
+        _context.remove("has_management_profile");
+		_resource.setMockContext(_context);
+		_resource.configure("PaloAltoResource", _resource_params);
+	}
+
+	@Test 
+	public void resourceConfigureWithManagementProfile() throws ConfigurationException {
+		if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+			System.out.println("\nTEST: resourceConfigureWithManagementProfile");
+			System.out.println("---------------------------------------------------");
+		}
+		_resource.configure("PaloAltoResource", _resource_params);
+	}
+
+	@Test (expected=ConfigurationException.class)
+	public void simulateFirewallNotConfigurable() throws ConfigurationException {
+		if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+			System.out.println("\nTEST: simulateFirewallNotConfigurable");
+	        System.out.println("---------------------------------------------------");
+	    }
+	    _context.put("firewall_has_pending_changes", "true");
+        _context.remove("has_management_profile");
+		_resource.setMockContext(_context);
+		_resource.configure("PaloAltoResource", _resource_params);
+	}
+
+	@Test (expected=ConfigurationException.class)
+	public void simulateFirewallCommitFailure() throws ConfigurationException {
+		if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+			System.out.println("\nTEST: simulateFirewallCommitFailure");
+	        System.out.println("---------------------------------------------------");
+	    }
+	    _context.put("simulate_commit_failure", "true");
+        _context.remove("has_management_profile");
+		_resource.setMockContext(_context);
+		_resource.configure("PaloAltoResource", _resource_params);
+	}
+
+	@Test
+    public void testInitialize() throws ConfigurationException {
+    	if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+	        System.out.println("\nTEST: testInitialization");
+			System.out.println("---------------------------------------------------");
+		}
+		_resource.configure("PaloAltoResource", _resource_params);
+
+        StartupCommand[] sc = _resource.initialize();
+        assertTrue(sc.length == 1);
+        assertTrue("aaaaa-bbbbb-ccccc".equals(sc[0].getGuid()));
+        assertTrue("PaloAltoTestDevice".equals(sc[0].getName()));
+        assertTrue("TestZone".equals(sc[0].getDataCenter()));
+    }
+
+	@Test // implement public & private interfaces, source nat, guest network
+	public void implementGuestNetwork() throws ConfigurationException, ExecutionException {
+		if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+			System.out.println("\nTEST: implementGuestNetwork");
+			System.out.println("---------------------------------------------------");
+		}
+		_resource.configure("PaloAltoResource", _resource_params);
+
+		IpAddressTO ip = new IpAddressTO(Long.valueOf("1"), "192.168.80.102", true, false, true, "untagged", null, null, null, 100, false);
+		IpAddressTO[] ips = new IpAddressTO[1];
+        ips[0] = ip;
+        IpAssocCommand cmd = new IpAssocCommand(ips);
+        cmd.setAccessDetail(NetworkElementCommand.GUEST_NETWORK_GATEWAY, "10.3.96.1");
+        cmd.setAccessDetail(NetworkElementCommand.GUEST_NETWORK_CIDR, "10.3.96.1/20");
+        cmd.setAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG, "3954");
+
+        IpAssocAnswer answer = (IpAssocAnswer) _resource.executeRequest(cmd);
+        assertTrue(answer.getResult());
+	}
+
+	@Test // remove public & private interface details, source nat, guest network
+	public void shutdownGuestNetwork() throws ConfigurationException, ExecutionException {
+		if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+			System.out.println("\nTEST: shutdownGuestNetwork");
+			System.out.println("---------------------------------------------------");
+		}
+		_context.put("has_public_interface", "true");
+		_context.put("has_private_interface", "true");
+		_context.put("has_src_nat_rule", "true");
+		_context.put("has_isolation_fw_rule", "true");
+		_resource.setMockContext(_context);
+		_resource.configure("PaloAltoResource", _resource_params);
+
+		IpAddressTO ip = new IpAddressTO(Long.valueOf("1"), "192.168.80.102", false, false, true, "untagged", null, null, null, 100, false);
+		IpAddressTO[] ips = new IpAddressTO[1];
+        ips[0] = ip;
+        IpAssocCommand cmd = new IpAssocCommand(ips);
+        cmd.setAccessDetail(NetworkElementCommand.GUEST_NETWORK_GATEWAY, "10.3.96.1");
+        cmd.setAccessDetail(NetworkElementCommand.GUEST_NETWORK_CIDR, "10.3.96.1/20");
+        cmd.setAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG, "3954");
+
+        IpAssocAnswer answer = (IpAssocAnswer) _resource.executeRequest(cmd);
+        assertTrue(answer.getResult());
+	}
+
+	@Test
+    public void addIngressFirewallRule() throws ConfigurationException, Exception {
+    	if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+	    	System.out.println("\nTEST: addIngressFirewallRule");
+			System.out.println("---------------------------------------------------");
+		}
+		_context.put("has_public_interface", "true");
+		_context.put("has_private_interface", "true");
+		_context.put("has_src_nat_rule", "true");
+		_context.put("has_isolation_fw_rule", "true");
+		_context.put("has_service_tcp_80", "true");
+		_resource.setMockContext(_context);
+		_resource.configure("PaloAltoResource", _resource_params);
+
+        long vlanId = 3954;
+        List<FirewallRuleTO> rules = new ArrayList<FirewallRuleTO>();
+        List<String> cidrList = new ArrayList<String>();
+        cidrList.add("0.0.0.0/0");
+        FirewallRuleTO active = new FirewallRuleTO(8,
+            null, "192.168.80.103", "tcp", 80, 80, false, false,
+            FirewallRule.Purpose.Firewall, cidrList, null, null);
+        rules.add(active);
+
+        SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(rules);
+        cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId));
+        cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, "10.3.96.1/20");
+
+        Answer answer = _resource.executeRequest(cmd);
+        assertTrue(answer.getResult());
+    }
+
+	@Test
+    public void removeIngressFirewallRule() throws ConfigurationException, Exception {
+    	if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+	    	System.out.println("\nTEST: removeIngressFirewallRule");
+			System.out.println("---------------------------------------------------");
+		}
+		_context.put("has_public_interface", "true");
+		_context.put("has_private_interface", "true");
+		_context.put("has_src_nat_rule", "true");
+		_context.put("has_isolation_fw_rule", "true");
+		_context.put("has_service_tcp_80", "true");
+		_context.put("has_ingress_fw_rule", "true");
+		_resource.setMockContext(_context);
+		_resource.configure("PaloAltoResource", _resource_params);
+
+        long vlanId = 3954;
+        List<FirewallRuleTO> rules = new ArrayList<FirewallRuleTO>();
+        FirewallRuleTO revoked = new FirewallRuleTO(8,
+            null, "192.168.80.103", "tcp", 80, 80, true, false,
+            FirewallRule.Purpose.Firewall, null, null, null);
+        rules.add(revoked);
+
+        SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(rules);
+        cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId));
+        cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, "10.3.96.1/20");
+
+        Answer answer = _resource.executeRequest(cmd);
+        assertTrue(answer.getResult());
+    }
+
+    @Test
+    public void addEgressFirewallRule() throws ConfigurationException, Exception {
+    	if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+	    	System.out.println("\nTEST: addEgressFirewallRule");
+			System.out.println("---------------------------------------------------");
+		}
+		_context.put("has_public_interface", "true");
+		_context.put("has_private_interface", "true");
+		_context.put("has_src_nat_rule", "true");
+		_context.put("has_isolation_fw_rule", "true");
+		_context.put("has_service_tcp_80", "true");
+		_resource.setMockContext(_context);
+		_resource.configure("PaloAltoResource", _resource_params);
+
+        long vlanId = 3954;
+        List<FirewallRuleTO> rules = new ArrayList<FirewallRuleTO>();
+        List<String> cidrList = new ArrayList<String>();
+        cidrList.add("0.0.0.0/0");
+        FirewallRuleVO activeVO = new FirewallRuleVO(null, null, 80, 80, "tcp", 
+            1, 1, 1, Purpose.Firewall, cidrList, null,
+            null, null, FirewallRule.TrafficType.Egress);
+        FirewallRuleTO active = new FirewallRuleTO(activeVO, Long.toString(vlanId), null, Purpose.Firewall, FirewallRule.TrafficType.Egress);
+        rules.add(active);
+
+        SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(rules);
+        cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId));
+        cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, "10.3.96.1/20");
+
+        Answer answer = _resource.executeRequest(cmd);
+        assertTrue(answer.getResult());
+    }
+
+	@Test
+    public void removeEgressFirewallRule() throws ConfigurationException, Exception {
+    	if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+	    	System.out.println("\nTEST: removeEgressFirewallRule");
+			System.out.println("---------------------------------------------------");
+		}
+		_context.put("has_public_interface", "true");
+		_context.put("has_private_interface", "true");
+		_context.put("has_src_nat_rule", "true");
+		_context.put("has_isolation_fw_rule", "true");
+		_context.put("has_service_tcp_80", "true");
+		_context.put("has_egress_fw_rule", "true");
+		_resource.setMockContext(_context);
+		_resource.configure("PaloAltoResource", _resource_params);
+
+        long vlanId = 3954;
+        List<FirewallRuleTO> rules = new ArrayList<FirewallRuleTO>();
+        FirewallRuleVO revokedVO = new FirewallRuleVO(null, null, 80, 80, "tcp", 
+            1, 1, 1, Purpose.Firewall, null, null, null, null, FirewallRule.TrafficType.Egress);
+        revokedVO.setState(State.Revoke);
+        FirewallRuleTO revoked = new FirewallRuleTO(revokedVO, Long.toString(vlanId), null, Purpose.Firewall, FirewallRule.TrafficType.Egress);
+        rules.add(revoked);
+
+        SetFirewallRulesCommand cmd = new SetFirewallRulesCommand(rules);
+        cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId));
+        cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, "10.3.96.1/20");
+
+        Answer answer = _resource.executeRequest(cmd);
+        assertTrue(answer.getResult());
+    }
+
+    @Test
+    public void addStaticNatRule() throws ConfigurationException, Exception {
+    	if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+	    	System.out.println("\nTEST: addStaticNatRule");
+			System.out.println("---------------------------------------------------");
+		}
+		_context.put("has_public_interface", "true");
+		_context.put("has_private_interface", "true");
+		_context.put("has_src_nat_rule", "true");
+		_context.put("has_isolation_fw_rule", "true");
+		_context.put("has_service_tcp_80", "true");
+		_resource.setMockContext(_context);
+		_resource.configure("PaloAltoResource", _resource_params);
+
+        long vlanId = 3954;
+        List<StaticNatRuleTO> rules = new ArrayList<StaticNatRuleTO>();
+        StaticNatRuleTO active = new StaticNatRuleTO(0, "192.168.80.103", null,
+                null, "10.3.97.158", null, null, null, false, false);
+        rules.add(active);
+
+        SetStaticNatRulesCommand cmd = new SetStaticNatRulesCommand(rules, null);
+        cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId));
+        cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, "10.3.96.1/20");
+
+        Answer answer = _resource.executeRequest(cmd);
+        assertTrue(answer.getResult());
+    }
+
+    @Test
+    public void removeStaticNatRule() throws ConfigurationException, Exception {
+    	if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+	    	System.out.println("\nTEST: removeStaticNatRule");
+			System.out.println("---------------------------------------------------");
+		}
+		_context.put("has_public_interface", "true");
+		_context.put("has_private_interface", "true");
+		_context.put("has_src_nat_rule", "true");
+		_context.put("has_isolation_fw_rule", "true");
+		_context.put("has_service_tcp_80", "true");
+		_context.put("has_stc_nat_rule", "true");
+		_resource.setMockContext(_context);
+		_resource.configure("PaloAltoResource", _resource_params);
+
+        long vlanId = 3954;
+        List<StaticNatRuleTO> rules = new ArrayList<StaticNatRuleTO>();
+        StaticNatRuleTO revoked = new StaticNatRuleTO(0, "192.168.80.103", null,
+                null, "10.3.97.158", null, null, null, true, false);
+        rules.add(revoked);
+
+        SetStaticNatRulesCommand cmd = new SetStaticNatRulesCommand(rules, null);
+        cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId));
+        cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, "10.3.96.1/20");
+
+        Answer answer = _resource.executeRequest(cmd);
+        assertTrue(answer.getResult());
+    }
+
+    @Test
+    public void addPortForwardingRule() throws ConfigurationException, Exception {
+    	if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+	    	System.out.println("\nTEST: addPortForwardingRule");
+			System.out.println("---------------------------------------------------");
+		}
+		_context.put("has_public_interface", "true");
+		_context.put("has_private_interface", "true");
+		_context.put("has_src_nat_rule", "true");
+		_context.put("has_isolation_fw_rule", "true");
+		_context.put("has_service_tcp_80", "true");
+		_resource.setMockContext(_context);
+		_resource.configure("PaloAltoResource", _resource_params);
+
+        long vlanId = 3954;
+        List<PortForwardingRuleTO> rules = new ArrayList<PortForwardingRuleTO>();
+        PortForwardingRuleTO active = new PortForwardingRuleTO(9, "192.168.80.103", 80,
+            80, "10.3.97.158", 8080, 8080, "tcp", false, false);
+        rules.add(active);
+
+        SetPortForwardingRulesCommand cmd = new SetPortForwardingRulesCommand(rules);
+        cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId));
+        cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, "10.3.96.1/20");
+
+        Answer answer = _resource.executeRequest(cmd);
+        assertTrue(answer.getResult());
+    }
+
+    @Test
+    public void removePortForwardingRule() throws ConfigurationException, Exception {
+    	if (_context.containsKey("enable_console_output") && _context.get("enable_console_output").equals("true")) {
+	    	System.out.println("\nTEST: removePortForwardingRule");
+			System.out.println("---------------------------------------------------");
+		}
+		_context.put("has_public_interface", "true");
+		_context.put("has_private_interface", "true");
+		_context.put("has_src_nat_rule", "true");
+		_context.put("has_isolation_fw_rule", "true");
+		_context.put("has_service_tcp_80", "true");
+		_context.put("has_dst_nat_rule", "true");
+		_resource.setMockContext(_context);
+		_resource.configure("PaloAltoResource", _resource_params);
+
+        long vlanId = 3954;
+        List<PortForwardingRuleTO> rules = new ArrayList<PortForwardingRuleTO>();
+        PortForwardingRuleTO revoked = new PortForwardingRuleTO(9, "192.168.80.103", 80,
+            80, "10.3.97.158", 8080, 8080, "tcp", true, false);
+        rules.add(revoked);
+
+        SetPortForwardingRulesCommand cmd = new SetPortForwardingRulesCommand(rules);
+        cmd.setContextParam(NetworkElementCommand.GUEST_VLAN_TAG, Long.toString(vlanId));
+        cmd.setContextParam(NetworkElementCommand.GUEST_NETWORK_CIDR, "10.3.96.1/20");
+
+        Answer answer = _resource.executeRequest(cmd);
+        assertTrue(answer.getResult());
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/pom.xml b/plugins/pom.xml
index 4f193bc..d0817a2 100755
--- a/plugins/pom.xml
+++ b/plugins/pom.xml
@@ -44,6 +44,7 @@
     <module>network-elements/elastic-loadbalancer</module>
     <module>network-elements/ovs</module>
     <module>network-elements/juniper-contrail</module>
+    <module>network-elements/palo-alto</module>
     <module>network-elements/nicira-nvp</module>
     <module>network-elements/bigswitch-vns</module>
     <module>network-elements/midonet</module>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/server/src/com/cloud/api/ApiResponseHelper.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java
index 769d345..36ef4bd 100755
--- a/server/src/com/cloud/api/ApiResponseHelper.java
+++ b/server/src/com/cloud/api/ApiResponseHelper.java
@@ -2631,7 +2631,7 @@ public class ApiResponseHelper implements ResponseGenerator {
         List<ProviderResponse> serviceProvidersResponses = new ArrayList<ProviderResponse>();
         for (Network.Provider serviceProvider : serviceProviders) {
             // return only Virtual Router/JuniperSRX/CiscoVnmc as a provider for the firewall
-            if (service == Service.Firewall && !(serviceProvider == Provider.VirtualRouter || serviceProvider == Provider.JuniperSRX || serviceProvider == Provider.CiscoVnmc)) {
+            if (service == Service.Firewall && !(serviceProvider == Provider.VirtualRouter || serviceProvider == Provider.JuniperSRX || serviceProvider == Provider.CiscoVnmc || serviceProvider == Provider.PaloAlto)) {
                 continue;
             }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
index e3aa4fa..2e9b388 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -3792,6 +3792,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
                             firewallProvider = provider;
                         }
 
+                        if (provider == Provider.PaloAlto) {
+                            firewallProvider = Provider.PaloAlto;
+                        }
+                        
                         if ((service == Service.PortForwarding || service == Service.StaticNat)
                                 && provider == Provider.VirtualRouter) {
                             firewallProvider = Provider.VirtualRouter;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/ui/dictionary.jsp
----------------------------------------------------------------------
diff --git a/ui/dictionary.jsp b/ui/dictionary.jsp
index 85f24c6..8bd547b 100644
--- a/ui/dictionary.jsp
+++ b/ui/dictionary.jsp
@@ -322,6 +322,7 @@ dictionary = {
 'label.add.new.gateway': '<fmt:message key="label.add.new.gateway" />',
 'label.add.new.NetScaler': '<fmt:message key="label.add.new.NetScaler" />',
 'label.add.new.SRX': '<fmt:message key="label.add.new.SRX" />',
+'label.add.new.PA': '<fmt:message key="label.add.new.PA" />',
 'label.add.new.tier': '<fmt:message key="label.add.new.tier" />',
 'label.add.NiciraNvp.device': '<fmt:message key="label.add.NiciraNvp.device" />',
 'label.add.pod': '<fmt:message key="label.add.pod" />',
@@ -334,6 +335,7 @@ dictionary = {
 'label.add.security.group': '<fmt:message key="label.add.security.group" />',
 'label.add.service.offering': '<fmt:message key="label.add.service.offering" />',
 'label.add.SRX.device': '<fmt:message key="label.add.SRX.device" />',
+'label.add.PA.device': '<fmt:message key="label.add.PA.device" />',
 'label.add.static.nat.rule': '<fmt:message key="label.add.static.nat.rule" />',
 'label.add.static.route': '<fmt:message key="label.add.static.route" />',
 'label.add.system.service.offering': '<fmt:message key="label.add.system.service.offering" />',
@@ -480,6 +482,7 @@ dictionary = {
 'label.delete.NiciraNvp': '<fmt:message key="label.delete.NiciraNvp" />',
 'label.delete.project': '<fmt:message key="label.delete.project" />',
 'label.delete.SRX': '<fmt:message key="label.delete.SRX" />',
+'label.delete.PA': '<fmt:message key="label.delete.PA" />',
 'label.delete.VPN.connection': '<fmt:message key="label.delete.VPN.connection" />',
 'label.delete.VPN.customer.gateway': '<fmt:message key="label.delete.VPN.customer.gateway" />',
 'label.delete.VPN.gateway': '<fmt:message key="label.delete.VPN.gateway" />',
@@ -859,6 +862,8 @@ dictionary = {
 'label.owned.public.ips': '<fmt:message key="label.owned.public.ips" />',
 'label.owner.account': '<fmt:message key="label.owner.account" />',
 'label.owner.domain': '<fmt:message key="label.owner.domain" />',
+'label.PA.log.profile': '<fmt:message key="label.PA.log.profile" />',
+'label.PA.threat.profile': '<fmt:message key="label.PA.threat.profile" />',
 'label.parent.domain': '<fmt:message key="label.parent.domain" />',
 'label.password.enabled': '<fmt:message key="label.password.enabled" />',
 'label.password': '<fmt:message key="label.password" />',
@@ -1031,6 +1036,7 @@ dictionary = {
 'label.specify.vxlan': '<fmt:message key="label.specify.vxlan" />',
 'label.SR.name ': '<fmt:message key="label.SR.name " />',
 'label.srx': '<fmt:message key="label.srx" />',
+'label.PA': '<fmt:message key="label.PA" />',
 'label.start.IP': '<fmt:message key="label.start.IP" />',
 'label.start.port': '<fmt:message key="label.start.port" />',
 'label.start.reserved.system.IP': '<fmt:message key="label.start.reserved.system.IP" />',
@@ -1332,6 +1338,7 @@ dictionary = {
 'message.confirm.delete.F5': '<fmt:message key="message.confirm.delete.F5" />',
 'message.confirm.delete.NetScaler': '<fmt:message key="message.confirm.delete.NetScaler" />',
 'message.confirm.delete.SRX': '<fmt:message key="message.confirm.delete.SRX" />',
+'message.confirm.delete.PA': '<fmt:message key="message.confirm.delete.PA" />',
 'message.confirm.destroy.router': '<fmt:message key="message.confirm.destroy.router" />',
 'message.confirm.disable.provider': '<fmt:message key="message.confirm.disable.provider" />',
 'message.confirm.enable.provider': '<fmt:message key="message.confirm.enable.provider" />',

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/ui/scripts/docs.js
----------------------------------------------------------------------
diff --git a/ui/scripts/docs.js b/ui/scripts/docs.js
index 3a4f8ca..7b7edf4 100755
--- a/ui/scripts/docs.js
+++ b/ui/scripts/docs.js
@@ -770,6 +770,75 @@ cloudStack.docs = {
         desc: 'Number of guest networks/accounts that will share this device',
         externalLink: ''
     },
+    // Add Palo Alto
+    helpPaloAltoIPAddress: {
+        desc: 'The IP address of the device',
+        externalLink: ''
+    },
+    helpPaloAltoUsername: {
+        desc: 'A user ID with valid authentication credentials that provide to access the device',
+        externalLink: ''
+    },
+    helpPaloAltoPassword: {
+        desc: 'The password for the user ID provided in Username',
+        externalLink: ''
+    },
+    helpPaloAltoType: {
+        desc: 'The type of device that is being added',
+        externalLink: ''
+    },
+    helpPaloAltoPublicInterface: {
+        desc: 'Interface of device that is configured to be part of the public network. For example, ge-0/0/2',
+        externalLink: ''
+    },
+    helpPaloAltoPrivateInterface: {
+        desc: 'Interface of device that is configured to be part of the private network. For example, ge-0/0/1',
+        externalLink: ''
+    },
+    helpPaloAltoUsageInterface: {
+        desc: 'Interface used to meter traffic. If you don\'t want to use the public interface, specify a different interface name here.',
+        externalLink: ''
+    },
+    helpPaloAltoRetries: {
+        desc: 'Number of times to attempt a command on the device before considering the operation failed. Default is 2.',
+        externalLink: ''
+    },
+    helpPaloAltoTimeout: {
+        desc: 'The time to wait for a command on the Palo Alto before considering it failed. Default is 300 seconds.',
+        externalLink: ''
+    },
+    helpPaloAltoMode: {
+        desc: 'Side by side mode is supported for the Palo Alto.',
+        externalLink: ''
+    },
+    helpPaloAltoPublicNetwork: {
+        desc: 'The name of the public network on the Palo Alto. For example, trust.',
+        externalLink: ''
+    },
+    helpPaloAltoPrivateNetwork: {
+        desc: 'The name of the private network on the Palo Alto. For example, untrust.',
+        externalLink: ''
+    },
+    helpPaloAltoVirtualRouter: {
+        desc: 'The name of the virtual router on the Palo Alto.',
+        externalLink: ''
+    },
+    helpPaloAltoThreatProfile: {
+        desc: 'The threat profile name/group to associate with allow firewall policies.',
+        externalLink: ''
+    },
+    helpPaloAltoLogProfile: {
+        desc: 'The log profile name/group to associate with allow firewall policies.',
+        externalLink: ''
+    },
+    helpPaloAltoDedicated: {
+        desc: 'Check this box to dedicate the device to a single account. The value in the Capacity field will be ignored.',
+        externalLink: ''
+    },
+    helpPaloAltoCapacity: {
+        desc: 'Number of guest networks/accounts that will share this device',
+        externalLink: ''
+    },
     // Add system service offering
     helpSystemOfferingName: {
         desc: 'Any desired name for the offering',