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:40 UTC

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

Updated Branches:
  refs/heads/master 40a783932 -> 8f8ad3f38


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/ui/scripts/system.js
----------------------------------------------------------------------
diff --git a/ui/scripts/system.js b/ui/scripts/system.js
index 1579d16..fa22811 100644
--- a/ui/scripts/system.js
+++ b/ui/scripts/system.js
@@ -4944,6 +4944,288 @@
                         }
                     },
 
+                    // Palo Alto provider detailView
+                    pa: {
+                        type: 'detailView',
+                        id: 'paProvider',
+                        label: 'label.PA',
+                        viewAll: {
+                            label: 'label.devices',
+                            path: '_zone.paDevices'
+                        },
+                        tabs: {
+                            details: {
+                                title: 'label.details',
+                                fields: [{
+                                    name: {
+                                        label: 'label.name'
+                                    }
+                                }, {
+                                    state: {
+                                        label: 'label.state'
+                                    }
+                                }],
+                                dataProvider: function (args) {
+                                    refreshNspData("PaloAlto");
+                                    var providerObj;
+                                    $(nspHardcodingArray).each(function () {
+                                        if (this.id == "pa") {
+                                            providerObj = this;
+                                            return false; //break each loop
+                                        }
+                                    });
+                                    args.response.success({
+                                        data: providerObj,
+                                        actionFilter: networkProviderActionFilter('pa')
+                                    });
+                                }
+                            }
+                        },
+                        actions: {
+                            add: {
+                                label: 'label.add.PA.device',
+                                createForm: {
+                                    title: 'label.add.PA.device',
+                                    fields: {
+                                        ip: {
+                                            label: 'label.ip.address',
+                                            docID: 'helpPaloAltoIPAddress'
+                                        },
+                                        username: {
+                                            label: 'label.username',
+                                            docID: 'helpPaloAltoUsername'
+                                        },
+                                        password: {
+                                            label: 'label.password',
+                                            isPassword: true,
+                                            docID: 'helpPaloAltoPassword'
+                                        },
+                                        networkdevicetype: {
+                                            label: 'label.type',
+                                            docID: 'helpPaloAltoType',
+                                            select: function (args) {
+                                                var items = [];
+                                                items.push({
+                                                    id: "PaloAltoFirewall",
+                                                    description: "Palo Alto Firewall"
+                                                });
+                                                args.response.success({
+                                                    data: items
+                                                });
+                                            }
+                                        },
+                                        publicinterface: {
+                                            label: 'label.public.interface',
+                                            docID: 'helpPaloAltoPublicInterface'
+                                        },
+                                        privateinterface: {
+                                            label: 'label.private.interface',
+                                            docID: 'helpPaloAltoPrivateInterface'
+                                        },
+                                        //usageinterface: {
+                                        //  label: 'Usage interface',
+                                        //  docID: 'helpPaloAltoUsageInterface'
+                                        //},
+                                        numretries: {
+                                            label: 'label.numretries',
+                                            defaultValue: '2',
+                                            docID: 'helpPaloAltoRetries'
+                                        },
+                                        timeout: {
+                                            label: 'label.timeout',
+                                            defaultValue: '300',
+                                            docID: 'helpPaloAltoTimeout'
+                                        },
+                                        // inline: {
+                                        //   label: 'Mode',
+                                        //   docID: 'helpPaloAltoMode',
+                                        //   select: function(args) {
+                                        //     var items = [];
+                                        //     items.push({id: "false", description: "side by side"});
+                                        //     items.push({id: "true", description: "inline"});
+                                        //     args.response.success({data: items});
+                                        //   }
+                                        // },
+                                        publicnetwork: {
+                                            label: 'label.public.network',
+                                            defaultValue: 'untrust',
+                                            docID: 'helpPaloAltoPublicNetwork'
+                                        },
+                                        privatenetwork: {
+                                            label: 'label.private.network',
+                                            defaultValue: 'trust',
+                                            docID: 'helpPaloAltoPrivateNetwork'
+                                        },
+                                        pavr: {
+                                            label: 'label.virtual.router',
+                                            docID: 'helpPaloAltoVirtualRouter'
+                                        },
+                                        patp: {
+                                            label: 'label.PA.threat.profile',
+                                            docID: 'helpPaloAltoThreatProfile'
+                                        },
+                                        palp: {
+                                            label: 'label.PA.log.profile',
+                                            docID: 'helpPaloAltoLogProfile'
+                                        },
+                                        capacity: {
+                                            label: 'label.capacity',
+                                            validation: {
+                                                required: false,
+                                                number: true
+                                            },
+                                            docID: 'helpPaloAltoCapacity'
+                                        },
+                                        dedicated: {
+                                            label: 'label.dedicated',
+                                            isBoolean: true,
+                                            isChecked: false,
+                                            docID: 'helpPaloAltoDedicated'
+                                        }
+                                    }
+                                },
+                                action: function (args) {
+                                    if (nspMap["pa"] == null) {
+                                        $.ajax({
+                                            url: createURL("addNetworkServiceProvider&name=PaloAlto&physicalnetworkid=" + selectedPhysicalNetworkObj.id),
+                                            dataType: "json",
+                                            async: true,
+                                            success: function (json) {
+                                                var jobId = json.addnetworkserviceproviderresponse.jobid;
+                                                var addPaloAltoProviderIntervalID = setInterval(function () {
+                                                    $.ajax({
+                                                        url: createURL("queryAsyncJobResult&jobId=" + jobId),
+                                                        dataType: "json",
+                                                        success: function (json) {
+                                                            var result = json.queryasyncjobresultresponse;
+                                                            if (result.jobstatus == 0) {
+                                                                return; //Job has not completed
+                                                            } else {
+                                                                clearInterval(addPaloAltoProviderIntervalID);
+                                                                if (result.jobstatus == 1) {
+                                                                    nspMap["pa"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider;
+                                                                    addExternalFirewall(args, selectedPhysicalNetworkObj, "addPaloAltoFirewall", "addpaloaltofirewallresponse", "pafirewall");
+                                                                } else if (result.jobstatus == 2) {
+                                                                    alert("addNetworkServiceProvider&name=Palo Alto failed. Error: " + _s(result.jobresult.errortext));
+                                                                }
+                                                            }
+                                                        },
+                                                        error: function (XMLHttpResponse) {
+                                                            var errorMsg = parseXMLHttpResponse(XMLHttpResponse);
+                                                            alert("addNetworkServiceProvider&name=Palo Alto failed. Error: " + errorMsg);
+                                                        }
+                                                    });
+                                                }, 3000);
+                                            }
+                                        });
+                                    } else {
+                                        addExternalFirewall(args, selectedPhysicalNetworkObj, "addPaloAltoFirewall", "addpaloaltofirewallresponse", "pafirewall");
+                                    }
+                                },
+                                messages: {
+                                    notification: function (args) {
+                                        return 'label.add.PA.device';
+                                    }
+                                },
+                                notification: {
+                                    poll: pollAsyncJobResult
+                                }
+                            },
+                            enable: {
+                                label: 'label.enable.provider',
+                                action: function (args) {
+                                    $.ajax({
+                                        url: createURL("updateNetworkServiceProvider&id=" + nspMap["pa"].id + "&state=Enabled"),
+                                        dataType: "json",
+                                        success: function (json) {
+                                            var jid = json.updatenetworkserviceproviderresponse.jobid;
+                                            args.response.success({
+                                                _custom: {
+                                                    jobId: jid,
+                                                    getUpdatedItem: function (json) {
+                                                        $(window).trigger('cloudStack.fullRefresh');
+                                                    }
+                                                }
+                                            });
+                                        }
+                                    });
+                                },
+                                messages: {
+                                    confirm: function (args) {
+                                        return 'message.confirm.enable.provider';
+                                    },
+                                    notification: function () {
+                                        return 'label.enable.provider';
+                                    }
+                                },
+                                notification: {
+                                    poll: pollAsyncJobResult
+                                }
+                            },
+                            disable: {
+                                label: 'label.disable.provider',
+                                action: function (args) {
+                                    $.ajax({
+                                        url: createURL("updateNetworkServiceProvider&id=" + nspMap["pa"].id + "&state=Disabled"),
+                                        dataType: "json",
+                                        success: function (json) {
+                                            var jid = json.updatenetworkserviceproviderresponse.jobid;
+                                            args.response.success({
+                                                _custom: {
+                                                    jobId: jid,
+                                                    getUpdatedItem: function (json) {
+                                                        $(window).trigger('cloudStack.fullRefresh');
+                                                    }
+                                                }
+                                            });
+                                        }
+                                    });
+                                },
+                                messages: {
+                                    confirm: function (args) {
+                                        return 'message.confirm.disable.provider';
+                                    },
+                                    notification: function () {
+                                        return 'label.disable.provider';
+                                    }
+                                },
+                                notification: {
+                                    poll: pollAsyncJobResult
+                                }
+                            },
+                            destroy: {
+                                label: 'label.shutdown.provider',
+                                action: function (args) {
+                                    $.ajax({
+                                        url: createURL("deleteNetworkServiceProvider&id=" + nspMap["pa"].id),
+                                        dataType: "json",
+                                        success: function (json) {
+                                            var jid = json.deletenetworkserviceproviderresponse.jobid;
+                                            args.response.success({
+                                                _custom: {
+                                                    jobId: jid
+                                                }
+                                            });
+
+                                            $(window).trigger('cloudStack.fullRefresh');
+                                        }
+                                    });
+                                },
+                                messages: {
+                                    confirm: function (args) {
+                                        return 'message.confirm.shutdown.provider';
+                                    },
+                                    notification: function (args) {
+                                        return 'label.shutdown.provider';
+                                    }
+                                },
+                                notification: {
+                                    poll: pollAsyncJobResult
+                                }
+                            }
+                        }
+                    },
+
                     // Security groups detail view
                     securityGroups: {
                         id: 'securityGroup-providers',
@@ -9156,6 +9438,250 @@
                     }
                 }
             },
+
+            //Palo Alto devices listView
+            paDevices: {
+                id: 'paDevices',
+                title: 'label.devices',
+                listView: {
+                    id: 'paDevices',
+                    fields: {
+                        ipaddress: {
+                            label: 'label.ip.address'
+                        },
+                        fwdevicestate: {
+                            label: 'label.status'
+                        },
+                        fwdevicename: {
+                            label: 'label.type'
+                        }
+                    },
+                    actions: {
+                        add: {
+                            label: 'label.add.PA.device',
+                            createForm: {
+                                title: 'label.add.PA.device',
+                                fields: {
+                                    ip: {
+                                        label: 'label.ip.address'
+                                    },
+                                    username: {
+                                        label: 'label.username'
+                                    },
+                                    password: {
+                                        label: 'label.password',
+                                        isPassword: true
+                                    },
+                                    networkdevicetype: {
+                                        label: 'label.type',
+                                        select: function (args) {
+                                            var items = [];
+                                            items.push({
+                                                id: "PaloAltoFirewall",
+                                                description: "Palo Alto Firewall"
+                                            });
+                                            args.response.success({
+                                                data: items
+                                            });
+                                        }
+                                    },
+                                    publicinterface: {
+                                        label: 'label.public.interface'
+                                    },
+                                    privateinterface: {
+                                        label: 'label.private.interface'
+                                    },
+                                    //usageinterface: {
+                                    //  label: 'label.usage.interface'
+                                    //},
+                                    numretries: {
+                                        label: 'label.numretries',
+                                        defaultValue: '2'
+                                    },
+                                    timeout: {
+                                        label: 'label.timeout',
+                                        defaultValue: '300'
+                                    },
+                                    // inline: {
+                                    //   label: 'Mode',
+                                    //   select: function(args) {
+                                    //     var items = [];
+                                    //     items.push({id: "false", description: "side by side"});
+                                    //     items.push({id: "true", description: "inline"});
+                                    //     args.response.success({data: items});
+                                    //   }
+                                    // },
+                                    publicnetwork: {
+                                        label: 'label.public.network',
+                                        defaultValue: 'untrust'
+                                    },
+                                    privatenetwork: {
+                                        label: 'label.private.network',
+                                        defaultValue: 'trust'
+                                    },
+                                    pavr: {
+                                        label: 'label.virtual.router'
+                                    },
+                                    patp: {
+                                        label: 'label.PA.threat.profile'
+                                    },
+                                    palp: {
+                                        label: 'label.PA.log.profile'
+                                    },
+                                    capacity: {
+                                        label: 'label.capacity',
+                                        validation: {
+                                            required: false,
+                                            number: true
+                                        }
+                                    },
+                                    dedicated: {
+                                        label: 'label.dedicated',
+                                        isBoolean: true,
+                                        isChecked: false
+                                    }
+                                }
+                            },
+                            action: function (args) {
+                                if (nspMap["pa"] == null) {
+                                    $.ajax({
+                                        url: createURL("addNetworkServiceProvider&name=PaloAlto&physicalnetworkid=" + selectedPhysicalNetworkObj.id),
+                                        dataType: "json",
+                                        async: true,
+                                        success: function (json) {
+                                            var jobId = json.addnetworkserviceproviderresponse.jobid;
+                                            var addPaloAltoProviderIntervalID = setInterval(function () {
+                                                $.ajax({
+                                                    url: createURL("queryAsyncJobResult&jobId=" + jobId),
+                                                    dataType: "json",
+                                                    success: function (json) {
+                                                        var result = json.queryasyncjobresultresponse;
+                                                        if (result.jobstatus == 0) {
+                                                            return; //Job has not completed
+                                                        } else {
+                                                            clearInterval(addPaloAltoProviderIntervalID);
+                                                            if (result.jobstatus == 1) {
+                                                                nspMap["pa"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider;
+                                                                addExternalFirewall(args, selectedPhysicalNetworkObj, "addPaloAltoFirewall", "addpaloaltofirewallresponse", "pafirewall");
+                                                            } else if (result.jobstatus == 2) {
+                                                                alert("addNetworkServiceProvider&name=Palo Alto failed. Error: " + _s(result.jobresult.errortext));
+                                                            }
+                                                        }
+                                                    },
+                                                    error: function (XMLHttpResponse) {
+                                                        var errorMsg = parseXMLHttpResponse(XMLHttpResponse);
+                                                        alert("addNetworkServiceProvider&name=Palo Alto failed. Error: " + errorMsg);
+                                                    }
+                                                });
+                                            }, 3000);
+                                        }
+                                    });
+                                } else {
+                                    addExternalFirewall(args, selectedPhysicalNetworkObj, "addPaloAltoFirewall", "addpaloaltofirewallresponse", "pafirewall");
+                                }
+                            },
+                            messages: {
+                                notification: function (args) {
+                                    return 'label.add.PA.device';
+                                }
+                            },
+                            notification: {
+                                poll: pollAsyncJobResult
+                            }
+                        }
+                    },
+                    dataProvider: function (args) {
+                        $.ajax({
+                            url: createURL("listPaloAltoFirewalls&physicalnetworkid=" + selectedPhysicalNetworkObj.id),
+                            data: {
+                                page: args.page,
+                                pageSize: pageSize
+                            },
+                            dataType: "json",
+                            async: false,
+                            success: function (json) {
+                                var items = json.listpaloaltofirewallresponse.paloaltofirewall;
+                                args.response.success({
+                                    data: items
+                                });
+                            }
+                        });
+                    },
+                    detailView: {
+                        name: 'Palo Alto details',
+                        actions: {
+                            'remove': {
+                                label: 'label.delete.PA',
+                                messages: {
+                                    confirm: function (args) {
+                                        return 'message.confirm.delete.PA';
+                                    },
+                                    notification: function (args) {
+                                        return 'label.delete.PA';
+                                    }
+                                },
+                                action: function (args) {
+                                    $.ajax({
+                                        url: createURL("deletePaloAltoFirewall&fwdeviceid=" + args.context.paDevices[0].fwdeviceid),
+                                        dataType: "json",
+                                        async: true,
+                                        success: function (json) {
+                                            var jid = json.deletepaloaltofirewallresponse.jobid;
+                                            args.response.success({
+                                                _custom: {
+                                                    jobId: jid
+                                                }
+                                            });
+                                        }
+                                    });
+                                },
+                                notification: {
+                                    poll: pollAsyncJobResult
+                                }
+                            }
+                        },
+                        tabs: {
+                            details: {
+                                title: 'label.details',
+                                fields: [{
+                                    fwdeviceid: {
+                                        label: 'label.id'
+                                    },
+                                    ipaddress: {
+                                        label: 'label.ip.address'
+                                    },
+                                    fwdevicestate: {
+                                        label: 'label.status'
+                                    },
+                                    fwdevicename: {
+                                        label: 'label.type'
+                                    },
+                                    fwdevicecapacity: {
+                                        label: 'label.capacity'
+                                    },
+                                    timeout: {
+                                        label: 'label.timeout'
+                                    }
+                                }],
+                                dataProvider: function (args) {
+                                    $.ajax({
+                                        url: createURL("listPaloAltoFirewalls&fwdeviceid=" + args.context.paDevices[0].fwdeviceid),
+                                        dataType: "json",
+                                        async: true,
+                                        success: function (json) {
+                                            var item = json.listpaloaltofirewallresponse.paloaltofirewall[0];
+                                            args.response.success({
+                                                data: item
+                                            });
+                                        }
+                                    });
+                                }
+                            }
+                        }
+                    }
+                }
+            },
+
             // FIXME convert to nicira detailview
             // NiciraNvp devices listView
             niciraNvpDevices: {
@@ -15763,6 +16289,44 @@
         }
         url.push("fwdevicededicated=" + dedicated.toString());
 
+        // START - Palo Alto Specific Fields
+        var externalVirtualRouter = args.data.pavr;
+        if(externalVirtualRouter != null && externalVirtualRouter.length > 0) {
+            if(isQuestionMarkAdded == false) {
+                url.push("?");
+                isQuestionMarkAdded = true;
+            }
+            else {
+                url.push("&");
+            }
+            url.push("pavr=" + encodeURIComponent(externalVirtualRouter));
+        }
+
+        var externalThreatProfile = args.data.patp;
+        if(externalThreatProfile != null && externalThreatProfile.length > 0) {
+            if(isQuestionMarkAdded == false) {
+                url.push("?");
+                isQuestionMarkAdded = true;
+            }
+            else {
+                url.push("&");
+            }
+            url.push("patp=" + encodeURIComponent(externalThreatProfile));
+        }
+
+        var externalLogProfile = args.data.palp;
+        if(externalLogProfile != null && externalLogProfile.length > 0) {
+            if(isQuestionMarkAdded == false) {
+                url.push("?");
+                isQuestionMarkAdded = true;
+            }
+            else {
+                url.push("&");
+            }
+            url.push("palp=" + encodeURIComponent(externalLogProfile));
+        }
+        // END - Palo Alto Specific Fields
+
         array1.push("&url=" + todb(url.join("")));
         //construct URL ends here
 
@@ -16495,6 +17059,9 @@
                             case "JuniperSRX":
                                 nspMap["srx"] = items[i];
                                 break;
+                            case "PaloAlto":
+                                nspMap["pa"] = items[i];
+                                break;
                             case "SecurityGroupProvider":
                                 nspMap["securityGroups"] = items[i];
                                 break;
@@ -16576,6 +17143,11 @@
                 name: 'SRX',
                 state: nspMap.srx ? nspMap.srx.state : 'Disabled'
             });
+            nspHardcodingArray.push({
+                id: 'pa',
+                name: 'Palo Alto',
+                state: nspMap.pa ? nspMap.pa.state : 'Disabled'
+            });
         }
     };
 


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

Posted by ya...@apache.org.
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',


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

Posted by ya...@apache.org.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoExternalFirewallElement.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoExternalFirewallElement.java b/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoExternalFirewallElement.java
new file mode 100644
index 0000000..3eb802e
--- /dev/null
+++ b/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoExternalFirewallElement.java
@@ -0,0 +1,538 @@
+// 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.element;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.ejb.Local;
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.response.ExternalFirewallResponse;
+import org.apache.cloudstack.network.ExternalNetworkDeviceManager.NetworkDevice;
+import org.apache.log4j.Logger;
+
+import com.cloud.api.ApiDBUtils;
+import com.cloud.api.commands.AddExternalFirewallCmd;
+import com.cloud.api.commands.AddPaloAltoFirewallCmd;
+import com.cloud.api.commands.ConfigurePaloAltoFirewallCmd;
+import com.cloud.api.commands.DeleteExternalFirewallCmd;
+import com.cloud.api.commands.DeletePaloAltoFirewallCmd;
+import com.cloud.api.commands.ListExternalFirewallsCmd;
+import com.cloud.api.commands.ListPaloAltoFirewallNetworksCmd;
+import com.cloud.api.commands.ListPaloAltoFirewallsCmd;
+import com.cloud.api.response.PaloAltoFirewallResponse;
+import com.cloud.configuration.Config;
+import com.cloud.configuration.ConfigurationManager;
+import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.DataCenter.NetworkType;
+import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InsufficientNetworkCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.host.dao.HostDetailsDao;
+import com.cloud.network.ExternalFirewallDeviceManagerImpl;
+import com.cloud.network.Network;
+import com.cloud.network.Network.Capability;
+import com.cloud.network.Network.Provider;
+import com.cloud.network.Network.Service;
+import com.cloud.network.NetworkModel;
+import com.cloud.network.PhysicalNetwork;
+import com.cloud.network.PhysicalNetworkServiceProvider;
+import com.cloud.network.PublicIpAddress;
+import com.cloud.network.dao.ExternalFirewallDeviceDao;
+import com.cloud.network.dao.ExternalFirewallDeviceVO;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkExternalFirewallDao;
+import com.cloud.network.dao.NetworkExternalFirewallVO;
+import com.cloud.network.dao.NetworkServiceMapDao;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.dao.PhysicalNetworkDao;
+import com.cloud.network.dao.PhysicalNetworkVO;
+import com.cloud.network.dao.ExternalFirewallDeviceVO.FirewallDeviceState;
+import com.cloud.network.resource.PaloAltoResource;
+import com.cloud.network.rules.FirewallRule;
+import com.cloud.network.rules.PortForwardingRule;
+import com.cloud.network.rules.StaticNat;
+import com.cloud.offering.NetworkOffering;
+import com.cloud.offerings.dao.NetworkOfferingDao;
+import com.cloud.utils.NumbersUtil;
+import com.cloud.utils.db.EntityManager;
+import com.cloud.utils.exception.CloudRuntimeException;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.ReservationContext;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineProfile;
+
+@Local(value = {NetworkElement.class, FirewallServiceProvider.class, 
+        PortForwardingServiceProvider.class, IpDeployer.class, 
+        SourceNatServiceProvider.class})
+public class PaloAltoExternalFirewallElement extends ExternalFirewallDeviceManagerImpl implements SourceNatServiceProvider, FirewallServiceProvider,
+PortForwardingServiceProvider, IpDeployer, PaloAltoFirewallElementService, StaticNatServiceProvider {
+
+    private static final Logger s_logger = Logger.getLogger(PaloAltoExternalFirewallElement.class);
+
+    private static final Map<Service, Map<Capability, String>> capabilities = setCapabilities();
+
+    @Inject
+    NetworkModel _networkManager;
+    @Inject
+    HostDao _hostDao;
+    @Inject
+    ConfigurationManager _configMgr;
+    @Inject
+    NetworkOfferingDao _networkOfferingDao;
+    @Inject
+    NetworkDao _networksDao;
+    @Inject
+    DataCenterDao _dcDao;
+    @Inject
+    PhysicalNetworkDao _physicalNetworkDao;
+    @Inject
+    ExternalFirewallDeviceDao _fwDevicesDao;
+    @Inject
+    NetworkExternalFirewallDao _networkFirewallDao;
+    @Inject
+    NetworkDao _networkDao;
+    @Inject
+    NetworkServiceMapDao _ntwkSrvcDao;
+    @Inject
+    HostDetailsDao _hostDetailDao;
+    @Inject
+    ConfigurationDao _configDao;
+    @Inject
+    EntityManager _entityMgr;
+
+    private boolean canHandle(Network network, Service service) {
+        DataCenter zone = _entityMgr.findById(DataCenter.class, network.getDataCenterId());
+        if (zone.getNetworkType() == NetworkType.Advanced && network.getGuestType() != Network.GuestType.Isolated) {
+            s_logger.trace("Element " + getProvider().getName() + "is not handling network type = " + network.getGuestType());
+            return false;
+        }
+
+        if (service == null) {
+            if (!_networkManager.isProviderForNetwork(getProvider(), network.getId())) {
+                s_logger.trace("Element " + getProvider().getName() + " is not a provider for the network " + network);
+                return false;
+            }
+        } else {
+            if (!_networkManager.isProviderSupportServiceInNetwork(network.getId(), service, getProvider())) {
+                s_logger.trace("Element " + getProvider().getName() + " doesn't support service " + service.getName() + " in the network " + network);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    @Override
+    public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ResourceUnavailableException, ConcurrentOperationException,
+    InsufficientNetworkCapacityException {
+        DataCenter zone = _entityMgr.findById(DataCenter.class, network.getDataCenterId());
+
+        // don't have to implement network is Basic zone
+        if (zone.getNetworkType() == NetworkType.Basic) {
+            s_logger.debug("Not handling network implement in zone of type " + NetworkType.Basic);
+            return false;
+        }
+
+        if (!canHandle(network, null)) {
+            return false;
+        }
+
+        try {
+            return manageGuestNetworkWithExternalFirewall(true, network);
+        } catch (InsufficientCapacityException capacityException) {
+            // TODO: handle out of capacity exception in more gracefule manner when multiple providers are present for
+            // the network
+            s_logger.error("Fail to implement the Palo Alto for network " + network, capacityException);
+            return false;
+        }
+    }
+
+    @Override
+    public boolean prepare(Network config, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException,
+    InsufficientNetworkCapacityException, ResourceUnavailableException {
+        return true;
+    }
+
+    @Override
+    public boolean release(Network config, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) {
+        return true;
+    }
+
+    @Override
+    public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ResourceUnavailableException, ConcurrentOperationException {
+        DataCenter zone = _entityMgr.findById(DataCenter.class, network.getDataCenterId());
+
+        // don't have to implement network is Basic zone
+        if (zone.getNetworkType() == NetworkType.Basic) {
+            s_logger.debug("Not handling network shutdown in zone of type " + NetworkType.Basic);
+            return false;
+        }
+
+        if (!canHandle(network, null)) {
+            return false;
+        }
+        try {
+            return manageGuestNetworkWithExternalFirewall(false, network);
+        } catch (InsufficientCapacityException capacityException) {
+            // TODO: handle out of capacity exception
+            return false;
+        }
+    }
+
+    @Override
+    public boolean destroy(Network config, ReservationContext context) {
+        return true;
+    }
+
+    @Override
+    public boolean applyFWRules(Network config, List<? extends FirewallRule> rules) throws ResourceUnavailableException {
+        if (!canHandle(config, Service.Firewall)) {
+            return false;
+        }
+
+        return applyFirewallRules(config, rules);
+    }
+
+    @Override
+    public Provider getProvider() {
+        return Provider.PaloAlto;
+    }
+
+    @Override
+    public Map<Service, Map<Capability, String>> getCapabilities() {
+        return capabilities;
+    }
+
+    private static Map<Service, Map<Capability, String>> setCapabilities() {
+        Map<Service, Map<Capability, String>> capabilities = new HashMap<Service, Map<Capability, String>>();
+
+        // Set capabilities for Firewall service
+        Map<Capability, String> firewallCapabilities = new HashMap<Capability, String>();
+        firewallCapabilities.put(Capability.SupportedProtocols, "tcp,udp,icmp");
+        firewallCapabilities.put(Capability.SupportedEgressProtocols, "tcp,udp,icmp,all");
+        firewallCapabilities.put(Capability.MultipleIps, "true");
+        firewallCapabilities.put(Capability.TrafficStatistics, "per public ip");
+        firewallCapabilities.put(Capability.SupportedTrafficDirection, "ingress, egress");
+        capabilities.put(Service.Firewall, firewallCapabilities);
+
+        capabilities.put(Service.Gateway, null);
+
+        Map<Capability, String> sourceNatCapabilities = new HashMap<Capability, String>();
+        // Specifies that this element supports either one source NAT rule per account;
+        sourceNatCapabilities.put(Capability.SupportedSourceNatTypes, "peraccount");
+        capabilities.put(Service.SourceNat, sourceNatCapabilities);
+
+        // Specifies that port forwarding rules are supported by this element
+        capabilities.put(Service.PortForwarding, null);
+
+        // Specifies that static NAT rules are supported by this element
+        capabilities.put(Service.StaticNat, null);
+
+        return capabilities;
+    }
+
+    @Override
+    public boolean applyPFRules(Network network, List<PortForwardingRule> rules) throws ResourceUnavailableException {
+        if (!canHandle(network, Service.PortForwarding)) {
+            return false;
+        }
+
+        return applyPortForwardingRules(network, rules);
+    }
+
+    @Override
+    public boolean isReady(PhysicalNetworkServiceProvider provider) {
+
+        List<ExternalFirewallDeviceVO> fwDevices = _fwDevicesDao.listByPhysicalNetworkAndProvider(provider.getPhysicalNetworkId(), Provider.PaloAlto.getName());
+        // true if at-least one Palo Alto device is added in to physical network and is in configured (in enabled state) state
+        if (fwDevices != null && !fwDevices.isEmpty()) {
+            for (ExternalFirewallDeviceVO fwDevice : fwDevices) {
+                if (fwDevice.getDeviceState() == FirewallDeviceState.Enabled) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException,
+    ResourceUnavailableException {
+        // TODO Auto-generated method stub
+        return true;
+    }
+
+    @Override
+    public boolean canEnableIndividualServices() {
+        return true;
+    }
+
+    @Override
+    @Deprecated
+    // should use more generic addNetworkDevice command to add firewall
+    public Host addExternalFirewall(AddExternalFirewallCmd cmd) {
+        Long zoneId = cmd.getZoneId();
+        DataCenterVO zone = null;
+        PhysicalNetworkVO pNetwork = null;
+        HostVO fwHost = null;
+
+        zone = _dcDao.findById(zoneId);
+        if (zone == null) {
+            throw new InvalidParameterValueException("Could not find zone with ID: " + zoneId);
+        }
+
+        List<PhysicalNetworkVO> physicalNetworks = _physicalNetworkDao.listByZone(zoneId);
+        if ((physicalNetworks == null) || (physicalNetworks.size() > 1)) {
+            throw new InvalidParameterValueException("There are no physical networks or multiple physical networks configured in zone with ID: "
+                    + zoneId + " to add this device.");
+        }
+        pNetwork = physicalNetworks.get(0);
+
+        String deviceType = NetworkDevice.PaloAltoFirewall.getName();
+        ExternalFirewallDeviceVO fwDeviceVO = addExternalFirewall(pNetwork.getId(), cmd.getUrl(), cmd.getUsername(), cmd.getPassword(), deviceType, new PaloAltoResource());
+        if (fwDeviceVO != null) {
+            fwHost = _hostDao.findById(fwDeviceVO.getHostId());
+        }
+
+        return fwHost;
+    }
+
+    @Override
+    public boolean deleteExternalFirewall(DeleteExternalFirewallCmd cmd) {
+        return deleteExternalFirewall(cmd.getId());
+    }
+
+    @Override
+    @Deprecated
+    // should use more generic listNetworkDevice command
+    public List<Host> listExternalFirewalls(ListExternalFirewallsCmd cmd) {
+        List<Host> firewallHosts = new ArrayList<Host>();
+        Long zoneId = cmd.getZoneId();
+        DataCenterVO zone = null;
+        PhysicalNetworkVO pNetwork = null;
+
+        if (zoneId != null) {
+            zone = _dcDao.findById(zoneId);
+            if (zone == null) {
+                throw new InvalidParameterValueException("Could not find zone with ID: " + zoneId);
+            }
+
+            List<PhysicalNetworkVO> physicalNetworks = _physicalNetworkDao.listByZone(zoneId);
+            if ((physicalNetworks == null) || (physicalNetworks.size() > 1)) {
+                throw new InvalidParameterValueException("There are no physical networks or multiple physical networks configured in zone with ID: "
+                        + zoneId + " to add this device.");
+            }
+            pNetwork = physicalNetworks.get(0);
+        }
+
+        firewallHosts.addAll(listExternalFirewalls(pNetwork.getId(), NetworkDevice.PaloAltoFirewall.getName()));
+        return firewallHosts;
+    }
+
+    @Override
+    public ExternalFirewallResponse createExternalFirewallResponse(Host externalFirewall) {
+        return super.createExternalFirewallResponse(externalFirewall);
+    }
+
+    @Override
+    public List<Class<?>> getCommands() {
+        List<Class<?>> cmdList = new ArrayList<Class<?>>();
+        cmdList.add(AddExternalFirewallCmd.class);
+        cmdList.add(AddPaloAltoFirewallCmd.class);
+        cmdList.add(ConfigurePaloAltoFirewallCmd.class);
+        cmdList.add(DeleteExternalFirewallCmd.class);
+        cmdList.add(DeletePaloAltoFirewallCmd.class);
+        cmdList.add(ListExternalFirewallsCmd.class);
+        cmdList.add(ListPaloAltoFirewallNetworksCmd.class);
+        cmdList.add(ListPaloAltoFirewallsCmd.class);
+        return cmdList;
+    }
+
+    @Override
+    public ExternalFirewallDeviceVO addPaloAltoFirewall(AddPaloAltoFirewallCmd cmd) {
+        String deviceName = cmd.getDeviceType();
+        if (!deviceName.equalsIgnoreCase(NetworkDevice.PaloAltoFirewall.getName())) {
+            throw new InvalidParameterValueException("Invalid Palo Alto firewall device type");
+        }
+        return addExternalFirewall(cmd.getPhysicalNetworkId(), cmd.getUrl(), cmd.getUsername(), cmd.getPassword(), deviceName,
+            new PaloAltoResource());
+    }
+
+    @Override
+    public boolean deletePaloAltoFirewall(DeletePaloAltoFirewallCmd cmd) {
+        Long fwDeviceId = cmd.getFirewallDeviceId();
+
+        ExternalFirewallDeviceVO fwDeviceVO = _fwDevicesDao.findById(fwDeviceId);
+        if (fwDeviceVO == null || !fwDeviceVO.getDeviceName().equalsIgnoreCase(NetworkDevice.PaloAltoFirewall.getName())) {
+            throw new InvalidParameterValueException("No Palo Alto firewall device found with ID: " + fwDeviceId);
+        }
+        return deleteExternalFirewall(fwDeviceVO.getHostId());
+    }
+
+    @Override
+    public ExternalFirewallDeviceVO configurePaloAltoFirewall(ConfigurePaloAltoFirewallCmd cmd) {
+        Long fwDeviceId = cmd.getFirewallDeviceId();
+        Long deviceCapacity = cmd.getFirewallCapacity();
+
+        ExternalFirewallDeviceVO fwDeviceVO = _fwDevicesDao.findById(fwDeviceId);
+        if (fwDeviceVO == null || !fwDeviceVO.getDeviceName().equalsIgnoreCase(NetworkDevice.PaloAltoFirewall.getName())) {
+            throw new InvalidParameterValueException("No Palo Alto firewall device found with ID: " + fwDeviceId);
+        }
+
+        if (deviceCapacity != null) {
+            // check if any networks are using this Palo Alto device
+            List<NetworkExternalFirewallVO> networks = _networkFirewallDao.listByFirewallDeviceId(fwDeviceId);
+            if ((networks != null) && !networks.isEmpty()) {
+                if (deviceCapacity < networks.size()) {
+                    throw new CloudRuntimeException("There are more number of networks already using this Palo Alto firewall device than configured capacity");
+                }
+            }
+            if (deviceCapacity != null) {
+                fwDeviceVO.setCapacity(deviceCapacity);
+            }
+        }
+
+        fwDeviceVO.setDeviceState(FirewallDeviceState.Enabled);
+        _fwDevicesDao.update(fwDeviceId, fwDeviceVO);
+        return fwDeviceVO;
+    }
+
+    @Override
+    public List<ExternalFirewallDeviceVO> listPaloAltoFirewalls(ListPaloAltoFirewallsCmd cmd) {
+        Long physcialNetworkId = cmd.getPhysicalNetworkId();
+        Long fwDeviceId = cmd.getFirewallDeviceId();
+        PhysicalNetworkVO pNetwork = null;
+        List<ExternalFirewallDeviceVO> fwDevices = new ArrayList<ExternalFirewallDeviceVO>();
+
+        if (physcialNetworkId == null && fwDeviceId == null) {
+            throw new InvalidParameterValueException("Either physical network Id or load balancer device Id must be specified");
+        }
+
+        if (fwDeviceId != null) {
+            ExternalFirewallDeviceVO fwDeviceVo = _fwDevicesDao.findById(fwDeviceId);
+            if (fwDeviceVo == null || !fwDeviceVo.getDeviceName().equalsIgnoreCase(NetworkDevice.PaloAltoFirewall.getName())) {
+                throw new InvalidParameterValueException("Could not find Palo Alto firewall device with ID: " + fwDeviceId);
+            }
+            fwDevices.add(fwDeviceVo);
+        }
+
+        if (physcialNetworkId != null) {
+            pNetwork = _physicalNetworkDao.findById(physcialNetworkId);
+            if (pNetwork == null) {
+                throw new InvalidParameterValueException("Could not find phyical network with ID: " + physcialNetworkId);
+            }
+            fwDevices = _fwDevicesDao.listByPhysicalNetworkAndProvider(physcialNetworkId, Provider.PaloAlto.getName());
+        }
+
+        return fwDevices;
+    }
+
+    @Override
+    public List<? extends Network> listNetworks(ListPaloAltoFirewallNetworksCmd cmd) {
+        Long fwDeviceId = cmd.getFirewallDeviceId();
+        List<NetworkVO> networks = new ArrayList<NetworkVO>();
+
+        ExternalFirewallDeviceVO fwDeviceVo = _fwDevicesDao.findById(fwDeviceId);
+        if (fwDeviceVo == null || !fwDeviceVo.getDeviceName().equalsIgnoreCase(NetworkDevice.PaloAltoFirewall.getName())) {
+            throw new InvalidParameterValueException("Could not find Palo Alto firewall device with ID " + fwDeviceId);
+        }
+
+        List<NetworkExternalFirewallVO> networkFirewallMaps = _networkFirewallDao.listByFirewallDeviceId(fwDeviceId);
+        if (networkFirewallMaps != null && !networkFirewallMaps.isEmpty()) {
+            for (NetworkExternalFirewallVO networkFirewallMap : networkFirewallMaps) {
+                NetworkVO network = _networkDao.findById(networkFirewallMap.getNetworkId());
+                networks.add(network);
+            }
+        }
+
+        return networks;
+    }
+
+    @Override
+    public PaloAltoFirewallResponse createPaloAltoFirewallResponse(ExternalFirewallDeviceVO fwDeviceVO) {
+        PaloAltoFirewallResponse response = new PaloAltoFirewallResponse();
+        Map<String, String> fwDetails = _hostDetailDao.findDetails(fwDeviceVO.getHostId());
+        Host fwHost = _hostDao.findById(fwDeviceVO.getHostId());
+
+        response.setId(fwDeviceVO.getUuid());
+        PhysicalNetwork pnw = ApiDBUtils.findPhysicalNetworkById(fwDeviceVO.getPhysicalNetworkId());
+        if (pnw != null) {
+            response.setPhysicalNetworkId(pnw.getUuid());
+        }
+        response.setDeviceName(fwDeviceVO.getDeviceName());
+        if (fwDeviceVO.getCapacity() == 0) {
+            long defaultFwCapacity = NumbersUtil.parseLong(_configDao.getValue(Config.DefaultExternalFirewallCapacity.key()), 50);
+            response.setDeviceCapacity(defaultFwCapacity);
+        } else {
+            response.setDeviceCapacity(fwDeviceVO.getCapacity());
+        }
+        response.setProvider(fwDeviceVO.getProviderName());
+        response.setDeviceState(fwDeviceVO.getDeviceState().name());
+        response.setIpAddress(fwHost.getPrivateIpAddress());
+        response.setPublicInterface(fwDetails.get("publicInterface"));
+        response.setUsageInterface(fwDetails.get("usageInterface"));
+        response.setPrivateInterface(fwDetails.get("privateInterface"));
+        response.setPublicZone(fwDetails.get("publicZone"));
+        response.setPrivateZone(fwDetails.get("privateZone"));
+        response.setNumRetries(fwDetails.get("numRetries"));
+        response.setTimeout(fwDetails.get("timeout"));
+        response.setObjectName("paloaltofirewall");
+        return response;
+    }
+
+    @Override
+    public boolean verifyServicesCombination(Set<Service> services) {
+        if (!services.contains(Service.Firewall)) {
+            s_logger.warn("Palo Alto must be used as Firewall Service Provider in the network");
+            return false;
+        }
+        return true;
+    }
+
+    @Override
+    public IpDeployer getIpDeployer(Network network) {
+        return this;
+    }
+
+    @Override
+    public boolean applyIps(Network network, List<? extends PublicIpAddress> ipAddress, Set<Service> service) throws ResourceUnavailableException {
+        // return true, as IP will be associated as part of static NAT/port forwarding rule configuration
+        return true;
+    }
+
+    @Override
+    public boolean applyStaticNats(Network config, List<? extends StaticNat> rules) throws ResourceUnavailableException {
+        if (!canHandle(config, Service.StaticNat)) {
+            return false;
+        }
+        return applyStaticNatRules(config, rules);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoFirewallElementService.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoFirewallElementService.java b/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoFirewallElementService.java
new file mode 100644
index 0000000..d2842ab
--- /dev/null
+++ b/plugins/network-elements/palo-alto/src/com/cloud/network/element/PaloAltoFirewallElementService.java
@@ -0,0 +1,88 @@
+// 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.element;
+
+import java.util.List;
+
+import com.cloud.api.commands.AddExternalFirewallCmd;
+import com.cloud.api.commands.AddPaloAltoFirewallCmd;
+import com.cloud.api.commands.ConfigurePaloAltoFirewallCmd;
+import com.cloud.api.commands.DeleteExternalFirewallCmd;
+import com.cloud.api.commands.DeletePaloAltoFirewallCmd;
+import com.cloud.api.commands.ListExternalFirewallsCmd;
+import com.cloud.api.commands.ListPaloAltoFirewallNetworksCmd;
+import com.cloud.api.commands.ListPaloAltoFirewallsCmd;
+import com.cloud.api.response.PaloAltoFirewallResponse;
+import com.cloud.host.Host;
+import com.cloud.network.Network;
+import com.cloud.network.dao.ExternalFirewallDeviceVO;
+
+import org.apache.cloudstack.api.response.ExternalFirewallResponse;
+import com.cloud.utils.component.PluggableService;
+
+public interface PaloAltoFirewallElementService  extends PluggableService {
+
+    /**
+     * adds a Palo Alto firewall device in to a physical network
+     * @param AddPaloAltoFirewallCmd 
+     * @return ExternalFirewallDeviceVO object for the firewall added
+     */
+    public ExternalFirewallDeviceVO addPaloAltoFirewall(AddPaloAltoFirewallCmd cmd);
+
+    /**
+     * removes Palo Alto firewall device from a physical network
+     * @param DeletePaloAltoFirewallCmd 
+     * @return true if firewall device successfully deleted
+     */
+    public boolean deletePaloAltoFirewall(DeletePaloAltoFirewallCmd cmd);
+
+    /**
+     * configures a Palo Alto firewal device added in a physical network
+     * @param ConfigurePaloAltoFirewallCmd
+     * @return ExternalFirewallDeviceVO for the device configured
+     */
+    public ExternalFirewallDeviceVO configurePaloAltoFirewall(ConfigurePaloAltoFirewallCmd cmd);
+
+    /**
+     * lists all the Palo Alto firewall devices added in to a physical network
+     * @param ListPaloAltoFirewallsCmd
+     * @return list of ExternalFirewallDeviceVO for the devices in the physical network.
+     */
+    public List<ExternalFirewallDeviceVO> listPaloAltoFirewalls(ListPaloAltoFirewallsCmd cmd);
+
+    /**
+     * lists all the guest networks using a PaloAlto firewall device
+     * @param ListPaloAltoFirewallNetworksCmd
+     * @return list of the guest networks that are using this F5 load balancer
+     */
+    public List<? extends Network> listNetworks(ListPaloAltoFirewallNetworksCmd cmd);
+
+    public PaloAltoFirewallResponse createPaloAltoFirewallResponse(ExternalFirewallDeviceVO fwDeviceVO);
+
+
+    @Deprecated // API helper function supported for backward compatibility
+    public Host addExternalFirewall(AddExternalFirewallCmd cmd);
+
+    @Deprecated // API helper function supported for backward compatibility
+    public boolean deleteExternalFirewall(DeleteExternalFirewallCmd cmd);
+    
+    @Deprecated // API helper function supported for backward compatibility
+    public List<Host> listExternalFirewalls(ListExternalFirewallsCmd cmd);
+    
+    @Deprecated // API helper function supported for backward compatibility
+    public ExternalFirewallResponse createExternalFirewallResponse(Host externalFirewall);
+}


[5/5] git commit: updated refs/heads/master to 8f8ad3f

Posted by ya...@apache.org.
Squashed commit of the Palo Alto Networks firewall integration plugin.

This patch adds a network plugin to support Palo Alto Networks firewall (their appliance and their VM series firewall).

More information in the FS: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Palo+Alto+Firewall+Integration

Features supported are:
- List/Add/Delete Palo Alto service provider
- List/Add/Delete Palo Alto network service offering
- List/Add/Delete Palo Alto network with above service offering
- Add instance to the new network (creates the public IP and private gateway/cidr on the PA as well as the source nat rule)
- List/Add/Delete Ingress Firewall rule
- List/Add/Delete Egress Firewall rule
- List/Add/Delete Port Forwarding rule
- List/Add/Delete Static Nat rule
- Supports Palo Alto Networks 'Log Forwarding' profile globally per device (additional docs to come)
- Supports Palo Alto Networks 'Security Profile Groups' functionality globally per device (additional docs to come)

Knowns limitations:
- Only supports one public IP range in CloudStack.
- Currently not verifying SSL certificates when creating a connection between CloudStack and the Palo Alto Networks firewall.
- Currently not tracking usage on Public IPs.

Signed-off-by: Sheng Yang <sh...@citrix.com>


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

Branch: refs/heads/master
Commit: 8f8ad3f38ef3c9ee840ba5f86c92d722d2bb5393
Parents: 40a7839
Author: Will Stevens <ws...@cloudops.com>
Authored: Tue Nov 5 22:24:23 2013 -0500
Committer: Sheng Yang <sh...@citrix.com>
Committed: Wed Nov 6 10:08:22 2013 -0800

----------------------------------------------------------------------
 api/src/com/cloud/network/Network.java          |    1 +
 .../admin/network/AddNetworkDeviceCmd.java      |    3 +-
 .../admin/network/ListNetworkDeviceCmd.java     |    2 +-
 .../network/ExternalNetworkDeviceManager.java   |    1 +
 .../classes/resources/messages.properties       |    7 +
 client/pom.xml                                  |    5 +
 client/tomcatconf/commands.properties.in        |   11 +
 plugins/network-elements/palo-alto/pom.xml      |   29 +
 .../cloudstack/paloalto/module.properties       |   18 +
 .../paloalto/spring-paloalto-context.xml        |   33 +
 .../api/commands/AddExternalFirewallCmd.java    |  112 +
 .../api/commands/AddPaloAltoFirewallCmd.java    |  135 ++
 .../commands/ConfigurePaloAltoFirewallCmd.java  |  114 +
 .../api/commands/DeleteExternalFirewallCmd.java |   88 +
 .../api/commands/DeletePaloAltoFirewallCmd.java |  105 +
 .../api/commands/ListExternalFirewallsCmd.java  |   88 +
 .../ListPaloAltoFirewallNetworksCmd.java        |   95 +
 .../api/commands/ListPaloAltoFirewallsCmd.java  |  103 +
 .../api/response/PaloAltoFirewallResponse.java  |  142 ++
 .../PaloAltoExternalFirewallElement.java        |  538 +++++
 .../element/PaloAltoFirewallElementService.java |   88 +
 .../network/resource/PaloAltoResource.java      | 2030 ++++++++++++++++++
 .../cloud/network/utils/HttpClientWrapper.java  |   69 +
 .../resource/MockablePaloAltoResource.java      |  460 ++++
 .../network/resource/PaloAltoResourceTest.java  |  507 +++++
 plugins/pom.xml                                 |    1 +
 server/src/com/cloud/api/ApiResponseHelper.java |    2 +-
 .../configuration/ConfigurationManagerImpl.java |    4 +
 ui/dictionary.jsp                               |    7 +
 ui/scripts/docs.js                              |   69 +
 ui/scripts/system.js                            |  572 +++++
 31 files changed, 5436 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/api/src/com/cloud/network/Network.java
----------------------------------------------------------------------
diff --git a/api/src/com/cloud/network/Network.java b/api/src/com/cloud/network/Network.java
index bda3326..318ac19 100644
--- a/api/src/com/cloud/network/Network.java
+++ b/api/src/com/cloud/network/Network.java
@@ -116,6 +116,7 @@ public interface Network extends ControlledEntity, StateObject<Network.State>, I
         public static final Provider VirtualRouter = new Provider("VirtualRouter", false);
         public static final Provider JuniperContrail = new Provider("JuniperContrail", false);
         public static final Provider JuniperSRX = new Provider("JuniperSRX", true);
+        public static final Provider PaloAlto = new Provider("PaloAlto", true);
         public static final Provider F5BigIp = new Provider("F5BigIp", true);
         public static final Provider Netscaler = new Provider("Netscaler", true);
         public static final Provider ExternalDhcpServer = new Provider("ExternalDhcpServer", true);

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/api/src/org/apache/cloudstack/api/command/admin/network/AddNetworkDeviceCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/AddNetworkDeviceCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/AddNetworkDeviceCmd.java
index 4983255..a7906f4 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/network/AddNetworkDeviceCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/network/AddNetworkDeviceCmd.java
@@ -47,8 +47,9 @@ public class AddNetworkDeviceCmd extends BaseCmd {
     // ////////////// API parameters /////////////////////
     // ///////////////////////////////////////////////////
 
+
     @Inject ExternalNetworkDeviceManager nwDeviceMgr;
-    @Parameter(name = ApiConstants.NETWORK_DEVICE_TYPE, type = CommandType.STRING, description = "Network device type, now supports ExternalDhcp, PxeServer, NetscalerMPXLoadBalancer, NetscalerVPXLoadBalancer, NetscalerSDXLoadBalancer, F5BigIpLoadBalancer, JuniperSRXFirewall")
+    @Parameter(name = ApiConstants.NETWORK_DEVICE_TYPE, type = CommandType.STRING, description = "Network device type, now supports ExternalDhcp, PxeServer, NetscalerMPXLoadBalancer, NetscalerVPXLoadBalancer, NetscalerSDXLoadBalancer, F5BigIpLoadBalancer, JuniperSRXFirewall, PaloAltoFirewall")
     private String type;
 
     @Parameter(name = ApiConstants.NETWORK_DEVICE_PARAMETER_LIST, type = CommandType.MAP, description = "parameters for network device")

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/api/src/org/apache/cloudstack/api/command/admin/network/ListNetworkDeviceCmd.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/api/command/admin/network/ListNetworkDeviceCmd.java b/api/src/org/apache/cloudstack/api/command/admin/network/ListNetworkDeviceCmd.java
index 0b7836d..5278ba9 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/network/ListNetworkDeviceCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/network/ListNetworkDeviceCmd.java
@@ -51,7 +51,7 @@ public class ListNetworkDeviceCmd extends BaseListCmd {
     //////////////// API parameters /////////////////////
     /////////////////////////////////////////////////////
 
-    @Parameter(name = ApiConstants.NETWORK_DEVICE_TYPE, type = CommandType.STRING, description = "Network device type, now supports ExternalDhcp, PxeServer, NetscalerMPXLoadBalancer, NetscalerVPXLoadBalancer, NetscalerSDXLoadBalancer, F5BigIpLoadBalancer, JuniperSRXFirewall")
+    @Parameter(name = ApiConstants.NETWORK_DEVICE_TYPE, type = CommandType.STRING, description = "Network device type, now supports ExternalDhcp, PxeServer, NetscalerMPXLoadBalancer, NetscalerVPXLoadBalancer, NetscalerSDXLoadBalancer, F5BigIpLoadBalancer, JuniperSRXFirewall, PaloAltoFirewall")
     private String type;
 
     @Parameter(name = ApiConstants.NETWORK_DEVICE_PARAMETER_LIST, type = CommandType.MAP, description = "parameters for network device")

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java
----------------------------------------------------------------------
diff --git a/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java b/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java
index 29ce2e3..32f13f8 100644
--- a/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java
+++ b/api/src/org/apache/cloudstack/network/ExternalNetworkDeviceManager.java
@@ -42,6 +42,7 @@ public interface ExternalNetworkDeviceManager extends Manager {
         public static final NetworkDevice NetscalerSDXLoadBalancer = new NetworkDevice("NetscalerSDXLoadBalancer", Network.Provider.Netscaler.getName());
         public static final NetworkDevice F5BigIpLoadBalancer = new NetworkDevice("F5BigIpLoadBalancer", Network.Provider.F5BigIp.getName());
         public static final NetworkDevice JuniperSRXFirewall = new NetworkDevice("JuniperSRXFirewall", Network.Provider.JuniperSRX.getName());
+        public static final NetworkDevice PaloAltoFirewall = new NetworkDevice("PaloAltoFirewall", Network.Provider.PaloAlto.getName());
         public static final NetworkDevice NiciraNvp = new NetworkDevice("NiciraNvp", Network.Provider.NiciraNvp.getName());
         public static final NetworkDevice CiscoVnmc = new NetworkDevice("CiscoVnmc", Network.Provider.CiscoVnmc.getName());
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/client/WEB-INF/classes/resources/messages.properties
----------------------------------------------------------------------
diff --git a/client/WEB-INF/classes/resources/messages.properties b/client/WEB-INF/classes/resources/messages.properties
index d548527..e450c29 100644
--- a/client/WEB-INF/classes/resources/messages.properties
+++ b/client/WEB-INF/classes/resources/messages.properties
@@ -304,6 +304,7 @@ label.add.new.F5=Add new F5
 label.add.new.gateway=Add new gateway
 label.add.new.NetScaler=Add new NetScaler
 label.add.new.SRX=Add new SRX
+label.add.new.PA=Add new Palo Alto
 label.add.new.tier=Add new tier
 label.add.NiciraNvp.device=Add Nvp Controller
 label.add.physical.network=Add physical network
@@ -318,6 +319,7 @@ label.add.secondary.storage=Add Secondary Storage
 label.add.security.group=Add Security Group
 label.add.service.offering=Add Service Offering
 label.add.SRX.device=Add SRX device
+label.add.PA.device=Add Palo Alto device
 label.add.static.nat.rule=Add static NAT rule
 label.add.static.route=Add static route
 label.add.system.service.offering=Add System Service Offering
@@ -479,6 +481,7 @@ label.delete.NetScaler=Delete NetScaler
 label.delete.NiciraNvp=Remove Nvp Controller
 label.delete.project=Delete project
 label.delete.SRX=Delete SRX
+label.delete.PA=Delete Palo Alto
 label.delete.VPN.connection=delete VPN connection
 label.delete.VPN.customer.gateway=delete VPN Customer Gateway
 label.delete.VPN.gateway=delete VPN Gateway
@@ -876,6 +879,8 @@ label.os.type=OS Type
 label.owned.public.ips=Owned Public IP Addresses
 label.owner.account=Owner Account
 label.owner.domain=Owner Domain
+label.PA.log.profile=Palo Alto Log Profile
+label.PA.threat.profile=Palo Alto Threat Profile
 label.parent.domain=Parent Domain
 label.password.enabled=Password Enabled
 label.password=Password
@@ -1048,6 +1053,7 @@ label.specify.vlan=Specify VLAN
 label.specify.vxlan=Specify VXLAN
 label.SR.name = SR Name-Label
 label.srx=SRX
+label.PA=Palo Alto
 label.start.IP=Start IP
 label.start.port=Start Port
 label.start.reserved.system.IP=Start Reserved system IP
@@ -1366,6 +1372,7 @@ message.confirm.action.force.reconnect=Please confirm that you want to force rec
 message.confirm.delete.F5=Please confirm that you would like to delete F5
 message.confirm.delete.NetScaler=Please confirm that you would like to delete NetScaler
 message.confirm.delete.SRX=Please confirm that you would like to delete SRX
+message.confirm.delete.PA=Please confirm that you would like to delete Palo Alto
 message.confirm.destroy.router=Please confirm that you would like to destroy this router
 message.confirm.disable.provider=Please confirm that you would like to disable this provider
 message.confirm.enable.provider=Please confirm that you would like to enable this provider

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/client/pom.xml
----------------------------------------------------------------------
diff --git a/client/pom.xml b/client/pom.xml
index 54cb667..a15a409 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -92,6 +92,11 @@
     </dependency>
     <dependency>
       <groupId>org.apache.cloudstack</groupId>
+      <artifactId>cloud-plugin-network-palo-alto</artifactId>
+      <version>${project.version}</version>
+    </dependency>
+    <dependency>
+      <groupId>org.apache.cloudstack</groupId>
       <artifactId>cloud-plugin-network-ovs</artifactId>
       <version>${project.version}</version>
     </dependency>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/client/tomcatconf/commands.properties.in
----------------------------------------------------------------------
diff --git a/client/tomcatconf/commands.properties.in b/client/tomcatconf/commands.properties.in
index 8cbe972..087d8b9 100644
--- a/client/tomcatconf/commands.properties.in
+++ b/client/tomcatconf/commands.properties.in
@@ -533,6 +533,17 @@ configureSrxFirewall=1
 listSrxFirewalls=1
 listSrxFirewallNetworks=1
 
+#### Palo Alto firewall commands
+addExternalFirewall=1
+deleteExternalFirewall=1
+listExternalFirewalls=1
+
+addPaloAltoFirewall=1
+deletePaloAltoFirewall=1
+configurePaloAltoFirewall=1
+listPaloAltoFirewalls=1
+listPaloAltoFirewallNetworks=1
+
 ####Netapp integration commands
 createVolumeOnFiler=15
 destroyVolumeOnFiler=15

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/pom.xml
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/pom.xml b/plugins/network-elements/palo-alto/pom.xml
new file mode 100644
index 0000000..50b4c13
--- /dev/null
+++ b/plugins/network-elements/palo-alto/pom.xml
@@ -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.
+-->
+<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>
+  <artifactId>cloud-plugin-network-palo-alto</artifactId>
+  <name>Apache CloudStack Plugin - Palo Alto</name>
+  <parent>
+    <groupId>org.apache.cloudstack</groupId>
+    <artifactId>cloudstack-plugins</artifactId>
+    <version>4.3.0-SNAPSHOT</version>
+    <relativePath>../../pom.xml</relativePath>
+  </parent>
+</project>

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/resources/META-INF/cloudstack/paloalto/module.properties
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/resources/META-INF/cloudstack/paloalto/module.properties b/plugins/network-elements/palo-alto/resources/META-INF/cloudstack/paloalto/module.properties
new file mode 100644
index 0000000..960fdba
--- /dev/null
+++ b/plugins/network-elements/palo-alto/resources/META-INF/cloudstack/paloalto/module.properties
@@ -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.
+name=paloalto
+parent=network
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/resources/META-INF/cloudstack/paloalto/spring-paloalto-context.xml
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/resources/META-INF/cloudstack/paloalto/spring-paloalto-context.xml b/plugins/network-elements/palo-alto/resources/META-INF/cloudstack/paloalto/spring-paloalto-context.xml
new file mode 100644
index 0000000..251f444
--- /dev/null
+++ b/plugins/network-elements/palo-alto/resources/META-INF/cloudstack/paloalto/spring-paloalto-context.xml
@@ -0,0 +1,33 @@
+<!--
+  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.
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+       xmlns:context="http://www.springframework.org/schema/context"
+       xmlns:aop="http://www.springframework.org/schema/aop"
+       xsi:schemaLocation="http://www.springframework.org/schema/beans
+                      http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
+                      http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd
+                      http://www.springframework.org/schema/context
+                      http://www.springframework.org/schema/context/spring-context-3.0.xsd"
+                      >
+
+    <bean id="PaloAlto" class="com.cloud.network.element.PaloAltoExternalFirewallElement">
+        <property name="name" value="PaloAlto" />
+    </bean>
+</beans>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/src/com/cloud/api/commands/AddExternalFirewallCmd.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/AddExternalFirewallCmd.java b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/AddExternalFirewallCmd.java
new file mode 100644
index 0000000..84ee869
--- /dev/null
+++ b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/AddExternalFirewallCmd.java
@@ -0,0 +1,112 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package com.cloud.api.commands;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.host.Host;
+import com.cloud.network.element.PaloAltoFirewallElementService;
+import org.apache.cloudstack.api.response.ExternalFirewallResponse;
+import com.cloud.user.Account;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = "addExternalFirewall", description="Adds an external firewall appliance", responseObject = ExternalFirewallResponse.class)
+public class AddExternalFirewallCmd extends BaseCmd {
+    public static final Logger s_logger = Logger.getLogger(AddExternalFirewallCmd.class.getName());
+    private static final String s_name = "addexternalfirewallresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class,
+            required = true, description="Zone in which to add the external firewall appliance.")
+    private Long zoneId;
+
+    @Parameter(name=ApiConstants.URL, type=CommandType.STRING, required = true, description="URL of the external firewall appliance.")
+    private String url;
+
+    @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required = true, description="Username of the external firewall appliance.")
+    private String username;
+
+    @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required = true, description="Password of the external firewall appliance.")
+    private String password;
+
+    ///////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getZoneId() {
+        return zoneId;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Inject PaloAltoFirewallElementService _paElementService;
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public void execute(){
+        try {
+            Host externalFirewall = _paElementService.addExternalFirewall(this);
+            ExternalFirewallResponse response = _paElementService.createExternalFirewallResponse(externalFirewall);
+            response.setObjectName("externalfirewall");
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+        } catch (InvalidParameterValueException ipve) {
+            throw new ServerApiException(ApiErrorCode.PARAM_ERROR, ipve.getMessage());
+        } catch (CloudRuntimeException cre) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, cre.getMessage());
+        }
+    }
+}
+

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/src/com/cloud/api/commands/AddPaloAltoFirewallCmd.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/AddPaloAltoFirewallCmd.java b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/AddPaloAltoFirewallCmd.java
new file mode 100644
index 0000000..faf28e2
--- /dev/null
+++ b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/AddPaloAltoFirewallCmd.java
@@ -0,0 +1,135 @@
+// 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.api.commands;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import com.cloud.api.response.PaloAltoFirewallResponse;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.dao.ExternalFirewallDeviceVO;
+import com.cloud.network.element.PaloAltoFirewallElementService;
+import org.apache.cloudstack.context.CallContext;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = "addPaloAltoFirewall", responseObject=PaloAltoFirewallResponse.class, description="Adds a Palo Alto firewall device")
+public class AddPaloAltoFirewallCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = Logger.getLogger(AddPaloAltoFirewallCmd.class.getName());
+    private static final String s_name = "addpaloaltofirewallresponse";
+    @Inject PaloAltoFirewallElementService _paFwService;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType = PhysicalNetworkResponse.class,
+            required=true, description="the Physical Network ID")
+    private Long physicalNetworkId;
+
+    @Parameter(name=ApiConstants.URL, type=CommandType.STRING, required = true, description="URL of the Palo Alto appliance.")
+    private String url;
+
+    @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required = true, description="Credentials to reach Palo Alto firewall device")
+    private String username;
+
+    @Parameter(name=ApiConstants.PASSWORD, type=CommandType.STRING, required = true, description="Credentials to reach Palo Alto firewall device")
+    private String password;
+
+    @Parameter(name = ApiConstants.NETWORK_DEVICE_TYPE, type = CommandType.STRING, required = true, description = "supports only PaloAltoFirewall")
+    private String deviceType;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getPhysicalNetworkId() {
+        return physicalNetworkId;
+    }
+
+    public String getUrl() {
+        return url;
+    }
+
+    public String getUsername() {
+        return username;
+    }
+
+    public String getPassword() {
+        return password;
+    }
+
+    public String getDeviceType() {
+        return deviceType;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException {
+        try {
+            ExternalFirewallDeviceVO fwDeviceVO = _paFwService.addPaloAltoFirewall(this);
+            if (fwDeviceVO != null) {
+                PaloAltoFirewallResponse response = _paFwService.createPaloAltoFirewallResponse(fwDeviceVO);
+                response.setObjectName("pafirewall");
+                response.setResponseName(getCommandName());
+                this.setResponseObject(response);
+            } else {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add Palo Alto firewall due to internal error.");
+            }
+        }  catch (InvalidParameterValueException invalidParamExcp) {
+            throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage());
+        } catch (CloudRuntimeException runtimeExcp) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, runtimeExcp.getMessage());
+        }
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Adding a Palo Alto firewall device";
+    }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_EXTERNAL_FIREWALL_DEVICE_ADD;
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return CallContext.current().getCallingAccount().getId();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ConfigurePaloAltoFirewallCmd.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ConfigurePaloAltoFirewallCmd.java b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ConfigurePaloAltoFirewallCmd.java
new file mode 100644
index 0000000..199bb83
--- /dev/null
+++ b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ConfigurePaloAltoFirewallCmd.java
@@ -0,0 +1,114 @@
+// 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.api.commands;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import com.cloud.api.response.PaloAltoFirewallResponse;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.dao.ExternalFirewallDeviceVO;
+import com.cloud.network.element.PaloAltoFirewallElementService;
+import org.apache.cloudstack.context.CallContext;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = "configurePaloAltoFirewall", responseObject=PaloAltoFirewallResponse.class, description="Configures a Palo Alto firewall device")
+public class ConfigurePaloAltoFirewallCmd extends BaseAsyncCmd {
+
+    public static final Logger s_logger = Logger.getLogger(ConfigurePaloAltoFirewallCmd.class.getName());
+    private static final String s_name = "configurepaloaltofirewallresponse";
+    @Inject PaloAltoFirewallElementService _paFwService;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.FIREWALL_DEVICE_ID, type=CommandType.UUID, entityType = PaloAltoFirewallResponse.class,
+            required=true, description="Palo Alto firewall device ID")
+    private Long fwDeviceId;
+
+    @Parameter(name=ApiConstants.FIREWALL_DEVICE_CAPACITY, type=CommandType.LONG, required=false, description="capacity of the firewall device, Capacity will be interpreted as number of networks device can handle")
+    private Long capacity;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getFirewallDeviceId() {
+        return fwDeviceId;
+    }
+
+    public Long getFirewallCapacity() {
+        return capacity;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException {
+        try {
+            ExternalFirewallDeviceVO fwDeviceVO = _paFwService.configurePaloAltoFirewall(this);
+            if (fwDeviceVO != null) {
+                PaloAltoFirewallResponse response = _paFwService.createPaloAltoFirewallResponse(fwDeviceVO);
+                response.setObjectName("pafirewall");
+                response.setResponseName(getCommandName());
+                this.setResponseObject(response);
+            } else {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to configure Palo Alto firewall device due to internal error.");
+            }
+        }  catch (InvalidParameterValueException invalidParamExcp) {
+            throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage());
+        } catch (CloudRuntimeException runtimeExcp) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, runtimeExcp.getMessage());
+        }
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Configuring a Palo Alto firewall device";
+    }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_EXTERNAL_FIREWALL_DEVICE_CONFIGURE;
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return CallContext.current().getCallingAccount().getId();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/src/com/cloud/api/commands/DeleteExternalFirewallCmd.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/DeleteExternalFirewallCmd.java b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/DeleteExternalFirewallCmd.java
new file mode 100644
index 0000000..93f752a
--- /dev/null
+++ b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/DeleteExternalFirewallCmd.java
@@ -0,0 +1,88 @@
+// 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.api.commands;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.response.HostResponse;
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.network.element.PaloAltoFirewallElementService;
+import com.cloud.user.Account;
+
+@APICommand(name = "deleteExternalFirewall", description="Deletes an external firewall appliance.", responseObject = SuccessResponse.class)
+public class DeleteExternalFirewallCmd extends BaseCmd {
+    public static final Logger s_logger = Logger.getLogger(DeleteExternalFirewallCmd.class.getName());
+    private static final String s_name = "deleteexternalfirewallresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.ID, type=CommandType.UUID, entityType = HostResponse.class,
+            required = true, description="Id of the external firewall appliance.")
+    private Long id;
+
+    ///////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getId() {
+        return id;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Inject PaloAltoFirewallElementService _paElementService;
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return Account.ACCOUNT_ID_SYSTEM;
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public void execute(){
+        try {
+            boolean result = _paElementService.deleteExternalFirewall(this);
+            if (result) {
+            SuccessResponse response = new SuccessResponse(getCommandName());
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+            } else {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete external firewall.");
+            }
+        } catch (InvalidParameterValueException e) {
+            throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Failed to delete external firewall.");
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/src/com/cloud/api/commands/DeletePaloAltoFirewallCmd.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/DeletePaloAltoFirewallCmd.java b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/DeletePaloAltoFirewallCmd.java
new file mode 100644
index 0000000..8614981
--- /dev/null
+++ b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/DeletePaloAltoFirewallCmd.java
@@ -0,0 +1,105 @@
+// 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.api.commands;
+
+import javax.inject.Inject;
+
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.BaseAsyncCmd;
+import org.apache.cloudstack.api.BaseCmd;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.response.SuccessResponse;
+import com.cloud.api.response.PaloAltoFirewallResponse;
+import com.cloud.event.EventTypes;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.element.PaloAltoFirewallElementService;
+import org.apache.cloudstack.context.CallContext;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = "deletePaloAltoFirewall", responseObject=SuccessResponse.class, description=" delete a Palo Alto firewall device")
+public class DeletePaloAltoFirewallCmd extends BaseAsyncCmd {
+    public static final Logger s_logger = Logger.getLogger(DeletePaloAltoFirewallCmd.class.getName());
+    private static final String s_name = "deletepaloaltofirewallresponse";
+    @Inject PaloAltoFirewallElementService _paElementService;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.FIREWALL_DEVICE_ID, type=CommandType.UUID, entityType = PaloAltoFirewallResponse.class,
+            required=true, description="Palo Alto firewall device ID")
+    private Long fwDeviceId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getFirewallDeviceId() {
+        return fwDeviceId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException {
+        try {
+            boolean result = _paElementService.deletePaloAltoFirewall(this);
+            if (result) {
+                SuccessResponse response = new SuccessResponse(getCommandName());
+                response.setResponseName(getCommandName());
+                this.setResponseObject(response);
+            } else {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete Palo Alto firewall device");
+            }
+        }  catch (InvalidParameterValueException invalidParamExcp) {
+            throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage());
+        } catch (CloudRuntimeException runtimeExcp) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, runtimeExcp.getMessage());
+        }
+    }
+
+    @Override
+    public String getEventDescription() {
+        return "Deleting Palo Alto firewall device";
+    }
+
+    @Override
+    public String getEventType() {
+        return EventTypes.EVENT_EXTERNAL_FIREWALL_DEVICE_DELETE;
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @Override
+    public long getEntityOwnerId() {
+        return CallContext.current().getCallingAccount().getId();
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListExternalFirewallsCmd.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListExternalFirewallsCmd.java b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListExternalFirewallsCmd.java
new file mode 100644
index 0000000..ebced7e
--- /dev/null
+++ b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListExternalFirewallsCmd.java
@@ -0,0 +1,88 @@
+// 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.api.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd;
+import org.apache.cloudstack.api.response.ZoneResponse;
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.ListResponse;
+import com.cloud.host.Host;
+import com.cloud.network.element.PaloAltoFirewallElementService;
+import org.apache.cloudstack.api.response.ExternalFirewallResponse;
+
+@APICommand(name = "listExternalFirewalls", description="List external firewall appliances.", responseObject = ExternalFirewallResponse.class)
+public class ListExternalFirewallsCmd extends BaseListCmd {
+	public static final Logger s_logger = Logger.getLogger(ListServiceOfferingsCmd.class.getName());
+    private static final String s_name = "listexternalfirewallsresponse";
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.ZONE_ID, type=CommandType.UUID, entityType = ZoneResponse.class,
+            required = true, description="zone Id")
+    private long zoneId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public long getZoneId() {
+        return zoneId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Inject PaloAltoFirewallElementService _paElementService;
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+
+    @SuppressWarnings("deprecation")
+    @Override
+    public void execute(){
+
+    	List<? extends Host> externalFirewalls = _paElementService.listExternalFirewalls(this);
+
+        ListResponse<ExternalFirewallResponse> listResponse = new ListResponse<ExternalFirewallResponse>();
+        List<ExternalFirewallResponse> responses = new ArrayList<ExternalFirewallResponse>();
+        for (Host externalFirewall : externalFirewalls) {
+        	ExternalFirewallResponse response = _paElementService.createExternalFirewallResponse(externalFirewall);
+        	response.setObjectName("externalfirewall");
+        	response.setResponseName(getCommandName());
+        	responses.add(response);
+        }
+
+        listResponse.setResponses(responses);
+        listResponse.setResponseName(getCommandName());
+        this.setResponseObject(listResponse);
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListPaloAltoFirewallNetworksCmd.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListPaloAltoFirewallNetworksCmd.java b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListPaloAltoFirewallNetworksCmd.java
new file mode 100644
index 0000000..15c5bfc
--- /dev/null
+++ b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListPaloAltoFirewallNetworksCmd.java
@@ -0,0 +1,95 @@
+// 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.api.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.*;
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.NetworkResponse;
+import com.cloud.api.response.PaloAltoFirewallResponse;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.Network;
+import com.cloud.network.element.PaloAltoFirewallElementService;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = "listPaloAltoFirewallNetworks", responseObject=NetworkResponse.class, description="lists network that are using Palo Alto firewall device")
+public class ListPaloAltoFirewallNetworksCmd extends BaseListCmd {
+
+    public static final Logger s_logger = Logger.getLogger(ListPaloAltoFirewallNetworksCmd.class.getName());
+    private static final String s_name = "listpaloaltofirewallnetworksresponse";
+    @Inject PaloAltoFirewallElementService _paFwService;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.LOAD_BALANCER_DEVICE_ID, type=CommandType.UUID, entityType = PaloAltoFirewallResponse.class,
+            required = true, description="palo alto balancer device ID")
+    private Long fwDeviceId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getFirewallDeviceId() {
+        return fwDeviceId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException {
+        try {
+            List<? extends Network> networks  = _paFwService.listNetworks(this);
+            ListResponse<NetworkResponse> response = new ListResponse<NetworkResponse>();
+            List<NetworkResponse> networkResponses = new ArrayList<NetworkResponse>();
+
+            if (networks != null && !networks.isEmpty()) {
+                for (Network network : networks) {
+                    NetworkResponse networkResponse = _responseGenerator.createNetworkResponse(network);
+                    networkResponses.add(networkResponse);
+                }
+            }
+
+            response.setResponses(networkResponses);
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+        }  catch (InvalidParameterValueException invalidParamExcp) {
+            throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage());
+        } catch (CloudRuntimeException runtimeExcp) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, runtimeExcp.getMessage());
+        }
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListPaloAltoFirewallsCmd.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListPaloAltoFirewallsCmd.java b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListPaloAltoFirewallsCmd.java
new file mode 100644
index 0000000..b788aca
--- /dev/null
+++ b/plugins/network-elements/palo-alto/src/com/cloud/api/commands/ListPaloAltoFirewallsCmd.java
@@ -0,0 +1,103 @@
+// 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.api.commands;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.*;
+import org.apache.cloudstack.api.response.PhysicalNetworkResponse;
+import org.apache.log4j.Logger;
+
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.response.ListResponse;
+import com.cloud.api.response.PaloAltoFirewallResponse;
+import com.cloud.exception.ConcurrentOperationException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.dao.ExternalFirewallDeviceVO;
+import com.cloud.network.element.PaloAltoFirewallElementService;
+import com.cloud.utils.exception.CloudRuntimeException;
+
+@APICommand(name = "listPaloAltoFirewalls", responseObject=PaloAltoFirewallResponse.class, description="lists Palo Alto firewall devices in a physical network")
+public class ListPaloAltoFirewallsCmd extends BaseListCmd {
+
+    public static final Logger s_logger = Logger.getLogger(ListPaloAltoFirewallsCmd.class.getName());
+    private static final String s_name = "listpaloaltofirewallresponse";
+    @Inject PaloAltoFirewallElementService _paFwService;
+
+    /////////////////////////////////////////////////////
+    //////////////// API parameters /////////////////////
+    /////////////////////////////////////////////////////
+
+    @Parameter(name=ApiConstants.PHYSICAL_NETWORK_ID, type=CommandType.UUID, entityType = PhysicalNetworkResponse.class,
+            description="the Physical Network ID")
+    private Long physicalNetworkId;
+
+    @Parameter(name=ApiConstants.FIREWALL_DEVICE_ID, type=CommandType.UUID, entityType = PaloAltoFirewallResponse.class,
+            description="Palo Alto firewall device ID")
+    private Long fwDeviceId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getFirewallDeviceId() {
+        return fwDeviceId;
+    }
+
+    public Long getPhysicalNetworkId() {
+        return physicalNetworkId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException {
+        try {
+            List<ExternalFirewallDeviceVO> fwDevices = _paFwService.listPaloAltoFirewalls(this);
+            ListResponse<PaloAltoFirewallResponse> response = new ListResponse<PaloAltoFirewallResponse>();
+            List<PaloAltoFirewallResponse> fwDevicesResponse = new ArrayList<PaloAltoFirewallResponse>();
+
+            if (fwDevices != null && !fwDevices.isEmpty()) {
+                for (ExternalFirewallDeviceVO fwDeviceVO : fwDevices) {
+                    PaloAltoFirewallResponse deviceResponse = _paFwService.createPaloAltoFirewallResponse(fwDeviceVO);
+                    fwDevicesResponse.add(deviceResponse);
+                }
+            }
+
+            response.setResponses(fwDevicesResponse);
+            response.setResponseName(getCommandName());
+            this.setResponseObject(response);
+        }  catch (InvalidParameterValueException invalidParamExcp) {
+            throw new ServerApiException(ApiErrorCode.PARAM_ERROR, invalidParamExcp.getMessage());
+        } catch (CloudRuntimeException runtimeExcp) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, runtimeExcp.getMessage());
+        }
+    }
+
+    @Override
+    public String getCommandName() {
+        return s_name;
+    }
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/src/com/cloud/api/response/PaloAltoFirewallResponse.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/src/com/cloud/api/response/PaloAltoFirewallResponse.java b/plugins/network-elements/palo-alto/src/com/cloud/api/response/PaloAltoFirewallResponse.java
new file mode 100644
index 0000000..cda018d
--- /dev/null
+++ b/plugins/network-elements/palo-alto/src/com/cloud/api/response/PaloAltoFirewallResponse.java
@@ -0,0 +1,142 @@
+// 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.api.response;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.EntityReference;
+import com.cloud.serializer.Param;
+import com.google.gson.annotations.SerializedName;
+import org.apache.cloudstack.api.BaseResponse;
+
+import com.cloud.network.dao.ExternalFirewallDeviceVO;
+
+@EntityReference(value=ExternalFirewallDeviceVO.class)
+@SuppressWarnings("unused")
+public class PaloAltoFirewallResponse extends BaseResponse {
+
+    @SerializedName(ApiConstants.FIREWALL_DEVICE_ID) @Param(description="device id of the Palo Alto firewall")
+    private String id;
+
+    @SerializedName(ApiConstants.PHYSICAL_NETWORK_ID) @Param(description="the physical network to which this Palo Alto firewall belongs to")
+    private String physicalNetworkId;
+
+    @SerializedName(ApiConstants.PROVIDER) @Param(description="name of the provider")
+    private String providerName;
+
+    @SerializedName(ApiConstants.FIREWALL_DEVICE_NAME) @Param(description="device name")
+    private String deviceName;
+
+    @SerializedName(ApiConstants.FIREWALL_DEVICE_STATE) @Param(description="device state")
+    private String deviceState;
+
+    @SerializedName(ApiConstants.FIREWALL_DEVICE_CAPACITY) @Param(description="device capacity")
+    private Long deviceCapacity;
+
+    @SerializedName(ApiConstants.ZONE_ID) @Param(description="the zone ID of the external firewall")
+    private String zoneId;
+
+    @SerializedName(ApiConstants.IP_ADDRESS) @Param(description="the management IP address of the external firewall")
+    private String ipAddress;
+
+    @SerializedName(ApiConstants.USERNAME) @Param(description="the username that's used to log in to the external firewall")
+    private String username;
+
+    @SerializedName(ApiConstants.PUBLIC_INTERFACE) @Param(description="the public interface of the external firewall")
+    private String publicInterface;
+
+    @SerializedName(ApiConstants.USAGE_INTERFACE) @Param(description="the usage interface of the external firewall")
+    private String usageInterface;
+
+    @SerializedName(ApiConstants.PRIVATE_INTERFACE) @Param(description="the private interface of the external firewall")
+    private String privateInterface;
+
+    @SerializedName(ApiConstants.PUBLIC_ZONE) @Param(description="the public security zone of the external firewall")
+    private String publicZone;
+
+    @SerializedName(ApiConstants.PRIVATE_ZONE) @Param(description="the private security zone of the external firewall")
+    private String privateZone;
+
+    @SerializedName(ApiConstants.NUM_RETRIES) @Param(description="the number of times to retry requests to the external firewall")
+    private String numRetries;
+
+    @SerializedName(ApiConstants.TIMEOUT) @Param(description="the timeout (in seconds) for requests to the external firewall")
+    private String timeout;
+
+    public void setId(String lbDeviceId) {
+        this.id = lbDeviceId;
+    }
+
+    public void setPhysicalNetworkId(String physicalNetworkId) {
+        this.physicalNetworkId = physicalNetworkId;
+    }
+
+    public void setProvider(String provider) {
+        this.providerName = provider;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public void setDeviceCapacity(long deviceCapacity) {
+        this.deviceCapacity = deviceCapacity;
+    }
+
+    public void setDeviceState(String deviceState) {
+        this.deviceState = deviceState;
+    }
+
+    public void setIpAddress(String ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+
+    public void setPublicInterface(String publicInterface) {
+        this.publicInterface = publicInterface;
+    }
+
+    public void setUsageInterface(String usageInterface) {
+        this.usageInterface = usageInterface;
+    }
+
+    public void setPrivateInterface(String privateInterface) {
+        this.privateInterface = privateInterface;
+    }
+
+    public void setPublicZone(String publicZone) {
+        this.publicZone = publicZone;
+    }
+
+    public void setPrivateZone(String privateZone) {
+        this.privateZone = privateZone;
+    }
+
+    public String getNumRetries() {
+        return numRetries;
+    }
+
+    public void setNumRetries(String numRetries) {
+        this.numRetries = numRetries;
+    }
+
+    public String getTimeout() {
+        return timeout;
+    }
+
+    public void setTimeout(String timeout) {
+        this.timeout = timeout;
+    }
+}


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

Posted by ya...@apache.org.
http://git-wip-us.apache.org/repos/asf/cloudstack/blob/8f8ad3f3/plugins/network-elements/palo-alto/src/com/cloud/network/resource/PaloAltoResource.java
----------------------------------------------------------------------
diff --git a/plugins/network-elements/palo-alto/src/com/cloud/network/resource/PaloAltoResource.java b/plugins/network-elements/palo-alto/src/com/cloud/network/resource/PaloAltoResource.java
new file mode 100644
index 0000000..2251ce0
--- /dev/null
+++ b/plugins/network-elements/palo-alto/src/com/cloud/network/resource/PaloAltoResource.java
@@ -0,0 +1,2030 @@
+// 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 PaloAltoResource implements ServerResource {
+
+    private String _name;
+    private String _zoneId;
+    private String _ip;
+    private String _username;
+    private String _password;
+    private String _guid;
+    private String _key;
+    private Integer _numRetries;
+    private Integer _timeoutInSeconds;
+    private String _publicZone;
+    private String _privateZone;
+    private String _publicInterface;
+    private String _privateInterface;
+    private String _publicInterfaceType;
+    private String _privateInterfaceType;
+    private String _virtualRouter;
+    private String _threatProfile;
+    private String _logProfile;
+    private String _pingManagementProfile;
+    private final Logger s_logger = Logger.getLogger(PaloAltoResource.class);
+
+    private static String _apiUri = "/api";
+    private static HttpClient _httpclient;
+
+    protected enum PaloAltoMethod {
+        GET, POST;
+    }
+
+    private enum PaloAltoPrimative {
+        CHECK_IF_EXISTS, ADD, DELETE;
+    }
+
+    private enum InterfaceType {
+        AGGREGATE("aggregate-ethernet"),
+        ETHERNET("ethernet");
+
+        private String type;
+
+        private InterfaceType(String type) {
+            this.type = type;
+        }
+        public String toString() {
+            return type;
+        }
+    }
+
+    private enum Protocol {
+        TCP("tcp"),
+        UDP("udp"),
+        ICMP("icmp"),
+        ALL("all");
+
+        private String protocol;
+
+        private Protocol(String protocol) {
+            this.protocol = protocol;
+        }
+        public String toString() {
+            return protocol;
+        }
+    }
+
+    private enum GuestNetworkType {
+        SOURCE_NAT,
+        INTERFACE_NAT;
+    }
+
+    public Answer executeRequest(Command cmd) {
+        if (cmd instanceof ReadyCommand) {
+            return execute((ReadyCommand) cmd);
+        } else if (cmd instanceof MaintainCommand) {
+            return execute((MaintainCommand) cmd);
+        } else if (cmd instanceof IpAssocCommand) {
+            return execute((IpAssocCommand) cmd);
+        } else if (cmd instanceof SetStaticNatRulesCommand) {
+            return execute((SetStaticNatRulesCommand) cmd);
+        } else if (cmd instanceof SetPortForwardingRulesCommand) {
+            return execute((SetPortForwardingRulesCommand) cmd);
+        } else if (cmd instanceof SetFirewallRulesCommand) {
+            return execute((SetFirewallRulesCommand) cmd);
+        } else if (cmd instanceof ExternalNetworkResourceUsageCommand) {
+            return execute((ExternalNetworkResourceUsageCommand) cmd);
+        } else {
+            return Answer.createUnsupportedCommandAnswer(cmd);
+        }
+    }
+
+    public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
+        try {
+            _name = (String) params.get("name");
+            if (_name == null) {
+                throw new ConfigurationException("Unable to find name");
+            }
+
+            _zoneId = (String) params.get("zoneId");
+            if (_zoneId == null) {
+                throw new ConfigurationException("Unable to find zone");
+            }
+
+            _ip = (String) params.get("ip");
+            if (_ip == null) {
+                throw new ConfigurationException("Unable to find IP");
+            }
+
+            _username = (String) params.get("username");
+            if (_username == null) {
+                throw new ConfigurationException("Unable to find username");
+            }
+
+            _password = (String) params.get("password");
+            if (_password == null) {
+                throw new ConfigurationException("Unable to find password");
+            }           
+
+            _publicInterface = (String) params.get("publicinterface");
+            if (_publicInterface == null) {
+                throw new ConfigurationException("Unable to find public interface.");
+            }
+
+            _privateInterface = (String) params.get("privateinterface");
+            if (_privateInterface == null) {
+                throw new ConfigurationException("Unable to find private interface.");
+            }
+
+            _publicZone = (String) params.get("publicnetwork");
+            if (_publicZone == null) {
+                throw new ConfigurationException("Unable to find public zone");
+            }
+
+            _privateZone = (String) params.get("privatenetwork");
+            if (_privateZone == null) {
+                throw new ConfigurationException("Unable to find private zone");
+            }
+
+            _virtualRouter = (String) params.get("pavr");
+            if (_virtualRouter == null) {
+                throw new ConfigurationException("Unable to find virtual router");
+            }
+
+            _threatProfile = (String) params.get("patp");
+            _logProfile = (String) params.get("palp");
+
+            _guid = (String) params.get("guid");
+            if (_guid == null) {
+                throw new ConfigurationException("Unable to find the guid");
+            }
+
+            _numRetries = NumbersUtil.parseInt((String) params.get("numretries"), 1);
+            _timeoutInSeconds = NumbersUtil.parseInt((String) params.get("timeout"), 300);
+
+            // Open a socket and login
+            if (!refreshPaloAltoConnection()) {
+                throw new ConfigurationException("Unable to open a connection to the Palo Alto.");
+            }
+
+            // check that the threat profile exists if one was specified
+            if (_threatProfile != null) {
+                try {
+                    boolean has_profile = getThreatProfile(_threatProfile);
+                    if (!has_profile) {
+                        throw new ConfigurationException("The specified threat profile group does not exist.");
+                    }
+                } catch (ExecutionException e) {
+                    throw new ConfigurationException(e.getMessage());
+                }
+            }
+
+            // check that the log profile exists if one was specified
+            if (_logProfile != null) {
+                try {
+                    boolean has_profile = getLogProfile(_logProfile);
+                    if (!has_profile) {
+                        throw new ConfigurationException("The specified log profile does not exist.");
+                    }
+                } catch (ExecutionException e) {
+                    throw new ConfigurationException(e.getMessage());
+                }
+            }
+
+            // get public interface type
+            try {
+                _publicInterfaceType = getInterfaceType(_publicInterface);
+                if (_publicInterfaceType.equals("")) {
+                    throw new ConfigurationException("The specified public interface is not configured on the Palo Alto.");
+                }
+            } catch (ExecutionException e) {
+                throw new ConfigurationException(e.getMessage());
+            }
+
+            // get private interface type
+            try {
+                _privateInterfaceType = getInterfaceType(_privateInterface);
+                if (_privateInterfaceType.equals("")) {
+                    throw new ConfigurationException("The specified private interface is not configured on the Palo Alto.");
+                }
+            } catch (ExecutionException e) {
+                throw new ConfigurationException(e.getMessage());
+            }
+
+            _pingManagementProfile = "Ping";
+            try {
+                ArrayList<IPaloAltoCommand> cmdList = new ArrayList<IPaloAltoCommand>();
+                managePingProfile(cmdList, PaloAltoPrimative.ADD);
+                boolean status = requestWithCommit(cmdList);
+            } catch (ExecutionException e) {
+                throw new ConfigurationException(e.getMessage());
+            }
+
+            return true;
+        } catch (Exception e) {
+            throw new ConfigurationException(e.getMessage());
+        }
+
+    }
+
+    public StartupCommand[] initialize() {   
+        StartupExternalFirewallCommand cmd = new StartupExternalFirewallCommand();
+        cmd.setName(_name);
+        cmd.setDataCenter(_zoneId);
+        cmd.setPod("");
+        cmd.setPrivateIpAddress(_ip);
+        cmd.setStorageIpAddress("");
+        cmd.setVersion(PaloAltoResource.class.getPackage().getImplementationVersion());
+        cmd.setGuid(_guid);
+        return new StartupCommand[]{cmd};
+    }
+
+    public Host.Type getType() {
+        return Host.Type.ExternalFirewall;
+    }
+
+    @Override
+    public String getName() {
+        return _name;
+    }
+
+    @Override
+    public boolean start() {
+        return true;
+    }
+
+    @Override
+    public boolean stop() {
+        return true;
+    }
+
+    @Override
+    public PingCommand getCurrentStatus(final long id) {
+        return new PingCommand(Host.Type.ExternalFirewall, id);
+    }
+
+    @Override
+    public void disconnected() {
+        // nothing for now...
+    }
+
+    public IAgentControl getAgentControl() {
+        return null;
+    }
+
+    public void setAgentControl(IAgentControl agentControl) {
+        return;
+    }
+
+    /*
+     * Login
+     */
+    private void openHttpConnection(){
+        _httpclient = new DefaultHttpClient();
+
+        // Allows you to connect via SSL using unverified certs
+        _httpclient = HttpClientWrapper.wrapClient(_httpclient);
+    }
+
+    private boolean refreshPaloAltoConnection() {
+        if (_httpclient == null) {
+            openHttpConnection();
+        }
+
+        try {
+            return login(_username, _password);
+        } catch (ExecutionException e) {
+            s_logger.error("Failed to login due to " + e.getMessage());
+            return false;
+        }
+    }
+
+    private boolean login(String username, String password) throws ExecutionException {
+        Map<String, String> params = new HashMap<String, String>();
+        params.put("type", "keygen");
+        params.put("user", username);
+        params.put("password", password);
+
+        String keygenBody;
+        try {
+            keygenBody = request(PaloAltoMethod.GET, params);    
+        } catch (ExecutionException e) {
+            return false;
+        }
+        Document keygen_doc = getDocument(keygenBody);
+        XPath xpath = XPathFactory.newInstance().newXPath();
+        try {
+            XPathExpression expr = xpath.compile("/response[@status='success']/result/key/text()");
+            _key = (String) expr.evaluate(keygen_doc, XPathConstants.STRING);
+        } catch (XPathExpressionException e) {
+            throw new ExecutionException(e.getCause().getMessage());
+        }
+        if (_key != null) {
+            return true;
+        }
+        return false;
+    }
+
+
+    // ENTRY POINTS...
+    
+
+    private Answer execute(ReadyCommand cmd) {
+        return new ReadyAnswer(cmd);
+    }
+
+    private Answer execute(MaintainCommand cmd) {
+        return new MaintainAnswer(cmd);
+    }
+
+    private ExternalNetworkResourceUsageAnswer execute(ExternalNetworkResourceUsageCommand cmd) {
+        return new ExternalNetworkResourceUsageAnswer(cmd);
+    }
+
+
+    /*
+     * Guest networks
+     */
+
+    private synchronized Answer execute(IpAssocCommand cmd) {
+        refreshPaloAltoConnection();
+        return execute(cmd, _numRetries);
+    }
+
+    private Answer execute(IpAssocCommand cmd, int numRetries) {        
+        String[] results = new String[cmd.getIpAddresses().length];
+        int i = 0;
+        try {
+            IpAddressTO ip;
+            if (cmd.getIpAddresses().length != 1) {
+                throw new ExecutionException("Received an invalid number of guest IPs to associate.");
+            } else {
+                ip = cmd.getIpAddresses()[0];
+            }                               
+
+            String sourceNatIpAddress = null; 
+            GuestNetworkType type = GuestNetworkType.INTERFACE_NAT;
+
+            if (ip.isSourceNat()) {
+                type = GuestNetworkType.SOURCE_NAT;
+
+                if (ip.getPublicIp() == null) {
+                    throw new ExecutionException("Source NAT IP address must not be null.");
+                } else {
+                    sourceNatIpAddress = ip.getPublicIp();
+                }
+            }
+
+            long guestVlanTag = Long.parseLong(cmd.getAccessDetail(NetworkElementCommand.GUEST_VLAN_TAG));
+            String guestVlanGateway = cmd.getAccessDetail(NetworkElementCommand.GUEST_NETWORK_GATEWAY);
+            String cidr = cmd.getAccessDetail(NetworkElementCommand.GUEST_NETWORK_CIDR);
+            long cidrSize = NetUtils.cidrToLong(cidr)[1];
+            String guestVlanSubnet = NetUtils.getCidrSubNet(guestVlanGateway, cidrSize);    
+            
+            Long publicVlanTag = null;
+            if (ip.getBroadcastUri() != null && !ip.getBroadcastUri().equals("untagged")) {
+                try {
+                    publicVlanTag = Long.parseLong(ip.getBroadcastUri());
+                } catch (Exception e) {
+                    throw new ExecutionException("Could not parse public VLAN tag: " + ip.getBroadcastUri());
+                }
+            } 
+
+            ArrayList<IPaloAltoCommand> commandList = new ArrayList<IPaloAltoCommand>();
+
+            if (ip.isAdd()) {                                 
+                // Implement the guest network for this VLAN
+                implementGuestNetwork(commandList, type, publicVlanTag, sourceNatIpAddress, guestVlanTag, guestVlanGateway, guestVlanSubnet, cidrSize);
+            } else {
+                // Remove the guest network:
+                shutdownGuestNetwork(commandList, type, publicVlanTag, sourceNatIpAddress, guestVlanTag, guestVlanGateway, guestVlanSubnet, cidrSize);
+            }
+
+            boolean status = requestWithCommit(commandList);
+
+            results[i++] = ip.getPublicIp() + " - success";
+        } catch (ExecutionException e) {
+            s_logger.error(e);
+
+            if (numRetries > 0 && refreshPaloAltoConnection()) {
+                int numRetriesRemaining = numRetries - 1;
+                s_logger.debug("Retrying IPAssocCommand. Number of retries remaining: " + numRetriesRemaining);
+                return execute(cmd, numRetriesRemaining);
+            } else {
+                results[i++] = IpAssocAnswer.errorResult;
+            }
+        }
+
+        return new IpAssocAnswer(cmd, results);
+    }
+
+    private void implementGuestNetwork(ArrayList<IPaloAltoCommand> cmdList, GuestNetworkType type, Long publicVlanTag, String publicIp, long privateVlanTag, String privateGateway, String privateSubnet, long privateCidrNumber) throws ExecutionException {
+        privateSubnet = privateSubnet+"/"+privateCidrNumber;
+
+        managePrivateInterface(cmdList, PaloAltoPrimative.ADD, privateVlanTag, privateGateway+"/"+privateCidrNumber);
+
+        if (type.equals(GuestNetworkType.SOURCE_NAT)) {
+            managePublicInterface(cmdList, PaloAltoPrimative.ADD, publicVlanTag, publicIp+"/32", privateVlanTag);
+            manageSrcNatRule(cmdList, PaloAltoPrimative.ADD, type, publicVlanTag, publicIp+"/32", privateVlanTag, privateGateway+"/"+privateCidrNumber);
+            manageNetworkIsolation(cmdList, PaloAltoPrimative.ADD, privateVlanTag, privateSubnet, privateGateway);
+        }
+
+        String msg = "Implemented guest network with type " + type + ". Guest VLAN tag: " + privateVlanTag + ", guest gateway: " + privateGateway+"/"+privateCidrNumber;
+        msg += type.equals(GuestNetworkType.SOURCE_NAT) ? ", source NAT IP: " + publicIp : "";
+        s_logger.debug(msg);
+    }
+
+    private void shutdownGuestNetwork(ArrayList<IPaloAltoCommand> cmdList, GuestNetworkType type, Long publicVlanTag, String sourceNatIpAddress, long privateVlanTag, String privateGateway, String privateSubnet, long privateCidrSize) throws ExecutionException {     
+        privateSubnet = privateSubnet+"/"+privateCidrSize;
+
+        if (type.equals(GuestNetworkType.SOURCE_NAT)) {
+            manageNetworkIsolation(cmdList, PaloAltoPrimative.DELETE, privateVlanTag, privateSubnet, privateGateway);
+            manageSrcNatRule(cmdList, PaloAltoPrimative.DELETE, type, publicVlanTag, sourceNatIpAddress+"/32", privateVlanTag, privateGateway+"/"+privateCidrSize);
+            managePublicInterface(cmdList, PaloAltoPrimative.DELETE, publicVlanTag, sourceNatIpAddress+"/32", privateVlanTag);                                                             
+        }
+
+        managePrivateInterface(cmdList, PaloAltoPrimative.DELETE, privateVlanTag, privateGateway+"/"+privateCidrSize);       
+
+        String msg = "Shut down guest network with type " + type +". Guest VLAN tag: " + privateVlanTag + ", guest gateway: " + privateGateway+"/"+privateCidrSize;
+        msg += type.equals(GuestNetworkType.SOURCE_NAT) ? ", source NAT IP: " + sourceNatIpAddress : "";
+        s_logger.debug(msg);
+    }
+
+    
+
+    /*
+     * Firewall rule entry point
+     */
+    private synchronized Answer execute(SetFirewallRulesCommand cmd) {
+        refreshPaloAltoConnection();
+        return execute(cmd, _numRetries);
+    }
+    
+    private Answer execute(SetFirewallRulesCommand cmd, int numRetries) {
+        FirewallRuleTO[] rules = cmd.getRules();
+        try {
+            ArrayList<IPaloAltoCommand> commandList = new ArrayList<IPaloAltoCommand>();
+
+            for (FirewallRuleTO rule : rules) {
+                if (!rule.revoked()) {
+                    manageFirewallRule(commandList, PaloAltoPrimative.ADD, rule);
+                } else {
+                    manageFirewallRule(commandList, PaloAltoPrimative.DELETE, rule);
+                }
+            }
+
+            boolean status = requestWithCommit(commandList);
+                
+            return new Answer(cmd);
+        } catch (ExecutionException e) {
+            s_logger.error(e);
+
+            if (numRetries > 0 && refreshPaloAltoConnection()) {
+                int numRetriesRemaining = numRetries - 1;
+                s_logger.debug("Retrying SetFirewallRulesCommand. Number of retries remaining: " + numRetriesRemaining);
+                return execute(cmd, numRetriesRemaining);
+            } else {
+                return new Answer(cmd, e);
+            }
+        }
+    }
+
+
+    /*
+     * Static NAT rule entry point
+     */
+
+    private synchronized Answer execute(SetStaticNatRulesCommand cmd) {
+        refreshPaloAltoConnection();
+        return execute(cmd, _numRetries);
+    }       
+
+    private Answer execute(SetStaticNatRulesCommand cmd, int numRetries) {      
+        StaticNatRuleTO[] rules = cmd.getRules();
+
+        try {
+            ArrayList<IPaloAltoCommand> commandList = new ArrayList<IPaloAltoCommand>();
+
+            for (StaticNatRuleTO rule : rules) {
+                if (!rule.revoked()) {
+                    manageStcNatRule(commandList, PaloAltoPrimative.ADD, rule);
+                } else {
+                    manageStcNatRule(commandList, PaloAltoPrimative.DELETE, rule);
+                }
+            }
+
+            boolean status = requestWithCommit(commandList);
+
+            return new Answer(cmd);
+        } catch (ExecutionException e) {
+            s_logger.error(e);
+
+            if (numRetries > 0 && refreshPaloAltoConnection()) {
+                int numRetriesRemaining = numRetries - 1;
+                s_logger.debug("Retrying SetStaticNatRulesCommand. Number of retries remaining: " + numRetriesRemaining);
+                return execute(cmd, numRetriesRemaining);
+            } else {
+                return new Answer(cmd, e);
+            }
+        }
+    }
+
+
+    /*
+     * Destination NAT (Port Forwarding) entry point
+     */
+    private synchronized Answer execute (SetPortForwardingRulesCommand cmd) {
+        refreshPaloAltoConnection();
+        return execute(cmd, _numRetries);
+    }
+
+    private Answer execute(SetPortForwardingRulesCommand cmd, int numRetries) {     
+        PortForwardingRuleTO[] rules = cmd.getRules();
+
+        try {
+            ArrayList<IPaloAltoCommand> commandList = new ArrayList<IPaloAltoCommand>();
+
+            for (PortForwardingRuleTO rule : rules) {
+                if (!rule.revoked()) {
+                    manageDstNatRule(commandList, PaloAltoPrimative.ADD, rule);
+                } else {
+                    manageDstNatRule(commandList, PaloAltoPrimative.DELETE, rule);
+                }
+            }
+
+            boolean status = requestWithCommit(commandList);         
+
+            return new Answer(cmd);
+        } catch (ExecutionException e) {
+            s_logger.error(e);
+            
+            if (numRetries > 0 && refreshPaloAltoConnection()) {
+                int numRetriesRemaining = numRetries - 1;
+                s_logger.debug("Retrying SetPortForwardingRulesCommand. Number of retries remaining: " + numRetriesRemaining);
+                return execute(cmd, numRetriesRemaining);
+            } else {
+                return new Answer(cmd, e);
+            }
+        }
+    }
+
+
+    // IMPLEMENTATIONS...
+
+
+    /*
+     * Private interface implementation
+     */
+
+    private String genPrivateInterfaceName(long vlanTag) {
+        return _privateInterface+"."+Long.toString(vlanTag);
+    }
+
+    public boolean managePrivateInterface(ArrayList<IPaloAltoCommand> cmdList, PaloAltoPrimative prim, long privateVlanTag, String privateGateway) throws ExecutionException {
+        String interfaceName =  genPrivateInterfaceName(privateVlanTag);
+
+        switch (prim) {
+
+        case CHECK_IF_EXISTS:
+            // check if one exists already
+            Map<String, String> params = new HashMap<String, String>();
+            params.put("type", "config");
+            params.put("action", "get");
+            params.put("xpath", "/config/devices/entry/network/interface/"+_privateInterfaceType+"/entry[@name='"+_privateInterface+"']/layer3/units/entry[@name='"+interfaceName+"']");
+            String response = request(PaloAltoMethod.GET, params);
+            boolean result = (validResponse(response) && responseNotEmpty(response));
+            s_logger.debug("Private sub-interface exists: "+interfaceName+", "+result);
+            return result;
+
+        case ADD:
+            if (managePrivateInterface(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, privateVlanTag, privateGateway)) {
+                return true;
+            }
+
+            // add cmds
+            // add sub-interface
+            Map<String, String> a_sub_params = new HashMap<String, String>();
+            a_sub_params.put("type", "config");
+            a_sub_params.put("action", "set");
+            a_sub_params.put("xpath", "/config/devices/entry/network/interface/"+_privateInterfaceType+"/entry[@name='"+_privateInterface+"']/layer3/units/entry[@name='"+interfaceName+"']");
+            a_sub_params.put("element", "<tag>"+privateVlanTag+"</tag><ip><entry name='"+privateGateway+"'/></ip><interface-management-profile>"+_pingManagementProfile+"</interface-management-profile>");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, a_sub_params));
+
+            // add sub-interface to VR...
+            Map<String, String> a_vr_params = new HashMap<String, String>();
+            a_vr_params.put("type", "config");
+            a_vr_params.put("action", "set");
+            a_vr_params.put("xpath", "/config/devices/entry/network/virtual-router/entry[@name='"+_virtualRouter+"']/interface");
+            a_vr_params.put("element", "<member>"+interfaceName+"</member>");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, a_vr_params));
+
+            // add sub-interface to vsys...
+            Map<String, String> a_vsys_params = new HashMap<String, String>();
+            a_vsys_params.put("type", "config");
+            a_vsys_params.put("action", "set");
+            a_vsys_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/import/network/interface");
+            a_vsys_params.put("element", "<member>"+interfaceName+"</member>");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, a_vsys_params));
+
+            // add sub-interface to zone...
+            Map<String, String> a_zone_params = new HashMap<String, String>();
+            a_zone_params.put("type", "config");
+            a_zone_params.put("action", "set");
+            a_zone_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/zone/entry[@name='"+_privateZone+"']/network/layer3");
+            a_zone_params.put("element", "<member>"+interfaceName+"</member>");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, a_zone_params));
+
+            return true;
+
+        case DELETE:
+            if (!managePrivateInterface(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, privateVlanTag, privateGateway)) {
+                return true;
+            }
+
+            // add cmds to the list
+            // delete sub-interface from zone...
+            Map<String, String> d_zone_params = new HashMap<String, String>();
+            d_zone_params.put("type", "config");
+            d_zone_params.put("action", "delete");
+            d_zone_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/zone/entry[@name='"+_privateZone+"']/network/layer3/member[text()='"+interfaceName+"']");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, d_zone_params));
+
+            // delete sub-interface from vsys...
+            Map<String, String> d_vsys_params = new HashMap<String, String>();
+            d_vsys_params.put("type", "config");
+            d_vsys_params.put("action", "delete");
+            d_vsys_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/import/network/interface/member[text()='"+interfaceName+"']");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, d_vsys_params));
+
+            // delete sub-interface from VR...
+            Map<String, String> d_vr_params = new HashMap<String, String>();
+            d_vr_params.put("type", "config");
+            d_vr_params.put("action", "delete");
+            d_vr_params.put("xpath", "/config/devices/entry/network/virtual-router/entry[@name='"+_virtualRouter+"']/interface/member[text()='"+interfaceName+"']");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, d_vr_params));
+
+            // delete sub-interface...
+            Map<String, String> d_sub_params = new HashMap<String, String>();
+            d_sub_params.put("type", "config");
+            d_sub_params.put("action", "delete");
+            d_sub_params.put("xpath", "/config/devices/entry/network/interface/"+_privateInterfaceType+"/entry[@name='"+_privateInterface+"']/layer3/units/entry[@name='"+interfaceName+"']");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, d_sub_params));
+
+            return true;
+
+        default:
+            s_logger.debug("Unrecognized command.");
+            return false;
+        }
+    }
+
+
+    /*
+     * Public Interface implementation
+     */
+
+    private String genPublicInterfaceName(Long id) {
+        return _publicInterface+"."+Long.toString(id);
+    }
+
+    public boolean managePublicInterface(ArrayList<IPaloAltoCommand> cmdList, PaloAltoPrimative prim, Long publicVlanTag, String publicIp, long privateVlanTag) throws ExecutionException {
+        String interfaceName;
+        if (publicVlanTag == null) {
+            interfaceName = genPublicInterfaceName(new Long("9999"));
+        } else {
+            interfaceName = genPublicInterfaceName(publicVlanTag);
+        }
+
+        switch (prim) {
+
+        case CHECK_IF_EXISTS:
+            // check if one exists already
+            Map<String, String> params = new HashMap<String, String>();
+            params.put("type", "config");
+            params.put("action", "get");
+            params.put("xpath", "/config/devices/entry/network/interface/"+_publicInterfaceType+"/entry[@name='"+_publicInterface+"']/layer3/units/entry[@name='"+interfaceName+"']/ip/entry[@name='"+publicIp+"']");
+            String response = request(PaloAltoMethod.GET, params);
+            boolean result = (validResponse(response) && responseNotEmpty(response));
+            s_logger.debug("Public sub-interface & IP exists: "+interfaceName+" : "+publicIp+", "+result);
+            return result;
+
+        case ADD:
+            if (managePublicInterface(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, publicVlanTag, publicIp, privateVlanTag)) {
+                return true;
+            }
+
+            // add IP to the sub-interface
+            Map<String, String> a_sub_params = new HashMap<String, String>();
+            a_sub_params.put("type", "config");
+            a_sub_params.put("action", "set");
+            a_sub_params.put("xpath", "/config/devices/entry/network/interface/"+_publicInterfaceType+"/entry[@name='"+_publicInterface+"']/layer3/units/entry[@name='"+interfaceName+"']/ip");
+            a_sub_params.put("element", "<entry name='"+publicIp+"'/>");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, a_sub_params));
+
+            // add sub-interface to VR (does nothing if already done)...
+            Map<String, String> a_vr_params = new HashMap<String, String>();
+            a_vr_params.put("type", "config");
+            a_vr_params.put("action", "set");
+            a_vr_params.put("xpath", "/config/devices/entry/network/virtual-router/entry[@name='"+_virtualRouter+"']/interface");
+            a_vr_params.put("element", "<member>"+interfaceName+"</member>");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, a_vr_params));
+
+            // add sub-interface to vsys (does nothing if already done)...
+            Map<String, String> a_vsys_params = new HashMap<String, String>();
+            a_vsys_params.put("type", "config");
+            a_vsys_params.put("action", "set");
+            a_vsys_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/import/network/interface");
+            a_vsys_params.put("element", "<member>"+interfaceName+"</member>");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, a_vsys_params));
+
+            // add sub-interface to zone (does nothing if already done)...
+            Map<String, String> a_zone_params = new HashMap<String, String>();
+            a_zone_params.put("type", "config");
+            a_zone_params.put("action", "set");
+            a_zone_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/zone/entry[@name='"+_publicZone+"']/network/layer3");
+            a_zone_params.put("element", "<member>"+interfaceName+"</member>");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, a_zone_params));
+
+            return true;
+
+        case DELETE:
+            if (!managePublicInterface(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, publicVlanTag, publicIp, privateVlanTag)) {
+                return true;
+            }
+
+            // delete IP from sub-interface...
+            Map<String, String> d_sub_params = new HashMap<String, String>();
+            d_sub_params.put("type", "config");
+            d_sub_params.put("action", "delete");
+            d_sub_params.put("xpath", "/config/devices/entry/network/interface/"+_publicInterfaceType+"/entry[@name='"+_publicInterface+"']/layer3/units/entry[@name='"+interfaceName+"']/ip/entry[@name='"+publicIp+"']");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, d_sub_params));
+
+            return true;
+
+        default:
+            s_logger.debug("Unrecognized command.");
+            return false;
+        }
+    }
+
+
+    /*
+     * Source NAT rule implementation
+     */
+
+    private String genSrcNatRuleName(Long privateVlanTag) {
+        return "src_nat."+Long.toString(privateVlanTag);
+    }
+
+    public boolean manageSrcNatRule(ArrayList<IPaloAltoCommand> cmdList, PaloAltoPrimative prim, GuestNetworkType type, Long publicVlanTag, String publicIp, long privateVlanTag, String privateGateway) throws ExecutionException {
+        String publicInterfaceName;
+        if (publicVlanTag == null) {
+            publicInterfaceName = genPublicInterfaceName(new Long("9999"));
+        } else {
+            publicInterfaceName = genPublicInterfaceName(publicVlanTag);
+        }
+        String srcNatName = genSrcNatRuleName(privateVlanTag);
+
+        switch (prim) {
+
+        case CHECK_IF_EXISTS:
+            // check if one exists already
+            Map<String, String> params = new HashMap<String, String>();
+            params.put("type", "config");
+            params.put("action", "get");
+            params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='"+srcNatName+"']");
+            String response = request(PaloAltoMethod.GET, params);
+            boolean result = (validResponse(response) && responseNotEmpty(response));
+            s_logger.debug("Source NAT exists: "+srcNatName+", "+result);
+            return result;
+
+        case ADD:
+            if (manageSrcNatRule(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, type, publicVlanTag, publicIp, privateVlanTag, privateGateway)) {
+                return true;
+            }
+
+            String xml = ""; 
+            xml += "<from><member>"+_privateZone+"</member></from>";
+            xml += "<to><member>"+_publicZone+"</member></to>";
+            xml += "<source><member>"+privateGateway+"</member></source>";
+            xml += "<destination><member>any</member></destination>";
+            xml += "<service>any</service>";
+            xml += "<nat-type>ipv4</nat-type>";
+            xml += "<to-interface>"+publicInterfaceName+"</to-interface>";
+            xml += "<source-translation><dynamic-ip-and-port><interface-address>";
+                xml += "<ip>"+publicIp+"</ip>";
+                xml += "<interface>"+publicInterfaceName+"</interface>";
+            xml += "</interface-address></dynamic-ip-and-port></source-translation>";
+
+            Map<String, String> a_params = new HashMap<String, String>();
+            a_params.put("type", "config");
+            a_params.put("action", "set");
+            a_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='"+srcNatName+"']");
+            a_params.put("element", xml);
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, a_params));
+
+            return true;
+
+        case DELETE:
+            if (!manageSrcNatRule(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, type, publicVlanTag, publicIp, privateVlanTag, privateGateway)) {
+                return true;
+            }
+
+            Map<String, String> d_params = new HashMap<String, String>();
+            d_params.put("type", "config");
+            d_params.put("action", "delete");
+            d_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='"+srcNatName+"']");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, d_params));
+
+            return true;
+
+        default:
+            s_logger.debug("Unrecognized command.");
+            return false;
+        }
+    }
+
+
+    /*
+     * Destination NAT rules (Port Forwarding) implementation
+     */
+    private String genDstNatRuleName(String publicIp, long id) {
+        return "dst_nat."+genIpIdentifier(publicIp)+"_"+Long.toString(id);
+    }
+
+    public boolean manageDstNatRule(ArrayList<IPaloAltoCommand> cmdList, PaloAltoPrimative prim, PortForwardingRuleTO rule) throws ExecutionException {
+        String publicIp = rule.getSrcIp();
+        String dstNatName = genDstNatRuleName(publicIp, rule.getId());
+
+        String publicInterfaceName;
+        String publicVlanTag = rule.getSrcVlanTag();
+        if (publicVlanTag == null || publicVlanTag.equals("untagged")) {
+            publicInterfaceName = genPublicInterfaceName(new Long("9999"));
+        } else {
+            publicInterfaceName = genPublicInterfaceName(new Long(publicVlanTag));
+        }
+
+        switch (prim) {
+
+        case CHECK_IF_EXISTS:
+            // check if one exists already
+            Map<String, String> params = new HashMap<String, String>();
+            params.put("type", "config");
+            params.put("action", "get");
+            params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='"+dstNatName+"']");
+            String response = request(PaloAltoMethod.GET, params);
+            boolean result = (validResponse(response) && responseNotEmpty(response));
+            s_logger.debug("Destination NAT exists: "+dstNatName+", "+result);
+            return result;
+
+        case ADD:
+            if (manageDstNatRule(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, rule)) {
+                return true;
+            }
+
+            // build source service xml
+            String srcService;
+            String protocol = rule.getProtocol();
+            int[] srcPortRange = rule.getSrcPortRange();
+            if (srcPortRange != null) {
+                String portRange;
+                if (srcPortRange.length == 1 || srcPortRange[0] == srcPortRange[1]) {
+                    portRange = String.valueOf(srcPortRange[0]);
+                } else {
+                    portRange = String.valueOf(srcPortRange[0])+"-"+String.valueOf(srcPortRange[1]);
+                }
+                manageService(cmdList, PaloAltoPrimative.ADD, protocol, portRange, null);
+                srcService = genServiceName(protocol, portRange, null);
+            } else {
+                // no equivalent config in PA, so allow all traffic...
+                srcService = "any";
+            }
+
+            // build destination port xml (single port limit in PA)
+            String dstPortXML = "";
+            int[] dstPortRange = rule.getDstPortRange();
+            if (dstPortRange != null) {
+                dstPortXML = "<translated-port>"+dstPortRange[0]+"</translated-port>";
+            }
+
+            // add public IP to the sub-interface
+            Map<String, String> a_sub_params = new HashMap<String, String>();
+            a_sub_params.put("type", "config");
+            a_sub_params.put("action", "set");
+            a_sub_params.put("xpath", "/config/devices/entry/network/interface/"+_publicInterfaceType+"/entry[@name='"+_publicInterface+"']/layer3/units/entry[@name='"+publicInterfaceName+"']/ip");
+            a_sub_params.put("element", "<entry name='"+publicIp+"/32'/>");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, a_sub_params));
+
+            // add the destination nat rule for the public IP
+            String xml = ""; 
+            xml += "<from><member>"+_publicZone+"</member></from>";
+            xml += "<to><member>"+_publicZone+"</member></to>";
+            xml += "<source><member>any</member></source>";
+            xml += "<destination><member>"+publicIp+"</member></destination>";
+            xml += "<service>"+srcService+"</service>";
+            xml += "<nat-type>ipv4</nat-type>";
+            xml += "<to-interface>"+publicInterfaceName+"</to-interface>";
+            xml += "<destination-translation><translated-address>"+rule.getDstIp()+"</translated-address>"+dstPortXML+"</destination-translation>";
+
+            Map<String, String> a_params = new HashMap<String, String>();
+            a_params.put("type", "config");
+            a_params.put("action", "set");
+            a_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='"+dstNatName+"']");
+            a_params.put("element", xml);
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, a_params));
+
+            return true;
+
+        case DELETE:
+            if (!manageDstNatRule(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, rule)) {
+                return true;
+            }
+
+            // determine if we need to delete the ip from the interface as well...
+            Map<String, String> c_params = new HashMap<String, String>();
+            c_params.put("type", "config");
+            c_params.put("action", "get");
+            c_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[destination/member[text()='"+publicIp+"']]");
+            String c_response = request(PaloAltoMethod.GET, c_params);
+
+            String count = "";
+            NodeList response_body;
+            Document doc = getDocument(c_response);
+            XPath xpath = XPathFactory.newInstance().newXPath();
+            try {
+                XPathExpression expr = xpath.compile("/response[@status='success']/result");
+                response_body = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
+            } catch (XPathExpressionException e) {
+                throw new ExecutionException(e.getCause().getMessage());
+            }
+            if (response_body.getLength() > 0 && response_body.item(0).getAttributes().getLength() > 0) {
+                count = response_body.item(0).getAttributes().getNamedItem("count").getTextContent();
+            }
+
+            // delete the dst nat rule
+            Map<String, String> d_params = new HashMap<String, String>();
+            d_params.put("type", "config");
+            d_params.put("action", "delete");
+            d_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='"+dstNatName+"']");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, d_params));
+
+            if (!count.equals("") && Integer.parseInt(count) == 1) { // this dst nat rule is the last, so remove the ip...
+                // delete IP from sub-interface...
+                Map<String, String> d_sub_params = new HashMap<String, String>();
+                d_sub_params.put("type", "config");
+                d_sub_params.put("action", "delete");
+                d_sub_params.put("xpath", "/config/devices/entry/network/interface/"+_publicInterfaceType+"/entry[@name='"+_publicInterface+"']/layer3/units/entry[@name='"+publicInterfaceName+"']/ip/entry[@name='"+publicIp+"/32']");
+                cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, d_sub_params));
+            }
+
+            return true;
+
+        default:
+            s_logger.debug("Unrecognized command.");
+            return false;
+        }
+    }
+
+
+
+    /*
+     * Static NAT rule implementation
+     */
+    private String genStcNatRuleName(String publicIp, long id) {
+        return "stc_nat."+genIpIdentifier(publicIp)+"_"+Long.toString(id);
+    }
+
+    public boolean manageStcNatRule(ArrayList<IPaloAltoCommand> cmdList, PaloAltoPrimative prim, StaticNatRuleTO rule) throws ExecutionException {
+        String publicIp = rule.getSrcIp();
+        String stcNatName = genStcNatRuleName(publicIp, rule.getId());
+
+        String publicInterfaceName;
+        String publicVlanTag = rule.getSrcVlanTag();
+        if (publicVlanTag == null || publicVlanTag.equals("untagged")) {
+            publicInterfaceName = genPublicInterfaceName(new Long("9999"));
+        } else {
+            publicInterfaceName = genPublicInterfaceName(new Long(publicVlanTag));
+        }
+
+        switch (prim) {
+
+        case CHECK_IF_EXISTS:
+            // check if one exists already
+            Map<String, String> params = new HashMap<String, String>();
+            params.put("type", "config");
+            params.put("action", "get");
+            params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='"+stcNatName+"']");
+            String response = request(PaloAltoMethod.GET, params);
+            boolean result = (validResponse(response) && responseNotEmpty(response));
+            s_logger.debug("Static NAT exists: "+stcNatName+", "+result);
+            return result;
+
+        case ADD:
+            if (manageStcNatRule(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, rule)) {
+                return true;
+            }
+
+            // add public IP to the sub-interface
+            Map<String, String> a_sub_params = new HashMap<String, String>();
+            a_sub_params.put("type", "config");
+            a_sub_params.put("action", "set");
+            a_sub_params.put("xpath", "/config/devices/entry/network/interface/"+_publicInterfaceType+"/entry[@name='"+_publicInterface+"']/layer3/units/entry[@name='"+publicInterfaceName+"']/ip");
+            a_sub_params.put("element", "<entry name='"+publicIp+"/32'/>");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, a_sub_params));
+
+            // add the static nat rule for the public IP
+            String xml = ""; 
+            xml += "<from><member>"+_publicZone+"</member></from>";
+            xml += "<to><member>"+_publicZone+"</member></to>";
+            xml += "<source><member>any</member></source>";
+            xml += "<destination><member>"+publicIp+"</member></destination>";
+            xml += "<service>any</service>";
+            xml += "<nat-type>ipv4</nat-type>";
+            xml += "<to-interface>"+publicInterfaceName+"</to-interface>";
+            xml += "<destination-translation><translated-address>"+rule.getDstIp()+"</translated-address></destination-translation>";
+
+
+            Map<String, String> a_params = new HashMap<String, String>();
+            a_params.put("type", "config");
+            a_params.put("action", "set");
+            a_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='"+stcNatName+"']");
+            a_params.put("element", xml);
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, a_params));
+
+            return true;
+
+        case DELETE:
+            if (!manageStcNatRule(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, rule)) {
+                return true;
+            }
+
+            // delete the static nat rule
+            Map<String, String> d_params = new HashMap<String, String>();
+            d_params.put("type", "config");
+            d_params.put("action", "delete");
+            d_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/nat/rules/entry[@name='"+stcNatName+"']");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, d_params));
+
+            // delete IP from sub-interface...
+            Map<String, String> d_sub_params = new HashMap<String, String>();
+            d_sub_params.put("type", "config");
+            d_sub_params.put("action", "delete");
+            d_sub_params.put("xpath", "/config/devices/entry/network/interface/"+_publicInterfaceType+"/entry[@name='"+_publicInterface+"']/layer3/units/entry[@name='"+publicInterfaceName+"']/ip/entry[@name='"+publicIp+"/32']");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, d_sub_params));
+
+            return true;
+
+        default:
+            s_logger.debug("Unrecognized command.");
+            return false;
+        }
+    }
+
+    
+    /*
+     * Firewall rule implementation
+     */
+
+    private String genFirewallRuleName(long id) {
+        return "policy_"+Long.toString(id);
+    }
+
+    public boolean manageFirewallRule(ArrayList<IPaloAltoCommand> cmdList, PaloAltoPrimative prim, FirewallRuleTO rule) throws ExecutionException {
+        String ruleName = genFirewallRuleName(rule.getId());
+
+        switch (prim) {
+
+        case CHECK_IF_EXISTS:
+            // check if one exists already
+            Map<String, String> params = new HashMap<String, String>();
+            params.put("type", "config");
+            params.put("action", "get");
+            params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='"+ruleName+"']");
+            String response = request(PaloAltoMethod.GET, params);
+            boolean result = (validResponse(response) && responseNotEmpty(response));
+            s_logger.debug("Firewall policy exists: "+ruleName+", "+result);
+            return result;
+
+        case ADD:
+            if (manageFirewallRule(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, rule)) {
+                return true;
+            }
+
+            String srcZone;
+            String dstZone;
+            String dstAddressXML;
+            String appXML;
+            String serviceXML;
+
+            String protocol = rule.getProtocol();
+
+            // Only ICMP will use an Application, so others will be any.
+            if (protocol.equals(Protocol.ICMP.toString())) {
+                appXML = "<member>icmp</member><member>ping</member><member>traceroute</member>"; // use the default icmp applications...
+            } else {
+                appXML = "<member>any</member>";
+            }
+
+            // Only TCP and UDP will use a Service, others will use any.
+            if (protocol.equals(Protocol.TCP.toString()) || protocol.equals(Protocol.UDP.toString())) {
+                String portRange;
+                if (rule.getSrcPortRange() != null) {
+                    int startPort = rule.getSrcPortRange()[0];
+                    int endPort = rule.getSrcPortRange()[1];
+                    if (startPort == endPort) {
+                        portRange = String.valueOf(startPort);
+                    } else {
+                        portRange = String.valueOf(startPort)+"-"+String.valueOf(endPort);
+                    }
+                    manageService(cmdList, PaloAltoPrimative.ADD, protocol, portRange, null);
+                    serviceXML = "<member>"+genServiceName(protocol, portRange, null)+"</member>";
+                } else {
+                    // no equivalent config in PA, so allow all traffic...
+                    serviceXML = "<member>any</member>";
+                }
+            } else {
+                serviceXML = "<member>any</member>";
+            }
+
+            if (rule.getTrafficType() == FirewallRule.TrafficType.Egress) { // Network egress rule
+                srcZone = _privateZone;
+                dstZone = _publicZone;
+                dstAddressXML = "<member>any</member>";
+            } else {
+                srcZone = _publicZone;
+                dstZone = _privateZone;
+                dstAddressXML = "<member>"+rule.getSrcIp()+"</member>";
+            }
+
+            // build the source cidr xml
+            String srcCidrXML = "";
+            List<String> ruleSrcCidrList = rule.getSourceCidrList();
+            if (ruleSrcCidrList.size() > 0) { // a cidr was entered, modify as needed...
+                for (int i = 0; i < ruleSrcCidrList.size(); i++) {
+                    if (ruleSrcCidrList.get(i).trim().equals("0.0.0.0/0")) { // allow any
+                        if (rule.getTrafficType() == FirewallRule.TrafficType.Egress) {
+                            srcCidrXML += "<member>"+getPrivateSubnet(rule.getSrcVlanTag())+"</member>";
+                        } else {
+                            srcCidrXML += "<member>any</member>"; 
+                        }
+                    } else {
+                        srcCidrXML += "<member>"+ruleSrcCidrList.get(i).trim()+"</member>";
+                    }
+                }
+            } else { // no cidr was entered, so allow ALL according to firewall rule type
+                if (rule.getTrafficType() == FirewallRule.TrafficType.Egress) {
+                    srcCidrXML = "<member>"+getPrivateSubnet(rule.getSrcVlanTag())+"</member>";
+                } else {
+                   srcCidrXML = "<member>any</member>"; 
+                }
+            }
+
+            String xml = "";
+            xml += "<from><member>"+srcZone+"</member></from>";
+            xml += "<to><member>"+dstZone+"</member></to>";
+            xml += "<source>"+srcCidrXML+"</source>";
+            xml += "<destination>"+dstAddressXML+"</destination>";
+            xml += "<application>"+appXML+"</application>";
+            xml += "<service>"+serviceXML+"</service>";
+            xml += "<action>allow</action>";
+            xml += "<negate-source>no</negate-source>";
+            xml += "<negate-destination>no</negate-destination>";
+            if (_threatProfile != null) { // add the threat profile if it exists
+                xml += "<profile-setting><group><member>"+_threatProfile+"</member></group></profile-setting>";
+            }
+            if (_logProfile != null) { // add the log profile if it exists
+                xml += "<log-setting>"+_logProfile+"</log-setting>";
+            }
+
+            Map<String, String> a_params = new HashMap<String, String>();
+            a_params.put("type", "config");
+            a_params.put("action", "set");
+            a_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='"+ruleName+"']");
+            a_params.put("element", xml);
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, a_params));
+
+            return true;
+
+        case DELETE:
+            if (!manageFirewallRule(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, rule)) {
+                return true;
+            }
+
+            Map<String, String> d_params = new HashMap<String, String>();
+            d_params.put("type", "config");
+            d_params.put("action", "delete");
+            d_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='"+ruleName+"']");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, d_params));
+
+            return true;
+
+        default:
+            s_logger.debug("Unrecognized command.");
+            return false;
+        }
+    }
+
+
+
+    /*
+     * Usage    
+     */
+
+
+
+    /*
+     * Helper config functions
+     */
+
+    // ensure guest network isolation
+    private String genNetworkIsolationName(long privateVlanTag) {
+        return "isolate_"+Long.toString(privateVlanTag);
+    }
+
+    public boolean manageNetworkIsolation(ArrayList<IPaloAltoCommand> cmdList, PaloAltoPrimative prim, long privateVlanTag, String privateSubnet, String privateGateway) throws ExecutionException {
+        String ruleName = genNetworkIsolationName(privateVlanTag);
+
+        switch (prim) {
+
+        case CHECK_IF_EXISTS:
+            // check if one exists already
+            Map<String, String> params = new HashMap<String, String>();
+            params.put("type", "config");
+            params.put("action", "get");
+            params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='"+ruleName+"']");
+            String response = request(PaloAltoMethod.GET, params);
+            boolean result = (validResponse(response) && responseNotEmpty(response));
+            s_logger.debug("Firewall policy exists: "+ruleName+", "+result);
+            return result;
+
+        case ADD:
+            if (manageNetworkIsolation(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, privateVlanTag, privateSubnet, privateGateway)) {
+                return true;
+            }
+
+            String xml = "";
+            xml += "<from><member>"+_privateZone+"</member></from>";
+            xml += "<to><member>"+_privateZone+"</member></to>";
+            xml += "<source><member>"+privateSubnet+"</member></source>";
+            xml += "<destination><member>"+privateGateway+"</member></destination>";
+            xml += "<application><member>any</member></application>";
+            xml += "<service><member>any</member></service>";
+            xml += "<action>deny</action>";
+            xml += "<negate-source>no</negate-source>";
+            xml += "<negate-destination>yes</negate-destination>";
+
+            Map<String, String> a_params = new HashMap<String, String>();
+            a_params.put("type", "config");
+            a_params.put("action", "set");
+            a_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='"+ruleName+"']");
+            a_params.put("element", xml);
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, a_params));
+
+            return true;
+
+        case DELETE:
+            if (!manageNetworkIsolation(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, privateVlanTag, privateSubnet, privateGateway)) {
+                return true;
+            }
+
+            Map<String, String> d_params = new HashMap<String, String>();
+            d_params.put("type", "config");
+            d_params.put("action", "delete");
+            d_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/rulebase/security/rules/entry[@name='"+ruleName+"']");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.POST, d_params));
+
+            return true;
+
+        default:
+            s_logger.debug("Unrecognized command.");
+            return false;
+        }
+    }
+
+
+    // make the interfaces pingable for basic network troubleshooting
+    public boolean managePingProfile(ArrayList<IPaloAltoCommand> cmdList, PaloAltoPrimative prim) throws ExecutionException {
+        switch (prim) {
+
+        case CHECK_IF_EXISTS:
+            // check if one exists already
+            Map<String, String> params = new HashMap<String, String>();
+            params.put("type", "config");
+            params.put("action", "get");
+            params.put("xpath", "/config/devices/entry/network/profiles/interface-management-profile/entry[@name='"+_pingManagementProfile+"']");
+            String response = request(PaloAltoMethod.GET, params);
+            boolean result = (validResponse(response) && responseNotEmpty(response));
+            s_logger.debug("Management profile exists: "+_pingManagementProfile+", "+result);
+            return result;
+
+        case ADD:
+            if (managePingProfile(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS)) {
+                return true;
+            }
+
+            // add ping profile...
+            Map<String, String> a_params = new HashMap<String, String>();
+            a_params.put("type", "config");
+            a_params.put("action", "set");
+            a_params.put("xpath", "/config/devices/entry/network/profiles/interface-management-profile/entry[@name='"+_pingManagementProfile+"']");
+            a_params.put("element", "<ping>yes</ping>");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, a_params));
+
+            return true;
+
+        case DELETE:
+            if (!managePingProfile(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS)) {
+                return true;
+            }
+
+            // delete ping profile...
+            Map<String, String> d_params = new HashMap<String, String>();
+            d_params.put("type", "config");
+            d_params.put("action", "delete");
+            d_params.put("xpath", "/config/devices/entry/network/profiles/interface-management-profile/entry[@name='"+_pingManagementProfile+"']");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, d_params));
+
+            return true;
+
+        default:
+            s_logger.debug("Unrecognized command.");
+            return false;
+        }
+    }
+
+
+    private String genServiceName(String protocol, String dstPorts, String srcPorts) {
+        String name;
+        if (srcPorts == null) {
+            name = "cs_"+protocol.toLowerCase()+"_"+dstPorts.replace(',', '.');
+        } else {
+            name = "cs_"+protocol.toLowerCase()+"_"+dstPorts.replace(',', '.')+"_"+srcPorts.replace(',', '.');
+        }
+        return name;
+    }
+
+    public boolean manageService(ArrayList<IPaloAltoCommand> cmdList, PaloAltoPrimative prim, String protocol, String dstPorts, String srcPorts) throws ExecutionException {
+        String serviceName = genServiceName(protocol, dstPorts, srcPorts);
+        
+        switch (prim) {
+
+        case CHECK_IF_EXISTS:
+            // check if one exists already
+            Map<String, String> params = new HashMap<String, String>();
+            params.put("type", "config");
+            params.put("action", "get");
+            params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/service/entry[@name='"+serviceName+"']");
+            String response = request(PaloAltoMethod.GET, params);
+            boolean result = (validResponse(response) && responseNotEmpty(response));
+            s_logger.debug("Service exists: "+serviceName+", "+result);
+            return result;
+
+        case ADD:
+            if (manageService(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, protocol, dstPorts, srcPorts)) {
+                return true;
+            }
+
+            String dstPortXML = "<port>"+dstPorts+"</port>";
+            String srcPortXML = "";
+            if (srcPorts != null) {
+                srcPortXML = "<source-port>"+srcPorts+"</source-port>";
+            }
+
+            // add ping profile...
+            Map<String, String> a_params = new HashMap<String, String>();
+            a_params.put("type", "config");
+            a_params.put("action", "set");
+            a_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/service/entry[@name='"+serviceName+"']");
+            a_params.put("element", "<protocol><"+protocol.toLowerCase()+">"+dstPortXML+srcPortXML+"</"+protocol.toLowerCase()+"></protocol>");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, a_params));
+
+            return true;
+
+        case DELETE:
+            if (!manageService(cmdList, PaloAltoPrimative.CHECK_IF_EXISTS, protocol, dstPorts, srcPorts)) {
+                return true;
+            }
+
+            // delete ping profile...
+            Map<String, String> d_params = new HashMap<String, String>();
+            d_params.put("type", "config");
+            d_params.put("action", "delete");
+            d_params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/service/entry[@name='"+serviceName+"']");
+            cmdList.add(new DefaultPaloAltoCommand(PaloAltoMethod.GET, d_params));
+
+            return true;
+
+        default:
+            s_logger.debug("Unrecognized command.");
+            return false;
+        }
+    }
+
+    private String getPrivateSubnet(String vlan) throws ExecutionException {
+        String _interfaceName = genPrivateInterfaceName(Long.valueOf(vlan).longValue());
+        Map<String, String> params = new HashMap<String, String>();
+        params.put("type", "config");
+        params.put("action", "get");
+        params.put("xpath", "/config/devices/entry/network/interface/"+_privateInterfaceType+"/entry[@name='"+_privateInterface+"']/layer3/units/entry[@name='"+_interfaceName+"']/ip/entry");
+        String response = request(PaloAltoMethod.GET, params);
+        if (validResponse(response) && responseNotEmpty(response)) {
+            NodeList response_body;
+            Document doc = getDocument(response);
+            XPath xpath = XPathFactory.newInstance().newXPath();
+            try {
+                XPathExpression expr = xpath.compile("/response[@status='success']/result/entry");
+                response_body = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
+            } catch (XPathExpressionException e) {
+                throw new ExecutionException(e.getCause().getMessage());
+            }
+            if (response_body.getLength() > 0) {
+                return response_body.item(0).getAttributes().getNamedItem("name").getTextContent();
+            } 
+        }
+        return null;
+    }
+
+
+    /*
+     * XML API commands
+     */
+
+    /* Function to make calls to the Palo Alto API. */
+    /* All API calls will end up going through this function. */
+    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 responseBody = "";
+        String debug_msg = "Palo Alto Request\n";
+
+        // a GET method...
+        if (method == PaloAltoMethod.GET) {
+            String queryString = "?";
+            for (String key : params.keySet()) {
+                if (!queryString.equals("?")) {
+                    queryString = queryString + "&";
+                }
+                try {
+                    queryString = queryString + key+"="+URLEncoder.encode(params.get(key), "UTF-8");
+                } catch (UnsupportedEncodingException e) {
+                    throw new ExecutionException(e.getMessage());
+                }
+            }
+            if (_key != null) {
+                queryString = queryString + "&key="+_key;
+            }
+
+            try {
+                debug_msg = debug_msg + "GET request: https://" + _ip + _apiUri + URLDecoder.decode(queryString, "UTF-8") + "\n";
+            } catch (UnsupportedEncodingException e) {
+                debug_msg = debug_msg + "GET request: https://" + _ip + _apiUri + queryString + "\n";
+            }
+            
+
+            HttpGet get_request = new HttpGet("https://" + _ip + _apiUri + queryString);
+            ResponseHandler<String> responseHandler = new BasicResponseHandler();
+            try {
+                responseBody = _httpclient.execute(get_request, responseHandler);
+            } catch (IOException e) {
+                throw new ExecutionException(e.getMessage());
+            }
+        }
+
+        // a POST method...
+        if (method == PaloAltoMethod.POST) {
+            List <NameValuePair> nvps = new ArrayList <NameValuePair>();
+            for (String key : params.keySet()) {
+                nvps.add(new BasicNameValuePair(key, params.get(key)));
+            }
+            if (_key != null) {
+                nvps.add(new BasicNameValuePair("key", _key));
+            }
+
+            debug_msg = debug_msg + "POST request: https://" + _ip + _apiUri + "\n";
+            for (NameValuePair nvp : nvps) {
+                debug_msg = debug_msg + "param: "+nvp.getName()+", "+nvp.getValue() + "\n";
+            }
+
+            HttpPost post_request = new HttpPost("https://" + _ip + _apiUri);
+            try {
+                post_request.setEntity(new UrlEncodedFormEntity(nvps, HTTP.UTF_8));
+            } catch (UnsupportedEncodingException e) {
+                throw new ExecutionException(e.getMessage());
+            }
+            ResponseHandler<String> responseHandler = new BasicResponseHandler();
+            try {
+                responseBody = _httpclient.execute(post_request, responseHandler);
+            } catch (IOException e) {
+                throw new ExecutionException(e.getMessage());
+            }
+        }
+
+        debug_msg = debug_msg + prettyFormat(responseBody);
+        debug_msg = debug_msg + "\n" + responseBody.replace("\"", "\\\"") + "\n\n"; // test cases
+        //s_logger.debug(debug_msg); // this can be commented if we don't want to show each request in the log.
+        
+        return responseBody;
+    }
+    
+    /* Used for requests that require polling to get a result (eg: commit) */
+    private String requestWithPolling(PaloAltoMethod method, Map<String, String> params) throws ExecutionException {
+        String job_id;
+        String job_response = request(method, params);
+        Document doc = getDocument(job_response);
+        XPath xpath = XPathFactory.newInstance().newXPath();
+        try {
+            XPathExpression expr = xpath.compile("/response[@status='success']/result/job/text()");
+            job_id = (String) expr.evaluate(doc, XPathConstants.STRING);
+        } catch (XPathExpressionException e) {
+            throw new ExecutionException(e.getCause().getMessage());
+        }
+        if (job_id.length() > 0) {
+            boolean finished = false;
+            Map<String, String> job_params = new HashMap<String, String>();
+            job_params.put("type", "op");
+            job_params.put("cmd", "<show><jobs><id>"+job_id+"</id></jobs></show>");
+
+            while (!finished) {
+                String job_status;
+                String response = request(PaloAltoMethod.GET, job_params);
+                Document job_doc = getDocument(response);
+                XPath job_xpath = XPathFactory.newInstance().newXPath();
+                try {
+                    XPathExpression expr = job_xpath.compile("/response[@status='success']/result/job/status/text()");
+                    job_status = (String) expr.evaluate(job_doc, XPathConstants.STRING);
+                } catch (XPathExpressionException e) {
+                    throw new ExecutionException(e.getCause().getMessage());
+                }
+                if (job_status.equals("FIN")) {
+                    finished = true;
+                    String job_result;
+                    try {
+                        XPathExpression expr = job_xpath.compile("/response[@status='success']/result/job/result/text()");
+                        job_result = (String) expr.evaluate(job_doc, XPathConstants.STRING);
+                    } catch (XPathExpressionException e) {
+                        throw new ExecutionException(e.getCause().getMessage());
+                    }
+                    if (!job_result.equals("OK")) {
+                        NodeList job_details;
+                        try {
+                            XPathExpression expr = job_xpath.compile("/response[@status='success']/result/job/details/line");
+                            job_details = (NodeList) expr.evaluate(job_doc, XPathConstants.NODESET);
+                        } catch (XPathExpressionException e) {
+                            throw new ExecutionException(e.getCause().getMessage());
+                        }
+                        String error = "";
+                        for (int i = 0; i < job_details.getLength(); i++) {
+                            error = error + job_details.item(i).getTextContent() + "\n";
+                        }
+                        throw new ExecutionException(error);
+                    }
+                    return response;
+                } else {
+                    try {
+                        Thread.sleep(2000); // poll periodically for the status of the async job...
+                    } catch (InterruptedException e) { /* do nothing */ }
+                }
+            }
+        } else {
+            return job_response;
+        }
+        return null;
+    }
+
+    /* Runs a sequence of commands and attempts to commit at the end. */
+    /* Uses the Command pattern to enable overriding of the response handling if needed. */
+    private synchronized boolean requestWithCommit(ArrayList<IPaloAltoCommand> commandList) throws ExecutionException {
+        boolean result = true;
+
+        if (commandList.size() > 0) {
+            // CHECK IF THERE IS PENDING CHANGES THAT HAVE NOT BEEN COMMITTED...
+            String pending_changes;
+            Map<String, String> check_params = new HashMap<String, String>();
+            check_params.put("type", "op");
+            check_params.put("cmd", "<check><pending-changes></pending-changes></check>");
+            String check_response = request(PaloAltoMethod.GET, check_params); 
+            Document check_doc = getDocument(check_response);
+            XPath check_xpath = XPathFactory.newInstance().newXPath();
+            try {
+                XPathExpression expr = check_xpath.compile("/response[@status='success']/result/text()");
+                pending_changes = (String) expr.evaluate(check_doc, XPathConstants.STRING);
+            } catch (XPathExpressionException e) {
+                throw new ExecutionException(e.getCause().getMessage());
+            }
+            if (pending_changes.equals("yes")) {
+                throw new ExecutionException("The Palo Alto has uncommited changes, so no changes can be made.  Try again later or contact your administrator.");
+            } else {
+                // ADD A CONFIG LOCK TO CAPTURE THE PALO ALTO RESOURCE
+                String add_lock_status;
+                Map<String, String> add_lock_params = new HashMap<String, String>();
+                add_lock_params.put("type", "op");
+                add_lock_params.put("cmd", "<request><config-lock><add></add></config-lock></request>");
+                String add_lock_response = request(PaloAltoMethod.GET, add_lock_params); 
+                Document add_lock_doc = getDocument(add_lock_response);
+                XPath add_lock_xpath = XPathFactory.newInstance().newXPath();
+                try {
+                    XPathExpression expr = add_lock_xpath.compile("/response[@status='success']/result/text()");
+                    add_lock_status = (String) expr.evaluate(add_lock_doc, XPathConstants.STRING);
+                } catch (XPathExpressionException e) {
+                    throw new ExecutionException(e.getCause().getMessage());
+                }
+                if (add_lock_status.length() == 0) {
+                    throw new ExecutionException("The Palo Alto is locked, no changes can be made at this time.");
+                }
+
+                try {
+                    // RUN THE SEQUENCE OF COMMANDS
+                    for (IPaloAltoCommand command : commandList) {
+                        result = (result && command.execute()); // run commands and modify result boolean
+                    }
+
+                    // COMMIT THE CHANGES (ALSO REMOVES CONFIG LOCK)
+                    String commit_job_id;
+                    Map<String, String> commit_params = new HashMap<String, String>();
+                    commit_params.put("type", "commit");
+                    commit_params.put("cmd", "<commit></commit>");
+                    String commit_response = requestWithPolling(PaloAltoMethod.GET, commit_params);
+                    Document commit_doc = getDocument(commit_response);
+                    XPath commit_xpath = XPathFactory.newInstance().newXPath();
+                    try {
+                        XPathExpression expr = commit_xpath.compile("/response[@status='success']/result/job/id/text()");
+                        commit_job_id = (String) expr.evaluate(commit_doc, XPathConstants.STRING);
+                    } catch (XPathExpressionException e) {
+                        throw new ExecutionException(e.getCause().getMessage());
+                    }
+                    if (commit_job_id.length() == 0) { // no commit was done, so release the lock...
+                        // REMOVE THE CONFIG LOCK TO RELEASE THE PALO ALTO RESOURCE
+                        String remove_lock_status;
+                        Map<String, String> remove_lock_params = new HashMap<String, String>();
+                        remove_lock_params.put("type", "op");
+                        remove_lock_params.put("cmd", "<request><config-lock><remove></remove></config-lock></request>");
+                        String remove_lock_response = request(PaloAltoMethod.GET, remove_lock_params); 
+                        Document remove_lock_doc = getDocument(remove_lock_response);
+                        XPath remove_lock_xpath = XPathFactory.newInstance().newXPath();
+                        try {
+                            XPathExpression expr = remove_lock_xpath.compile("/response[@status='success']/result/text()");
+                            remove_lock_status = (String) expr.evaluate(remove_lock_doc, XPathConstants.STRING);
+                        } catch (XPathExpressionException e) {
+                            throw new ExecutionException(e.getCause().getMessage());
+                        }
+                        if (remove_lock_status.length() == 0) {
+                            throw new ExecutionException("Could not release the Palo Alto device.  Please notify an administrator!");
+                        }
+                    }
+                    
+                } catch (ExecutionException ex) {
+                    // REVERT TO RUNNING
+                    String revert_job_id;
+                    Map<String, String> revert_params = new HashMap<String, String>();
+                    revert_params.put("type", "op");
+                    revert_params.put("cmd", "<load><config><from>running-config.xml</from></config></load>");
+                    requestWithPolling(PaloAltoMethod.GET, revert_params);
+
+                    // REMOVE THE CONFIG LOCK TO RELEASE THE PALO ALTO RESOURCE
+                    String remove_lock_status;
+                    Map<String, String> remove_lock_params = new HashMap<String, String>();
+                    remove_lock_params.put("type", "op");
+                    remove_lock_params.put("cmd", "<request><config-lock><remove></remove></config-lock></request>");
+                    String remove_lock_response = request(PaloAltoMethod.GET, remove_lock_params); 
+                    Document remove_lock_doc = getDocument(remove_lock_response);
+                    XPath remove_lock_xpath = XPathFactory.newInstance().newXPath();
+                    try {
+                        XPathExpression expr = remove_lock_xpath.compile("/response[@status='success']/result/text()");
+                        remove_lock_status = (String) expr.evaluate(remove_lock_doc, XPathConstants.STRING);
+                    } catch (XPathExpressionException e) {
+                        throw new ExecutionException(e.getCause().getMessage());
+                    }
+                    if (remove_lock_status.length() == 0) {
+                        throw new ExecutionException("Could not release the Palo Alto device.  Please notify an administrator!");
+                    }
+
+                    throw ex; // Bubble up the reason we reverted...
+                }
+
+                return result;
+            }
+        } else {
+            return true; // nothing to do
+        }
+    }
+
+    /* A default response handler to validate that the request was successful. */
+    public boolean validResponse(String response) throws ExecutionException {
+        NodeList response_body;
+        Document doc = getDocument(response);
+        XPath xpath = XPathFactory.newInstance().newXPath();
+        try {
+            XPathExpression expr = xpath.compile("/response[@status='success']");
+            response_body = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
+        } catch (XPathExpressionException e) {
+            throw new ExecutionException(e.getCause().getMessage());
+        }
+
+        if (response_body.getLength() > 0) {
+            return true;
+        } else {
+            NodeList error_details;
+            try {
+                XPathExpression expr = xpath.compile("/response/msg/line/line");
+                error_details = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
+            } catch (XPathExpressionException e) {
+                throw new ExecutionException(e.getCause().getMessage());
+            }
+            if (error_details.getLength() == 0) {
+                try {
+                    XPathExpression expr = xpath.compile("/response/msg/line");
+                    error_details = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
+                } catch (XPathExpressionException e) {
+                    throw new ExecutionException(e.getCause().getMessage());
+                }
+
+                if (error_details.getLength() == 0) {
+                    try {
+                        XPathExpression expr = xpath.compile("/response/result/msg");
+                        error_details = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
+                    } catch (XPathExpressionException e) {
+                        throw new ExecutionException(e.getCause().getMessage());
+                    }
+                }
+            }
+            String error = "";
+            for (int i = 0; i < error_details.getLength(); i++) {
+                error = error + error_details.item(i).getTextContent() + "\n";
+            }
+            throw new ExecutionException(error);
+        }
+    }
+
+    /* Validate that the response is not empty. */
+    public boolean responseNotEmpty(String response) throws ExecutionException {
+        NodeList response_body;
+        Document doc = getDocument(response);
+        XPath xpath = XPathFactory.newInstance().newXPath();
+        try {
+            XPathExpression expr = xpath.compile("/response[@status='success']");
+            response_body = (NodeList) expr.evaluate(doc, XPathConstants.NODESET);
+        } catch (XPathExpressionException e) {
+            throw new ExecutionException(e.getCause().getMessage());
+        }
+
+        if (response_body.getLength() > 0 && 
+            (!response_body.item(0).getTextContent().equals("") || 
+                (response_body.item(0).hasChildNodes() && response_body.item(0).getFirstChild().hasChildNodes()))) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /* Get the type of interface from the PA device. */
+    private String getInterfaceType(String interface_name) throws ExecutionException {
+        String[] types = { InterfaceType.ETHERNET.toString(), InterfaceType.AGGREGATE.toString() };
+        for (String type : types) {
+            Map<String, String> params = new HashMap<String, String>();
+            params.put("type", "config");
+            params.put("action", "get");
+            params.put("xpath", "/config/devices/entry/network/interface/"+type+"/entry[@name='"+interface_name+"']");
+            String ethernet_response = request(PaloAltoMethod.GET, params);
+            if (validResponse(ethernet_response) && responseNotEmpty(ethernet_response)) {
+                return type;
+            }
+        }
+        return "";
+    }
+
+    /* Get the threat profile from the server if it exists. */
+    private boolean getThreatProfile(String profile) throws ExecutionException {
+        Map<String, String> params = new HashMap<String, String>();
+        params.put("type", "config");
+        params.put("action", "get");
+        params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/profile-group/entry[@name='"+profile+"']");
+        String response = request(PaloAltoMethod.GET, params);
+        return (validResponse(response) && responseNotEmpty(response));
+    }
+
+    /* Get the log profile from the server if it exists. */
+    private boolean getLogProfile(String profile) throws ExecutionException {
+        Map<String, String> params = new HashMap<String, String>();
+        params.put("type", "config");
+        params.put("action", "get");
+        params.put("xpath", "/config/devices/entry/vsys/entry[@name='vsys1']/log-settings/profiles/entry[@name='"+profile+"']");
+        String response = request(PaloAltoMethod.GET, params);
+        return (validResponse(response) && responseNotEmpty(response));
+    }
+
+    /* Command Interface */
+    public interface IPaloAltoCommand {
+        public boolean execute() throws ExecutionException;
+    }
+
+    /* Command Abstract */
+    private abstract class AbstractPaloAltoCommand implements IPaloAltoCommand {
+        PaloAltoMethod method;
+        Map<String, String> params;
+        
+        public AbstractPaloAltoCommand() {}
+
+        public AbstractPaloAltoCommand(PaloAltoMethod method, Map<String, String> params) {
+            this.method = method;
+            this.params = params;
+        }
+
+        public boolean execute() throws ExecutionException {
+            String response = request(method, params);
+            return validResponse(response);
+        }
+    }
+
+    /* Implement the default functionality */
+    private class DefaultPaloAltoCommand extends AbstractPaloAltoCommand {
+        public DefaultPaloAltoCommand(PaloAltoMethod method, Map<String, String> params) {
+            super(method, params);
+        }
+    }
+
+
+    /*
+     * Misc
+     */    
+    
+    private String genIpIdentifier(String ip) {
+        return ip.r

<TRUNCATED>