Browse Source

Add ml2\l3\qos\fwaas implements

1. zte driver of ml2 plugin to send networks\subnets\sgs\sg rules\ports to zenic controller
2. zte zenic agent of neutron l3 agent to send router info to zenic controller
3. common code is rest api
4. fwaas implements fwaas 1.0 functions
5. tools contain some install scripts

Change-Id: I93d193e79624c8d5b1f1ef84c7ec158a92150bff
hui_liu 1 month ago
parent
commit
2486d0b331
43 changed files with 6750 additions and 581 deletions
  1. 10
    0
      etc/neutron-zenic-agent
  2. 147
    0
      etc/neutron-zenic-agent-script
  3. 23
    0
      etc/neutron-zenic-agent.conf
  4. 12
    0
      etc/neutron-zenic-agent.service
  5. 0
    19
      networking_zte/__init__.py
  6. 0
    495
      networking_zte/common/rest/znic_l2/znic_l2restconf.py
  7. 138
    48
      networking_zte/common/servermanager.py
  8. 330
    0
      networking_zte/fwaas/zenic_firewall_pool.py
  9. 282
    0
      networking_zte/fwaas/zenic_fwaas_plugin.py
  10. 196
    0
      networking_zte/l3/all_l3_agents_scheduler.py
  11. 789
    0
      networking_zte/l3/zenic_agent.py
  12. 0
    0
      networking_zte/ml2/common/__init__.py
  13. 0
    0
      networking_zte/ml2/common/rest/__init__.py
  14. 0
    0
      networking_zte/ml2/common/rest/ml2_zenic/__init__.py
  15. 105
    0
      networking_zte/ml2/common/rest/ml2_zenic/config.py
  16. 37
    16
      networking_zte/ml2/common/rest/ml2_zenic/mech_zenic_l2.py
  17. 749
    0
      networking_zte/ml2/common/rest/ml2_zenic/ml2_zenic_restconf.py
  18. 107
    0
      networking_zte/ml2/driver_api.py
  19. 94
    0
      networking_zte/ml2/driver_context.py
  20. 1035
    0
      networking_zte/ml2/ml2_neutron_driver.py
  21. 162
    0
      networking_zte/ml2/sync_filter.py
  22. 0
    0
      networking_zte/qos/__init__.py
  23. 233
    0
      networking_zte/qos/zenic_qos_plugin.py
  24. 215
    0
      networking_zte/qos/zenic_qos_pool.py
  25. 0
    0
      networking_zte/utils/__init__.py
  26. 33
    0
      networking_zte/utils/cmcc_util.py
  27. 9
    0
      setup.cfg
  28. 176
    0
      tools/LICENSE
  29. 0
    0
      tools/config.py
  30. 9
    0
      tools/dos2unix.sh
  31. 11
    0
      tools/l3_scheduler.patch
  32. 11
    0
      tools/l3_scheduler_k.patch
  33. 11
    0
      tools/l3_scheduler_l.patch
  34. 11
    0
      tools/l3_scheduler_m.patch
  35. 10
    0
      tools/l3_scheduler_n.patch
  36. 10
    0
      tools/l3_scheduler_o.patch
  37. 221
    0
      tools/mech_agent.py
  38. 19
    0
      tools/pep8_format.sh
  39. 103
    0
      tools/qos.patch
  40. 240
    0
      tools/sdn_patch_api.py
  41. 1
    0
      tools/version.info
  42. 1198
    0
      tools/zenic_plugin_install.py
  43. 13
    3
      tox.ini

+ 10
- 0
etc/neutron-zenic-agent View File

@@ -0,0 +1,10 @@
1
+#!/usr/bin/python
2
+# PBR Generated from u'console_scripts'
3
+
4
+import sys
5
+
6
+from networking_zte.l3.zenic_agent import main
7
+
8
+
9
+if __name__ == "__main__":
10
+    sys.exit(main())

+ 147
- 0
etc/neutron-zenic-agent-script View File

@@ -0,0 +1,147 @@
1
+#!/bin/sh
2
+### BEGIN INIT INFO
3
+# Provides:          neutron-zenic-agent
4
+# Required-Start:    $network $local_fs $remote_fs $syslog
5
+# Required-Stop:     $remote_fs
6
+# Should-Start:      mysql postgresql rabbitmq-server keystone openvswitch-switch neutron-ovs-cleanup
7
+# Should-Stop:       mysql postgresql rabbitmq-server keystone openvswitch-switch
8
+# Default-Start:     2 3 4 5
9
+# Default-Stop:      0 1 6
10
+# Short-Description: Neutron zenic agent
11
+# Description:       Provide zenic agent for neutron
12
+### END INIT INFO
13
+
14
+# Authors: Mehdi Abaakouk <sileht@sileht.net>
15
+#          Thomas Goirand <zigo@debian.org>
16
+
17
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
18
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
19
+DESC="OpenStack Neutron zenic agent"
20
+PROJECT_NAME=neutron
21
+NAME=${PROJECT_NAME}-zenic-agent
22
+# --config-file=/etc/neutron/neutron.conf will be happened 
23
+# to DAEMON_ARGS later by openstack-pkg-tools
24
+DAEMON_ARGS="--config-file=/etc/neutron/plugin.ini"
25
+#!/bin/sh
26
+# The content after this line comes from openstack-pkg-tools
27
+# and has been automatically added to a .init.in script, which
28
+# contains only the descriptive part for the daemon. Everything
29
+# else is standardized as a single unique script.
30
+
31
+# Author: Thomas Goirand <zigo@debian.org>
32
+
33
+# PATH should only include /usr/* if it runs after the mountnfs.sh script
34
+PATH=/sbin:/usr/sbin:/bin:/usr/bin
35
+
36
+if [ -z "${DAEMON}" ] ; then
37
+        DAEMON=/usr/bin/${NAME}
38
+fi
39
+PIDFILE=/var/run/${PROJECT_NAME}/${NAME}.pid
40
+if [ -z "${SCRIPTNAME}" ] ; then
41
+        SCRIPTNAME=/etc/init.d/${NAME}
42
+fi
43
+if [ -z "${SYSTEM_USER}" ] ; then
44
+        SYSTEM_USER=${PROJECT_NAME}
45
+fi
46
+if [ -z "${SYSTEM_USER}" ] ; then
47
+        SYSTEM_GROUP=${PROJECT_NAME}
48
+fi
49
+if [ "${SYSTEM_USER}" != "root" ] ; then
50
+        STARTDAEMON_CHUID="--chuid ${SYSTEM_USER}:${SYSTEM_GROUP}"
51
+fi
52
+if [ -z "${CONFIG_FILE}" ] ; then
53
+        CONFIG_FILE=/etc/${PROJECT_NAME}/${PROJECT_NAME}.conf
54
+fi
55
+LOGFILE=/var/log/${PROJECT_NAME}/${NAME}.log
56
+if [ -z "${NO_OPENSTACK_CONFIG_FILE_DAEMON_ARG}" ] ; then
57
+        DAEMON_ARGS="${DAEMON_ARGS} --config-file=${CONFIG_FILE}"
58
+fi
59
+
60
+# Exit if the package is not installed
61
+[ -x $DAEMON ] || exit 0
62
+
63
+# If ran as root, create /var/lock/X, /var/run/X, /var/lib/X and /var/log/X as needed
64
+if [ `whoami` = "root" ] ; then
65
+        for i in lock run log lib ; do
66
+                mkdir -p /var/$i/${PROJECT_NAME}
67
+                chown ${SYSTEM_USER} /var/$i/${PROJECT_NAME}
68
+        done
69
+fi
70
+
71
+# This defines init_is_upstart which we use later on (+ more...)
72
+. /lib/lsb/init-functions
73
+
74
+# Manage log options: logfile and/or syslog, depending on user's choosing
75
+[ -r /etc/default/openstack ] && . /etc/default/openstack
76
+[ -r /etc/default/$NAME ] && . /etc/default/$NAME
77
+[ "x$USE_SYSLOG" = "xyes" ] && DAEMON_ARGS="$DAEMON_ARGS --use-syslog"
78
+[ "x$USE_LOGFILE" != "xno" ] && DAEMON_ARGS="$DAEMON_ARGS --log-file=$LOGFILE"
79
+
80
+do_start() {
81
+        start-stop-daemon --start  ${STARTDAEMON_CHUID} --make-pidfile --pidfile ${PIDFILE} --chdir /var/
82
+lib/${PROJECT_NAME} --startas $DAEMON \
83
+                        --test > /dev/null || return 1
84
+        start-stop-daemon --start   ${STARTDAEMON_CHUID} --make-pidfile --pidfile ${PIDFILE} --chdir /var/
85
+lib/${PROJECT_NAME} --startas $DAEMON \
86
+                        -- $DAEMON_ARGS || return 2
87
+}
88
+
89
+do_stop() {
90
+        start-stop-daemon --stop --quiet --retry=TERM/30/KILL/5 --pidfile $PIDFILE
91
+        RETVAL=$?
92
+        rm -f $PIDFILE
93
+        return "$RETVAL"
94
+}
95
+
96
+do_systemd_start() {
97
+        exec $DAEMON $DAEMON_ARGS
98
+}
99
+
100
+case "$1" in
101
+start)
102
+        init_is_upstart > /dev/null 2>&1 && exit 1
103
+        log_daemon_msg "Starting $DESC" "$NAME"
104
+        do_start
105
+        case $? in
106
+                0|1) log_end_msg 0 ;;
107
+                2) log_end_msg 1 ;;
108
+        esac
109
+;;
110
+stop)
111
+        init_is_upstart > /dev/null 2>&1 && exit 0
112
+        log_daemon_msg "Stopping $DESC" "$NAME"
113
+        do_stop
114
+        case $? in
115
+                0|1) log_end_msg 0 ;;
116
+                2) log_end_msg 1 ;;
117
+        esac
118
+;;
119
+status)
120
+        status_of_proc "$DAEMON" "$NAME" && exit 0 || exit $?
121
+;;
122
+systemd-start)
123
+        do_systemd_start
124
+;;  
125
+restart|force-reload)
126
+        init_is_upstart > /dev/null 2>&1 && exit 1
127
+        log_daemon_msg "Restarting $DESC" "$NAME"
128
+        do_stop
129
+        case $? in
130
+        0|1)
131
+                do_start
132
+                case $? in
133
+                        0) log_end_msg 0 ;;
134
+                        1) log_end_msg 1 ;; # Old process is still running
135
+                        *) log_end_msg 1 ;; # Failed to start
136
+                esac
137
+        ;;
138
+        *) log_end_msg 1 ;; # Failed to stop
139
+        esac
140
+;;
141
+*)
142
+        echo "Usage: $SCRIPTNAME  {start|stop|status|restart|force-reload|systemd-start}" >&2
143
+        exit 3
144
+;;
145
+esac
146
+
147
+exit 0

+ 23
- 0
etc/neutron-zenic-agent.conf View File

@@ -0,0 +1,23 @@
1
+# vim:set ft=upstart ts=2 et:
2
+description "Neutron zenic Agent"
3
+author "Chuck Short <zulcss@ubuntu.com>"
4
+
5
+start on runlevel [2345]
6
+stop on runlevel [!2345]
7
+
8
+respawn
9
+
10
+chdir /var/run
11
+
12
+pre-start script
13
+  mkdir -p /var/run/neutron
14
+  chown neutron:root /var/run/neutron
15
+  # Check to see if openvswitch plugin in use by checking
16
+  # status of cleanup upstart configuration
17
+  if status neutron-ovs-cleanup; then
18
+    start wait-for-state WAIT_FOR=neutron-ovs-cleanup WAIT_STATE=running WAITER=neutron-zenic-agent
19
+  fi
20
+end script
21
+
22
+exec start-stop-daemon --start --chuid neutron --exec /usr/bin/neutron-zenic-agent -- \
23
+--config-file=/etc/neutron/neutron.conf --config-file=/etc/neutron/plugin.ini --log-file=/var/log/neutron/zenic-agent.log

+ 12
- 0
etc/neutron-zenic-agent.service View File

@@ -0,0 +1,12 @@
1
+[Unit]
2
+Description=OpenStack Neutron Zenic Layer 3 Agent
3
+After=syslog.target network.target
4
+
5
+[Service]
6
+Type=simple
7
+User=neutron
8
+ExecStart=/usr/bin/neutron-zenic-agent --log-file /var/log/neutron/zenic-agent.log
9
+PrivateTmp=false
10
+
11
+[Install]
12
+WantedBy=multi-user.target

+ 0
- 19
networking_zte/__init__.py View File

@@ -1,19 +0,0 @@
1
-# -*- coding: utf-8 -*-
2
-
3
-# Licensed under the Apache License, Version 2.0 (the "License"); you may
4
-# not use this file except in compliance with the License. You may obtain
5
-# a copy of the License at
6
-#
7
-#      http://www.apache.org/licenses/LICENSE-2.0
8
-#
9
-# Unless required by applicable law or agreed to in writing, software
10
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
-# License for the specific language governing permissions and limitations
13
-# under the License.
14
-
15
-import pbr.version
16
-
17
-
18
-__version__ = pbr.version.VersionInfo(
19
-    'networking_zte').version_string()

+ 0
- 495
networking_zte/common/rest/znic_l2/znic_l2restconf.py View File

@@ -1,495 +0,0 @@
1
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
-#
3
-# Copyright 2014 Big Switch Networks, Inc.
4
-# All Rights Reserved.
5
-#
6
-#    Licensed under the Apache License, Version 2.0 (the "License"); you may
7
-#    not use this file except in compliance with the License. You may obtain
8
-#    a copy of the License at
9
-#
10
-#         http://www.apache.org/licenses/LICENSE-2.0
11
-#
12
-#    Unless required by applicable law or agreed to in writing, software
13
-#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
-#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
-#    License for the specific language governing permissions and limitations
16
-#    under the License.
17
-
18
-
19
-from neutron.db import common_db_mixin as base_db
20
-# from neutron.openstack.common import log
21
-from neutron.plugins.proxydriver.common.rest import servermanager
22
-from oslo_log import log
23
-
24
-from neutron.extensions import portsecurity as psec
25
-
26
-LOG = log.getLogger(__name__)
27
-
28
-# The following are used to invoke the API on the external controller
29
-TENANT = 'tenant'
30
-NETWORK = 'network'
31
-SUBNET = 'subnet'
32
-PORT = 'port'
33
-ROUTER = 'router'
34
-FLOATING_IP = 'floating-ip'
35
-VXLAN_TUNNEL = 'vxlan-tunnel'
36
-SECURITY_GROUP = 'sg'
37
-SECURITY_GROUP_RULE = 'sg-rule'
38
-CLASSIFIER = 'classifier'
39
-
40
-BASE_URI = '/restconf/operations/zenic-vdcapp-model:'
41
-SUCCESS_CODES = range(200, 207)
42
-FAILURE_CODES = [0, 9, 301, 302, 303, 400, 401, 403, 404, 500, 501, 502, 503,
43
-                 504, 505]
44
-
45
-
46
-class ZnicServerPool(servermanager.ServerPool, base_db.CommonDbMixin):
47
-    """Znic Server Pool for Znic Mechanism Driver.
48
-
49
-    This server pool has the network,subnet,port and security group operations
50
-    of create, update and delete, to the Znic Controller.
51
-    """
52
-    def __init__(self, servers, auth, zenic_version, ssl, no_ssl_validation,
53
-                 ssl_sticky, ssl_cert_directory, consistency_interval,
54
-                 timeout=False, cache_connections=True, base_uri=BASE_URI,
55
-                 success_codes=SUCCESS_CODES,
56
-                 failure_codes=FAILURE_CODES, name='ZnicRestProxy'):
57
-        super(ZnicServerPool, self).__init__(
58
-            servers, auth, ssl, no_ssl_validation, ssl_sticky,
59
-            ssl_cert_directory, consistency_interval, timeout,
60
-            cache_connections, base_uri, success_codes, failure_codes, name)
61
-        version = zenic_version.split('.')
62
-        version = version[0] + version[1]
63
-        if (not version.isdigit()) or (int(version) < 403):
64
-            LOG.error(_("zenic_version error!zenic_version = %s"), version)
65
-        self.zenic_version = int(version)
66
-
67
-    def validate_dict(self, instance, key, default_val):
68
-        return instance[key] if (key in instance and
69
-                                 instance[key] is not None) else default_val
70
-
71
-    def validate_ipv4(self, ip_in, default_val):
72
-        return ip_in if (ip_in != 0 and (ip_in is not None)) else default_val
73
-
74
-    def construct_network_info(self, mech_context, action):
75
-        network = mech_context.current
76
-        context = mech_context._plugin_context
77
-        # validate tenant
78
-        tenant_id = self._get_tenant_id_for_create(context, network)
79
-
80
-        if action == 'DELETE' or action == 'GET':
81
-            network_info = {
82
-                "input": {
83
-                    "id": network['id']
84
-                }
85
-            }
86
-        else:
87
-            network_info = {
88
-                "input": {
89
-                    "id": network['id'],
90
-                    "name": network['name'],
91
-                    "admin_state_up": network['admin_state_up'],
92
-                    "tenant_id": tenant_id,
93
-                    "shared": network['shared'],
94
-                    "band_width": self.validate_dict(network, 'bandwidth', 0),
95
-                    "burst_size": self.validate_dict(network, 'cbs', 0),
96
-                    "dscp": self.validate_dict(network, 'dscp', 0),
97
-                    "external":
98
-                        self.validate_dict(network, 'router:external', False),
99
-                }
100
-            }
101
-
102
-            input = network_info['input']
103
-            if network.get('provider:network_type') != "flat":
104
-                input['segmentation_id'] = \
105
-                    mech_context.network_segments[0]['segmentation_id']
106
-
107
-            if self.zenic_version > 403:
108
-                if 'mtu' in network:
109
-                    input['mtu'] = self.validate_dict(network, "mtu", 0)
110
-
111
-        if action == 'POST':
112
-            input = network_info['input']
113
-            if self.zenic_version > 403:
114
-                if 'port_security_enabled' in network and \
115
-                        self.en_security_group:
116
-                    input['port_security_enabled'] = \
117
-                        self.validate_dict(network, psec.PORTSECURITY, True)
118
-        return network_info
119
-
120
-    def construct_subnet_info(self, mech_context, action):
121
-        subnet = mech_context.current
122
-        context = mech_context._plugin_context
123
-        # validate tenant
124
-        tenant_id = self._get_tenant_id_for_create(context, subnet)
125
-
126
-        if action == 'DELETE' or action == 'GET':
127
-            subnet_info = {
128
-                "input": {
129
-                    "id": subnet['id']
130
-                }
131
-            }
132
-        else:
133
-            if subnet['ip_version'] == 6:
134
-                gateway_default = "::"
135
-            else:
136
-                gateway_default = "0.0.0.0"
137
-
138
-            subnet_info = {
139
-                "input": {
140
-                    "id": subnet['id'],
141
-                    "subnet_name": subnet['name'],
142
-                    # "network_id": subnet['network_id'],
143
-                    # "tenant_id": tenant_id,
144
-                    "dns_nameservers": ','.join(subnet['dns_nameservers']),
145
-                    "allocation_pools": subnet['allocation_pools'],
146
-                    "host_routes":
147
-                        '\r\n'.join(','.join([route.get("destination", ""),
148
-                                              route.get("nexthop", "")])
149
-                                    for route in self.validate_dict(
150
-                            subnet, 'host_routes', [])),
151
-                    # "ip_version": subnet['ip_version'],
152
-                    "gateway_ip": self.validate_ipv4(
153
-                        subnet['gateway_ip'], gateway_default),
154
-                    # "cidr": subnet['cidr']
155
-                }
156
-            }
157
-
158
-        if action == 'POST':
159
-            input = subnet_info['input']
160
-            input['network_id'] = subnet['network_id']
161
-            input['tenant_id'] = tenant_id
162
-            input['cidr'] = subnet['cidr']
163
-            input['ip_version'] = subnet['ip_version']
164
-
165
-        return subnet_info
166
-
167
-    def construct_port_info(self, mech_context, action):
168
-        port = mech_context.current
169
-        context = mech_context._plugin_context
170
-        # validate tenant
171
-        tenant_id = self._get_tenant_id_for_create(context, port)
172
-
173
-        if action == 'DELETE' or action == 'GET':
174
-            port_info = {
175
-                "input": {
176
-                    "id": port["id"]
177
-                }
178
-            }
179
-        else:
180
-            if not self.en_security_group:
181
-                port["security_groups"] = []
182
-            port_info = {
183
-                "input": {
184
-                    "id": port['id'],
185
-                    "name": port['name'],
186
-                    "allowed_address_pairs":
187
-                        [{'ip_address': pairs['ip_address'],
188
-                          'mac_address': pairs['mac_address']}
189
-                         for pairs in port['allowed_address_pairs']],
190
-                    "admin_state_up": port["admin_state_up"],
191
-                    # "network_id": port["network_id"],
192
-                    # "tenant_id": tenant_id,
193
-                    # "mac_address": port["mac_address"],
194
-                    "binding_profile": str(port['binding:profile']),
195
-                    "device_owner": port["device_owner"],
196
-                    "fixed_ips": [{'subnet_id': ip["subnet_id"],
197
-                                   'ip_address': ip["ip_address"]}
198
-                                  for ip in port["fixed_ips"]],
199
-                    "security_groups": port["security_groups"],
200
-                    "band_width": self.validate_dict(port, 'bandwidth', 0),
201
-                    "burst_size": self.validate_dict(port, 'cbs', 0),
202
-                    "dscp": self.validate_dict(port, 'dscp', 0),
203
-                }
204
-            }
205
-
206
-        if action == 'POST' or action == 'PUT':
207
-            input = port_info['input']
208
-            if self.zenic_version > 403:
209
-                if 'extra_dhcp_opts' in port:
210
-                    input['extra_dhcp_opts'] = [{'opt_value':
211
-                                                dhcp["opt_value"],
212
-                                                 'ip_version':
213
-                                                dhcp["ip_version"],
214
-                                                 'opt_name':
215
-                                                dhcp["opt_name"]}
216
-                                                for dhcp in
217
-                                                port["extra_dhcp_opts"]]
218
-
219
-        if action == 'POST':
220
-            input = port_info['input']
221
-            input['network_id'] = port['network_id']
222
-            input['tenant_id'] = tenant_id
223
-            input['mac_address'] = port['mac_address']
224
-            if self.zenic_version > 403:
225
-                if 'port_security_enabled' in port and self.en_security_group:
226
-                    input['port_security_enabled'] = \
227
-                        self.validate_dict(port, psec.PORTSECURITY, True)
228
-        return port_info
229
-
230
-    def construct_securitygroup_info(self, mech_context, action):
231
-        sg = mech_context.current
232
-        context = mech_context._plugin_context
233
-        # validate tenant
234
-        tenant_id = self._get_tenant_id_for_create(context, sg)
235
-
236
-        if action == 'DELETE' or action == 'GET':
237
-            securitygroup_info = {"input": {"id": sg["id"]}}
238
-        elif action == 'PUT':
239
-            securitygroup_info = {
240
-                "input": {
241
-                    "id": sg['id'],
242
-                    "name": sg['name'],
243
-                    "description": sg["description"],
244
-                }
245
-            }
246
-        else:
247
-            securitygroup_info = {
248
-                "input": {
249
-                    "id": sg['id'],
250
-                    "name": sg['name'],
251
-                    "description": sg["description"],
252
-                    "tenant_id": tenant_id
253
-                }
254
-            }
255
-
256
-        if action == "POST":
257
-            securitygroup_rules = self.validate_dict(
258
-                sg, 'security_group_rules', None)
259
-            if securitygroup_rules is not None:
260
-                security_group_rules = []
261
-                for rule in securitygroup_rules:
262
-                    ethertype = self.validate_dict(rule, 'ethertype', None)
263
-                    ipv4 = None
264
-                    ipv6 = None
265
-                    if ethertype and ethertype.find('4') != -1:
266
-                        ipv4 = self.validate_dict(
267
-                            rule, 'remote_ip_prefix', None)
268
-                    elif ethertype and ethertype.find('6') != -1:
269
-                        ipv6 = self.validate_dict(
270
-                            rule, 'remote_ip_prefix', None)
271
-                    else:
272
-                        LOG.error("ethertype:%s is error!" % ethertype)
273
-
274
-                    sg_rule = {
275
-                        "id": rule['id'],
276
-                        "port_range_max":
277
-                            self.validate_dict(rule, 'port_range_max', 0),
278
-                        "port_range_min":
279
-                            self.validate_dict(rule, 'port_range_min', 0),
280
-                        "protocol":
281
-                            self.validate_dict(rule, 'protocol', None),
282
-                        "remote_group_id":
283
-                            self.validate_dict(rule, 'remote_group_id', None),
284
-                        "remote_ipv4_prefix": ipv4,
285
-                        "remote_ipv6_prefix": ipv6,
286
-                        "direction":
287
-                            self.validate_dict(rule, 'direction', None),
288
-                        "ethertype": ethertype,
289
-                        "tenant_id": tenant_id,
290
-                        "security_group_id":
291
-                            self.validate_dict(rule, 'security_group_id', None)
292
-                    }
293
-                    security_group_rules.append(sg_rule)
294
-                securitygroup_info['input']['security_group_rules'] = \
295
-                    security_group_rules
296
-        return securitygroup_info
297
-
298
-    def construct_securitygroup_rule_info(self, mech_context, action):
299
-        rule = mech_context.current
300
-        context = mech_context._plugin_context
301
-        # validate tenant
302
-        tenant_id = self._get_tenant_id_for_create(context, rule)
303
-        ethertype = self.validate_dict(rule, 'ethertype', None)
304
-        ipv4 = None
305
-        ipv6 = None
306
-        if ethertype and ethertype.find('4') != -1:
307
-            ipv4 = self.validate_dict(rule, 'remote_ip_prefix', None)
308
-        elif ethertype and ethertype.find('6') != -1:
309
-            ipv6 = self.validate_dict(rule, 'remote_ip_prefix', None)
310
-        else:
311
-            LOG.error("ethertype:%s is error!" % ethertype)
312
-
313
-        if action == 'DELETE' or action == 'GET':
314
-            securitygroup_rule_info = {"input": {"id": rule["id"]}}
315
-        else:
316
-            securitygroup_rule_info = {
317
-                "input": {
318
-                    "id": rule['id'],
319
-                    "port_range_max":
320
-                        self.validate_dict(rule, 'port_range_max', 0),
321
-                    "port_range_min":
322
-                        self.validate_dict(rule, 'port_range_min', 0),
323
-                    "protocol":
324
-                        self.validate_dict(rule, 'protocol', None),
325
-                    "remote_group_id":
326
-                        self.validate_dict(rule, 'remote_group_id', None),
327
-                    "remote_ipv4_prefix": ipv4,
328
-                    "remote_ipv6_prefix": ipv6,
329
-                    "security_group_id":
330
-                        self.validate_dict(rule, 'security_group_id', None)
331
-                }
332
-            }
333
-
334
-        if action == 'POST':
335
-            input = securitygroup_rule_info['input']
336
-            input['direction'] = self.validate_dict(rule, 'direction', None)
337
-            input['ethertype'] = ethertype
338
-            input['tenant_id'] = tenant_id
339
-
340
-        return securitygroup_rule_info
341
-
342
-    def set_enable_security_group(self, en_security_group):
343
-        self.en_security_group = en_security_group
344
-
345
-    def rest_create_tenant(self, tenant_id, tenant_name, description):
346
-        tenant_data = {"id": tenant_id,
347
-                       "name": tenant_name,
348
-                       "description": description}
349
-        data = {"input": tenant_data}
350
-        resource = 'add-' + TENANT
351
-        errstr = _("Unable to create tenant: %s")
352
-        self.rest_action('POST', resource, data, errstr)
353
-
354
-    def rest_update_tenant(self, tenant_id, tenant_name, description):
355
-        tenant_data = {"id": tenant_id,
356
-                       "name": tenant_name,
357
-                       "description": description}
358
-        data = {"input": tenant_data}
359
-        resource = 'update-' + TENANT
360
-        errstr = _("Unable to update tenant: %s")
361
-        self.rest_action('POST', resource, data, errstr)
362
-
363
-    def rest_delete_tenant(self, tenant_id):
364
-        tenant_data = {"id": tenant_id}
365
-        data = {"input": tenant_data}
366
-        resource = 'del-' + TENANT
367
-        errstr = _("Unable to delete tenant: %s")
368
-        self.rest_action('POST', resource, data, errstr)
369
-
370
-    def rest_get_tenant(self, tenant_id):
371
-        tenant_data = {"id": tenant_id}
372
-        data = {"input": tenant_data}
373
-        resource = 'get-' + TENANT
374
-        errstr = _("Unable to get tenant: %s")
375
-        return self.rest_action('POST', resource, data, errstr)
376
-
377
-    def rest_create_network(self, mech_context):
378
-        data = self.construct_network_info(mech_context, 'POST')
379
-        resource = 'add-' + NETWORK
380
-        errstr = _("Unable to create remote network: %s")
381
-        self.rest_action('POST', resource, data, errstr)
382
-
383
-    def rest_update_network(self, mech_context):
384
-        data = self.construct_network_info(mech_context, 'PUT')
385
-        resource = 'update-' + NETWORK
386
-        errstr = _("Unable to update remote network: %s")
387
-        self.rest_action('POST', resource, data, errstr)
388
-
389
-    def rest_delete_network(self, mech_context):
390
-        data = self.construct_network_info(mech_context, 'DELETE')
391
-        resource = 'del-' + NETWORK
392
-        errstr = _("Unable to delete remote network: %s")
393
-        self.rest_action('POST', resource, data, errstr)
394
-
395
-    def rest_get_network(self, mech_context):
396
-        data = self.construct_network_info(mech_context, 'GET')
397
-        resource = 'get-' + NETWORK
398
-        errstr = _("Unable to get remote network: %s")
399
-        return self.rest_action('POST', resource, data, errstr)
400
-
401
-    def rest_create_subnet(self, mech_context):
402
-        data = self.construct_subnet_info(mech_context, 'POST')
403
-        resource = 'add-' + SUBNET
404
-        errstr = _("Unable to create remote subnet: %s")
405
-        self.rest_action('POST', resource, data, errstr)
406
-
407
-    def rest_update_subnet(self, mech_context):
408
-        data = self.construct_subnet_info(mech_context, 'PUT')
409
-        resource = 'update-' + SUBNET
410
-        errstr = _("Unable to update remote subnet: %s")
411
-        self.rest_action('POST', resource, data, errstr)
412
-
413
-    def rest_delete_subnet(self, mech_context):
414
-        data = self.construct_subnet_info(mech_context, 'DELETE')
415
-        resource = 'del-' + SUBNET
416
-        errstr = _("Unable to delete remote subnet: %s")
417
-        self.rest_action('POST', resource, data, errstr)
418
-
419
-    def rest_get_subnet(self, mech_context):
420
-        data = self.construct_subnet_info(mech_context, 'GET')
421
-        resource = 'get-' + SUBNET
422
-        errstr = _("Unable to get remote subnet: %s")
423
-        return self.rest_action('POST', resource, data, errstr)
424
-
425
-    def rest_create_port(self, mech_context):
426
-        data = self.construct_port_info(mech_context, 'POST')
427
-        resource = 'add-' + PORT
428
-        errstr = _("Unable to create remote port: %s")
429
-        self.rest_action('POST', resource, data, errstr)
430
-
431
-    def rest_update_port(self, mech_context):
432
-        data = self.construct_port_info(mech_context, 'PUT')
433
-        resource = 'update-' + PORT
434
-        errstr = _("Unable to update remote port: %s")
435
-        self.rest_action('POST', resource, data, errstr)
436
-
437
-    def rest_delete_port(self, mech_context):
438
-        data = self.construct_port_info(mech_context, 'DELETE')
439
-        resource = 'del-' + PORT
440
-        errstr = _("Unable to delete remote port: %s")
441
-        self.rest_action('POST', resource, data, errstr)
442
-
443
-    def rest_get_port(self, mech_context):
444
-        data = self.construct_port_info(mech_context, 'GET')
445
-        resource = 'get-' + PORT
446
-        errstr = _("Unable to get remote port: %s")
447
-        return self.rest_action('POST', resource, data, errstr)
448
-
449
-    def rest_create_securitygroup(self, mech_context):
450
-        data = self.construct_securitygroup_info(mech_context, 'POST')
451
-        resource = 'add-' + SECURITY_GROUP
452
-        errstr = _("Unable to create remote securitygroup: %s")
453
-        self.rest_action('POST', resource, data, errstr)
454
-
455
-    def rest_update_securitygroup(self, mech_context):
456
-        data = self.construct_securitygroup_info(mech_context, 'PUT')
457
-        resource = 'update-' + SECURITY_GROUP
458
-        errstr = _("Unable to update remote securitygroup: %s")
459
-        self.rest_action('POST', resource, data, errstr)
460
-
461
-    def rest_delete_securitygroup(self, mech_context):
462
-        data = self.construct_securitygroup_info(mech_context, 'DELETE')
463
-        resource = 'del-' + SECURITY_GROUP
464
-        errstr = _("Unable to delete remote securitygroup: %s")
465
-        self.rest_action('POST', resource, data, errstr)
466
-
467
-    def rest_get_securitygroup(self, mech_context):
468
-        data = self.construct_securitygroup_info(mech_context, 'GET')
469
-        resource = 'get-' + SECURITY_GROUP
470
-        errstr = _("Unable to get remote securitygroup: %s")
471
-        return self.rest_action('POST', resource, data, errstr)
472
-
473
-    def rest_create_securitygroup_rule(self, mech_context):
474
-        data = self.construct_securitygroup_rule_info(mech_context, 'POST')
475
-        resource = 'add-' + SECURITY_GROUP_RULE
476
-        errstr = _("Unable to create remote securitygroup_rule: %s")
477
-        self.rest_action('POST', resource, data, errstr)
478
-
479
-    def rest_update_securitygroup_rule(self, mech_context):
480
-        data = self.construct_securitygroup_rule_info(mech_context, 'PUT')
481
-        resource = 'update-' + SECURITY_GROUP_RULE
482
-        errstr = _("Unable to update remote securitygroup_rule: %s")
483
-        self.rest_action('POST', resource, data, errstr)
484
-
485
-    def rest_delete_securitygroup_rule(self, mech_context):
486
-        data = self.construct_securitygroup_rule_info(mech_context, 'DELETE')
487
-        resource = 'del-' + SECURITY_GROUP_RULE
488
-        errstr = _("Unable to delete remote securitygroup_rule: %s")
489
-        self.rest_action('POST', resource, data, errstr)
490
-
491
-    def rest_get_securitygroup_rule(self, mech_context):
492
-        data = self.construct_securitygroup_rule_info(mech_context, 'GET')
493
-        resource = 'get-' + SECURITY_GROUP_RULE
494
-        errstr = _("Unable to get remote securitygroup_rule: %s")
495
-        return self.rest_action('POST', resource, data, errstr)

networking_zte/common/rest/servermanager.py → networking_zte/common/servermanager.py View File

@@ -1,5 +1,5 @@
1 1
 # vim: tabstop=4 shiftwidth=4 softtabstop=4
2
-# Copyright 2014 Big Switch Networks, Inc.
2
+# Copyright 2017 ZTE, Inc.
3 3
 # All Rights Reserved.
4 4
 #
5 5
 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
@@ -31,18 +31,23 @@ The following functionality is handled by this module:
31 31
 import base64
32 32
 import eventlet
33 33
 import httplib
34
+import json
34 35
 import os
36
+import re
35 37
 import socket
36 38
 import ssl
37 39
 
38
-from oslo_config import cfg
39 40
 from oslo_log import log
40 41
 from oslo_serialization import jsonutils
41
-
42
-from neutron.common import exceptions
43
-from neutron.i18n import _LE
44
-from neutron.i18n import _LI
45
-from neutron.i18n import _LW
42
+try:
43
+    from oslo.config import cfg
44
+except Exception:
45
+    from oslo_config import cfg
46
+try:
47
+    from neutron._i18n import _
48
+    from neutron_lib import exceptions
49
+except Exception:
50
+    from neutron.common import exceptions
46 51
 
47 52
 LOG = log.getLogger(__name__)
48 53
 
@@ -50,6 +55,15 @@ TOPOLOGY_PATH = "/topology"
50 55
 SUCCESS_CODES = range(200, 207)
51 56
 FAILURE_CODES = [301, 302, 303]
52 57
 BASE_URI = '/'
58
+response_code = {
59
+    'OK': 200,
60
+    'OK_1': 204,
61
+    'Bad_Request': 400,
62
+    'Unauthorized': 401,
63
+    'Forbidden': 403,
64
+    'Not_Found': 404,
65
+    'Conflict': 409,
66
+}
53 67
 
54 68
 
55 69
 class RemoteRestError(exceptions.NeutronException):
@@ -75,14 +89,86 @@ class ServerProxy(object):
75 89
         self.timeout = timeout
76 90
         self.name = name
77 91
         self.success_codes = success_codes
78
-        self.auth = None
92
+        self.auth = auth
79 93
         self.failed = False
80 94
         self.capabilities = []
81
-        # cache connection here to avoid a SSL handshake for every connection
82
-        # self.currentconn = None
83
-        if auth:
84
-            self.auth = 'Basic ' + base64.encodestring(auth).strip()
95
+        self.currentconn = None
96
+        self.header = {
97
+            "Accept": "application/json",
98
+            "Content-Type": "application/json"}
85 99
         self.combined_cert = combined_cert
100
+        self.auth_type = self.get_auth_type()
101
+
102
+        self.username, self.password = re.split(':', self.auth)
103
+
104
+        if self.auth_type == "BASE64":
105
+            self.auth = "Basic " + \
106
+                base64.b64encode("%s:%s" % (self.username, self.password))
107
+        elif self.auth_type == "AES":
108
+            encrypt_pwd = self.add_aes_encryption(self.password)
109
+            self.auth = "Basic " + \
110
+                base64.b64encode("%s:%s" % (self.username, encrypt_pwd))
111
+            LOG.debug('after base64enc auth=%s' % "****")
112
+
113
+        if self.auth is not None:
114
+            self.header["Authorization"] = self.auth
115
+            self.header["Realm"] = 'ZENIC'
116
+
117
+    def get_auth_type(self):
118
+        url = '/rest/v1/security/encryption'
119
+        method = "GET"
120
+        body = None
121
+        r = self.send_http_request(method, url, body)
122
+        if r:
123
+            jsn = json.loads(r)
124
+            enc = jsn['content']
125
+            return enc
126
+        else:
127
+            return ""
128
+
129
+    def send_http_request(self, method="", url="", body=(), trans=False):
130
+        if self.ssl and not self.combined_cert:
131
+            http = HTTPSConnectionWithValidation(self.server, self.port)
132
+        else:
133
+            http = httplib.HTTPConnection(self.server, self.port)
134
+        if trans:
135
+            payload = body
136
+        else:
137
+            if body:
138
+                payload = json.dumps(body)
139
+            else:
140
+                payload = None
141
+
142
+        LOG.debug('servermanager send_http_request, method=%s,header=%s, '
143
+                  'url=%s,payload=%s' % (method, self.header, url, "****"))
144
+        http.request(method, url, payload, self.header)
145
+        res = http.getresponse()
146
+        data = res.read()
147
+        LOG.info(_(
148
+            'servermanager send_http_request --ret code=%s ---'),
149
+            res.status)
150
+        if (res.status not in (response_code['OK'], response_code['OK_1'])):
151
+            if res.status == 404:
152
+                LOG.debug(
153
+                    'servermanager send_http_request finished, '
154
+                    'res code=%s, but get none data' % res.status)
155
+            else:
156
+                LOG.error(_(
157
+                    'servermanager send_http_request failed, res code=%('
158
+                    'code)s, reason=%(data)s'), {'code': res.status,
159
+                                                 'data': data})
160
+            return None
161
+        LOG.info(_('servermanager send_http_request --ret data=%s ---'),
162
+                 "****")
163
+
164
+        return data
165
+
166
+    def add_aes_encryption(self, pwd=""):
167
+        url = '/rest/v1/security/encrypt/AES'
168
+        method = "POST"
169
+        body = 'pwd=%s' % pwd
170
+        r = self.send_http_request(method, url, body, True)
171
+        return r
86 172
 
87 173
     def rest_call(self, action, resource, data='', headers={}, timeout=False,
88 174
                   reconnect=False):
@@ -98,27 +184,27 @@ class ServerProxy(object):
98 184
             headers['Authorization'] = self.auth
99 185
             headers['Realm'] = 'ZENIC'
100 186
 
101
-        LOG.info(_LI("ServerProxy: server=%(server)s, port=%(port)d, "
102
-                     "ssl=%(ssl)r"),
187
+        LOG.info(("ServerProxy: server=%(server)s, port=%(port)d, "
188
+                  "ssl=%(ssl)r"),
103 189
                  {'server': self.server, 'port': self.port, 'ssl': self.ssl})
104
-        LOG.info(_LI("ServerProxy: resource=%(resource)s, data=%(data)r, "
105
-                     "headers=%(headers)r, action=%(action)s"),
106
-                 {'resource': resource, 'data': data, 'headers': headers,
190
+        LOG.info(("ServerProxy: resource=%(resource)s, data=%(data)r, "
191
+                  "action=%(action)s"),
192
+                 {'resource': resource, 'data': data,
107 193
                   'action': action})
108 194
 
109 195
         conn = None
110
-        if self.ssl:
111
-            conn = httplib.HTTPSConnection(
112
-                self.server, self.port, timeout=self.timeout)
196
+        if self.ssl and not self.combined_cert:
197
+            conn = HTTPSConnectionWithValidation(
198
+                    self.server, self.port, timeout=self.timeout)
113 199
             if conn is None:
114
-                LOG.error(_LE(
200
+                LOG.error((
115 201
                     'ServerProxy: Could not establish HTTPS connection'))
116 202
                 return 0, None, None, None
117 203
         else:
118 204
             conn = httplib.HTTPConnection(
119 205
                 self.server, self.port, timeout=self.timeout)
120 206
             if conn is None:
121
-                LOG.error(_LE(
207
+                LOG.error((
122 208
                     'ServerProxy: Could not establish HTTP connection'))
123 209
                 return 0, None, None, None
124 210
 
@@ -135,15 +221,19 @@ class ServerProxy(object):
135 221
                     pass
136 222
             ret = (response.status, response.reason, respstr, respdata)
137 223
         except socket.timeout as e1:
138
-            LOG.error(_LE('ServerProxy: %(action)s failure, %(el)r'),
224
+            LOG.error(('ServerProxy: %(action)s failure, %(el)r'),
139 225
                       {"action": action, "el": e1})
140 226
             ret = 9, None, None, None
141 227
         except socket.error as e:
142
-            LOG.error(_LE("ServerProxy: %(action)s failure, %(e)r"),
228
+            LOG.error(("ServerProxy: %(action)s failure, %(e)r"),
143 229
                       {"action": action, "e": e})
144 230
             ret = 0, None, None, None
145 231
         conn.close()
146
-        # LOG.debug('ServerProxy: status=%d, reason=%r, ret=%s, data=%r' % ret)
232
+        LOG.info(_("ServerProxy: status=%(status)d, reason=%(reason)r, "
233
+                   "ret=%(ret)s, data=%(data)r"), {'status': ret[0],
234
+                                                   'reason': ret[1],
235
+                                                   'ret': ret[2],
236
+                                                   'data': ret[3]})
147 237
         return ret
148 238
 
149 239
         """
@@ -207,6 +297,7 @@ class ServerProxy(object):
207 297
 
208 298
 
209 299
 class ServerPool(object):
300
+
210 301
     def __init__(self, servers, auth, ssl, no_ssl_validation, ssl_sticky,
211 302
                  ssl_cert_directory, consistency_interval,
212 303
                  timeout=False, cache_connections=False,
@@ -251,7 +342,7 @@ class ServerPool(object):
251 342
         self.servers = [
252 343
             self.server_proxy_for(server, int(port))
253 344
             for server, port in (s.rsplit(':', 1) for s in servers)
254
-            ]
345
+        ]
255 346
         eventlet.spawn(self._consistency_watchdog, self.consistency_interval)
256 347
         LOG.debug("ServerPool: initialization done")
257 348
 
@@ -296,8 +387,7 @@ class ServerPool(object):
296 387
         return combined_cert
297 388
 
298 389
     def _combine_certs_to_file(self, certs, cfile):
299
-        """combine_certs_to_file
300
-
390
+        """
301 391
         Concatenates the contents of each certificate in a list of
302 392
         certificate paths to one combined location for use with ssl
303 393
         sockets.
@@ -308,7 +398,9 @@ class ServerPool(object):
308 398
                     combined.write(cert_handle.read())
309 399
 
310 400
     def _get_host_cert_path(self, host_dir, server):
311
-        """returns full path and boolean indicating existence"""
401
+        """
402
+        returns full path and boolean indicating existence
403
+        """
312 404
         hcert = os.path.join(host_dir, '%s.pem' % server)
313 405
         if os.path.exists(hcert):
314 406
             return hcert, True
@@ -319,12 +411,15 @@ class ServerPool(object):
319 411
                  for name in [
320 412
                      name for (root, dirs, files) in os.walk(ca_dir)
321 413
                      for name in files
322
-                     ]
323
-                 if name.endswith('.pem')]
414
+        ]
415
+            if name.endswith('.pem')]
324 416
         return certs
325 417
 
326 418
     def _fetch_and_store_cert(self, server, port, path):
327
-        """Grabs a certificate from a server and writes it to a given path."""
419
+        """
420
+        Grabs a certificate from a server and writes it to
421
+        a given path.
422
+        """
328 423
         try:
329 424
             cert = ssl.get_server_certificate((server, port))
330 425
         except Exception as e:
@@ -333,9 +428,8 @@ class ServerPool(object):
333 428
                               'Error details: %(error)s') %
334 429
                             {'server': server, 'error': str(e)})
335 430
 
336
-        LOG.warning(_LW("Storing to certificate for host %(server)s "
337
-                        "at %(path)s") % {'server': server,
338
-                                          'path': path})
431
+        LOG.warning("Storing to certificate for host %(server)s "
432
+                    "at %(path)s" % {'server': server, 'path': path})
339 433
         self._file_put_contents(path, cert)
340 434
 
341 435
         return cert
@@ -387,21 +481,19 @@ class ServerPool(object):
387 481
                 return ret
388 482
             else:
389 483
                 try:
390
-                    LOG.error(_LE('ServerProxy: %(action)s failure for '
391
-                                  'servers:%(server)r Response:'
392
-                                  '%(response)s'),
484
+                    LOG.error('ServerProxy: %(action)s failure for '
485
+                              'servers:%(server)r Response: %(response)s',
393 486
                               {'action': action,
394 487
                                'server': (active_server.server,
395 488
                                           active_server.port),
396 489
                                'response': unicode(ret[3], "utf-8")})
397
-                    LOG.error(_LE("ServerProxy: Error details: "
398
-                                  "status=%(status)d, reason=%(reason)r, "
399
-                                  "ret=%(ret)s, data=%(data)r"),
490
+                    LOG.error("ServerProxy: Error details: status=%(status)d,"
491
+                              " reason=%(reason)r, ret=%(ret)s, data=%(data)r",
400 492
                               {'status': ret[0], 'reason': ret[1],
401 493
                                'ret': unicode(ret[2], "utf-8"),
402 494
                                'data': unicode(ret[3], "utf-8")})
403 495
                 except Exception as e:
404
-                    LOG.error(_LE("fail to display info, err: %(e)s"),
496
+                    LOG.error("fail to display info, err: %(e)s",
405 497
                               {'e': e})
406 498
                 active_server.failed = True
407 499
 
@@ -415,8 +507,7 @@ class ServerPool(object):
415 507
 
416 508
     def rest_action(self, action, resource, data='', errstr='%s',
417 509
                     ignore_codes=[], headers={}, timeout=False):
418
-        """rest_action
419
-
510
+        """
420 511
         Wrapper for rest_call that verifies success and raises a
421 512
         RemoteRestError on failure with a provided error string
422 513
         By default, 404 errors on DELETE calls are ignored because
@@ -426,15 +517,13 @@ class ServerPool(object):
426 517
                     "resource %(resource)s %(data)s"),
427 518
                   {'action': action, 'resource': resource, 'data': data})
428 519
 
429
-        if not ignore_codes and action == 'DELETE':
430
-            ignore_codes = [404]
431 520
         resp = self.rest_call(action, resource, data, headers, ignore_codes,
432 521
                               timeout)
433 522
         if self.server_failure(resp, ignore_codes):
434 523
             try:
435
-                LOG.error(errstr, unicode(resp[2], "utf-8"))
524
+                LOG.error(errstr, unicode(resp[2], "utf-8"))  # noqa
436 525
             except Exception as e:
437
-                LOG.error(_LE("fail to display info, err: %(e)s"),
526
+                LOG.error("fail to display info, err: %(e)s",
438 527
                           {'e': e})
439 528
             raise RemoteRestError(reason=resp[2], status=resp[0])
440 529
         if resp[0] in ignore_codes:
@@ -450,6 +539,7 @@ class ServerPool(object):
450 539
 
451 540
 
452 541
 class HTTPSConnectionWithValidation(httplib.HTTPSConnection):
542
+
453 543
     # If combined_cert is None, the connection will continue without
454 544
     # any certificate validation.
455 545
     combined_cert = None

+ 330
- 0
networking_zte/fwaas/zenic_firewall_pool.py View File

@@ -0,0 +1,330 @@
1
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
+# Copyright 2017 ZTE, Inc.
3
+# All Rights Reserved.
4
+#
5
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
6
+#    not use this file except in compliance with the License. You may obtain
7
+#    a copy of the License at
8
+#
9
+#         http://www.apache.org/licenses/LICENSE-2.0
10
+#
11
+#    Unless required by applicable law or agreed to in writing, software
12
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+#    License for the specific language governing permissions and limitations
15
+#    under the License.
16
+
17
+from networking_zte.common import servermanager
18
+from neutron.db import common_db_mixin as base_db
19
+from oslo_log import log
20
+
21
+LOG = log.getLogger(__name__)
22
+
23
+# The following are used to invoke the API on the external controller
24
+
25
+FIREWALL = 'firewall'
26
+FIREWALL_POLICY = 'firewall-policy'
27
+FIREWALL_RULE = 'firewall-rule'
28
+INSERT_RULE = 'insert-rule'
29
+REMOVE_RULE = 'remove-rule'
30
+
31
+
32
+BASE_URI = '/restconf/operations/zenic-fwapp-model:'
33
+SUCCESS_CODES = range(200, 207)
34
+FAILURE_CODES = [
35
+    0,
36
+    9,
37
+    301,
38
+    302,
39
+    303,
40
+    400,
41
+    401,
42
+    403,
43
+    404,
44
+    409,
45
+    500,
46
+    501,
47
+    502,
48
+    503,
49
+    504,
50
+    505]
51
+
52
+
53
+class ZenicRestServerPool(
54
+        servermanager.ServerPool,
55
+        base_db.CommonDbMixin):
56
+    """ZenicRestServerPool for firewall plugin.
57
+    This server pool has firewall firewall_policy firewall_rule operations
58
+    of create, update and delete, to the Zenic Controller.
59
+    """
60
+
61
+    def __init__(self, servers, auth, ssl, no_ssl_validation, ssl_sticky,
62
+                 ssl_cert_directory, consistency_interval, timeout=False,
63
+                 cache_connections=True, base_uri=BASE_URI,
64
+                 success_codes=SUCCESS_CODES,
65
+                 failure_codes=FAILURE_CODES, name='ZenicRestProxy'):
66
+        super(ZenicRestServerPool, self).__init__(
67
+            servers, auth, ssl, no_ssl_validation, ssl_sticky,
68
+            ssl_cert_directory, consistency_interval, timeout,
69
+            cache_connections, base_uri, success_codes, failure_codes, name)
70
+
71
+    @staticmethod
72
+    def construct_firewall_info(context, id, firewall, action):
73
+        """
74
+        :param context:
75
+        :param id:
76
+        :param firewall:
77
+        :param action:
78
+        :return: firewall={'status': 'INACTIVE',
79
+           'router_ids': [],
80
+           'name': u'fw2',
81
+           'shared': None,
82
+           'firewall_policy_id': u'58b61e09-b27a-439b-b428-aec51bf6061a',
83
+           'tenant_id': u'a968288bfc9d4ced9c8c007f654310f9',
84
+           'admin_state_up': True,
85
+           'id': '3f2fb3ec-f7ce-450b-82e9-60983c10ff29',
86
+           'description': u''}
87
+        """
88
+        if action == 'UPDATE':
89
+            firewall = firewall['firewall']
90
+        firewall_info = {
91
+            "input": {
92
+                "id": id if (id != 0) else firewall["id"]
93
+            }
94
+        }
95
+        input = firewall_info['input']
96
+        if 'status' in firewall:
97
+            input['status'] = firewall['status']
98
+        if 'router_ids' in firewall:
99
+            input['router_ids'] = firewall['router_ids']
100
+        if 'name' in firewall:
101
+            input['name'] = firewall['name']
102
+        if 'shared' in firewall:
103
+            input['shared'] = firewall['shared']
104
+        if 'tenant_id' in firewall:
105
+            input['tenant_id'] = firewall['tenant_id']
106
+        if 'firewall_policy_id' in firewall:
107
+            input['firewall_policy_id'] = firewall['firewall_policy_id']
108
+        if 'admin_state_up' in firewall:
109
+            input['admin_state_up'] = firewall['admin_state_up']
110
+        if 'description' in firewall:
111
+            input['description'] = firewall['description']
112
+
113
+        return firewall_info
114
+
115
+    @staticmethod
116
+    def construct_firewall_policy_info(context, id, firewall_policy, action):
117
+        """
118
+        :param context:
119
+        :param id:
120
+        :param firewall_policy:
121
+        :param action:
122
+        :return: firewall_policy={'name': u'fw5',
123
+             'firewall_rules': [],
124
+             'shared': False,
125
+             'audited': False,
126
+             'tenant_id': u'a968288bfc9d4ced9c8c007f654310f9',
127
+             'id': '3c923e59-afed-4501-8e73-27be355746ab',
128
+             'firewall_list': [],
129
+             'description': u''}
130
+        """
131
+        if action == 'UPDATE':
132
+            firewall_policy = firewall_policy['firewall_policy']
133
+        firewall_policy_info = {
134
+            "input": {
135
+                "id": id if (id != 0) else firewall_policy['id'],
136
+            }
137
+        }
138
+        input = firewall_policy_info['input']
139
+        if 'firewall_rules' in firewall_policy:
140
+            input['firewall_rules'] = firewall_policy['firewall_rules']
141
+        if 'description' in firewall_policy:
142
+            input['description'] = firewall_policy['description']
143
+        if 'tenant_id ' in firewall_policy:
144
+            input['tenant_id'] = firewall_policy['tenant_id']
145
+        if 'shared' in firewall_policy:
146
+            input['shared'] = firewall_policy['shared']
147
+        if 'name' in firewall_policy:
148
+            input['name'] = firewall_policy['name']
149
+        if 'audited' in firewall_policy:
150
+            input['audited'] = firewall_policy['audited']
151
+        if 'firewall_list' in firewall_policy:
152
+            input['firewall_list'] = firewall_policy['firewall_list']
153
+
154
+        return firewall_policy_info
155
+
156
+    @staticmethod
157
+    def construct_firewall_rule_info(context, id, firewall_rule, action):
158
+        """
159
+        :param context:
160
+        :param id:
161
+        :param firewall_rule:
162
+        :param action:
163
+        :return:firewall_rule={'protocol': u'tcp',
164
+            'description': u'',
165
+            'source_port': None,
166
+            'source_ip_address': None,
167
+            'destination_ip_address': None,
168
+            'firewall_policy_id': None,
169
+            'position': 0,
170
+            'destination_port': None,
171
+            'id': '07410a40-3941-4e62-8f26-f87fc2032263',
172
+            'name': u'fw5',
173
+            'tenant_id': u'a968288bfc9d4ced9c8c007f654310f9',
174
+            'enabled': True,
175
+            'action': u'allow',
176
+            'ip_version': 4,
177
+            'shared': False}
178
+        """
179
+        if action == 'UPDATE':
180
+            firewall_rule = firewall_rule['firewall_rule']
181
+        firewall_rule_info = {
182
+            "input": {
183
+                "id": id if (id != 0) else firewall_rule['id'],
184
+            }
185
+        }
186
+        input = firewall_rule_info['input']
187
+        if 'protocol' in firewall_rule:
188
+            input['protocol'] = firewall_rule['protocol']
189
+        if 'description' in firewall_rule:
190
+            input['description'] = firewall_rule['description']
191
+        if firewall_rule.get('source_port', None):
192
+            input['source_port'] = firewall_rule['source_port']
193
+        if firewall_rule.get('source_ip_address', None):
194
+            input['source_ip_address'] = firewall_rule['source_ip_address']
195
+        if firewall_rule.get('destination_ip_address', None):
196
+            input['destination_ip_address'] = firewall_rule[
197
+                'destination_ip_address']
198
+        if firewall_rule.get('destination_port', None):
199
+            input['destination_port'] = firewall_rule['destination_port']
200
+        if 'name' in firewall_rule:
201
+            input['name'] = firewall_rule['name']
202
+        if 'tenant_id' in firewall_rule:
203
+            input['tenant_id'] = firewall_rule['tenant_id']
204
+        if 'enabled' in firewall_rule:
205
+            input['enabled'] = firewall_rule['enabled']
206
+        if 'action' in firewall_rule:
207
+            input['action'] = firewall_rule['action']
208
+        if firewall_rule.get('firewall_policy_id', None):
209
+            input['firewall_policy_id'] = firewall_rule['firewall_policy_id']
210
+        if firewall_rule.get('position', 0):
211
+            input['position'] = firewall_rule['position']
212
+        if 'ip_version' in firewall_rule:
213
+            input['ip_version'] = firewall_rule['ip_version']
214
+        if 'shared' in firewall_rule:
215
+            input['shared'] = firewall_rule['shared']
216
+
217
+        return firewall_rule_info
218
+
219
+    @staticmethod
220
+    def construct_insert_rule_info(policy_id, insert_rule_info):
221
+        """
222
+        :param policy_id:
223
+        :param insert_rule_info:
224
+        :return: rule_info={u'insert_after': u'',
225
+            u'firewall_rule_id': u'96541466-d916-43f2-926e-24c48939db5c',
226
+            u'insert_before': u'790f6db4-7f63-4697-b037-32a37a08a69f'}
227
+        """
228
+        rule_info = {
229
+            "input": {
230
+                "policy_id": policy_id,
231
+                "firewall_rule_id": insert_rule_info['firewall_rule_id'],
232
+            }
233
+        }
234
+        input_str = rule_info['input']
235
+        if insert_rule_info['insert_after']:
236
+            input_str['insert_after'] = insert_rule_info['insert_after']
237
+        if insert_rule_info['insert_before']:
238
+            input_str['insert_before'] = insert_rule_info['insert_before']
239
+        return rule_info
240
+
241
+    @staticmethod
242
+    def construct_delete_firewall_info(id):
243
+        firewall_info = {
244
+            "input": {
245
+                "id": id
246
+            }
247
+        }
248
+        return firewall_info
249
+
250
+    @staticmethod
251
+    def construct_remove_firewall_rule_info(policy_id, rule_id):
252
+        firewall_info = {
253
+            "input": {
254
+                "policy_id": policy_id,
255
+                "firewall_rule_id": rule_id['firewall_rule_id'],
256
+            }
257
+        }
258
+        return firewall_info
259
+
260
+    def create_firewall(self, context, firewall):
261
+        data = self.construct_firewall_info(context, 0, firewall, 'CREATE')
262
+        resource = 'add-' + FIREWALL
263
+        err_str = _("Unable to add firewall: %s")
264
+        self.rest_action('POST', resource, data, err_str)
265
+
266
+    def update_firewall(self, context, id, firewall):
267
+        data = self.construct_firewall_info(context, id, firewall, 'UPDATE')
268
+        resource = 'update-' + FIREWALL
269
+        err_str = _("Unable to update firewall: %s")
270
+        self.rest_action('POST', resource, data, err_str)
271
+
272
+    def delete_firewall(self, context, id):
273
+        data = self.construct_delete_firewall_info(id)
274
+        resource = 'del-' + FIREWALL
275
+        err_str = _("Unable to add firewall: %s")
276
+        self.rest_action('POST', resource, data, err_str)
277
+
278
+    def create_firewall_policy(self, context, firewall_policy):
279
+        data = self.construct_firewall_policy_info(
280
+            context, 0, firewall_policy, 'CREATE')
281
+        resource = 'add-' + FIREWALL_POLICY
282
+        err_str = _("Unable to add firewall policy: %s")
283
+        self.rest_action('POST', resource, data, err_str)
284
+
285
+    def update_firewall_policy(self, context, id, firewall_policy):
286
+        data = self.construct_firewall_policy_info(
287
+            context, id, firewall_policy, 'UPDATE')
288
+        resource = 'update-' + FIREWALL_POLICY
289
+        err_str = _("Unable to update firewall policy: %s")
290
+        self.rest_action('POST', resource, data, err_str)
291
+
292
+    def delete_firewall_policy(self, context, id):
293
+        data = self.construct_delete_firewall_info(id)
294
+        resource = 'del-' + FIREWALL_POLICY
295
+        err_str = _("Unable to del firewall policy: %s")
296
+        self.rest_action('POST', resource, data, err_str)
297
+
298
+    def create_firewall_rule(self, context, firewall_rule):
299
+        data = self.construct_firewall_rule_info(
300
+            context, 0, firewall_rule, 'CREATE')
301
+        resource = 'add-' + FIREWALL_RULE
302
+        err_str = _("Unable to add firewall rule: %s")
303
+        self.rest_action('POST', resource, data, err_str)
304
+
305
+    def update_firewall_rule(self, context, id, firewall_rule):
306
+        data = self.construct_firewall_rule_info(
307
+            context, id, firewall_rule, 'UPDATE')
308
+        resource = 'update-' + FIREWALL_RULE
309
+        err_str = _("Unable to update firewall rule: %s")
310
+        self.rest_action('POST', resource, data, err_str)
311
+
312
+    def delete_firewall_rule(self, context, id):
313
+        data = self.construct_delete_firewall_info(id)
314
+        resource = 'del-' + FIREWALL_RULE
315
+        err_str = _("Unable to del firewall rule: %s")
316
+        self.rest_action('POST', resource, data, err_str)
317
+
318
+    def insert_rule(self, context, policy_id, rule_info):
319
+        data = self.construct_insert_rule_info(policy_id, rule_info)
320
+        # resource = FIREWALL_POLICY + '-' + INSERT_RULE
321
+        resource = 'insert-' + FIREWALL_POLICY + '-rule'
322
+        err_str = _("Unable to insert rule: %s")
323
+        self.rest_action('POST', resource, data, err_str)
324
+
325
+    def remove_rule(self, context, policy_id, rule_id):
326
+        data = self.construct_remove_firewall_rule_info(policy_id, rule_id)
327
+        # resource = FIREWALL_POLICY + '-' + REMOVE_RULE
328
+        resource = 'remove-' + FIREWALL_POLICY + '-rule'
329
+        err_str = _("Unable to remove rule: %s")
330
+        self.rest_action('POST', resource, data, err_str)

+ 282
- 0
networking_zte/fwaas/zenic_fwaas_plugin.py View File

@@ -0,0 +1,282 @@
1
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
2
+# Copyright 2017 ZTE, Inc.
3
+# All Rights Reserved.
4
+#
5
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
6
+#    not use this file except in compliance with the License. You may obtain
7
+#    a copy of the License at
8
+#
9
+#         http://www.apache.org/licenses/LICENSE-2.0
10
+#
11
+#    Unless required by applicable law or agreed to in writing, software
12
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+#    License for the specific language governing permissions and limitations
15
+#    under the License.
16
+
17
+from networking_zte.fwaas.zenic_firewall_pool import ZenicRestServerPool
18
+try:
19
+    from neutron_lib import exceptions
20
+except Exception:
21
+    from neutron.common import exceptions
22
+from neutron.plugins.common import constants as const
23
+from neutron_fwaas.services.firewall.fwaas_plugin import FirewallPlugin
24
+from oslo_config import cfg
25
+from oslo_log import log as logging
26
+
27
+LOG = logging.getLogger(__name__)
28
+
29
+rest_proxy_opts = [
30
+    cfg.ListOpt('servers', default=['localhost:8800'],
31
+                help=_("A comma separated list of Big Switch or Floodlight "
32
+                       "servers and port numbers. The plugin proxies the "
33
+                       "requests to the Big Switch/Floodlight server, "
34
+                       "which performs the networking configuration. Only one"
35
+                       "server is needed per deployment, but you may wish to"
36
+                       "deploy multiple servers to support failover.")),
37
+    cfg.StrOpt('server_auth', default=None, secret=True,
38
+               help=_("The username and password for authenticating against "
39
+                      " the Big Switch or Floodlight controller.")),
40
+    cfg.StrOpt('base_url', default='/restconf/operations/zenic-fwapp-model:',
41
+               help=_("Base URL for restconf server ")),
42
+    cfg.BoolOpt('server_ssl', default=False,
43
+                help=_("If True, Use SSL when connecting to the Big Switch or "
44
+                       "Floodlight controller.")),
45
+    cfg.BoolOpt('ssl_sticky', default=True,
46
+                help=_("Trust and store the first certificate received for "
47
+                       "each controller address and use it to validate future "
48
+                       "connections to that address.")),
49
+    cfg.BoolOpt('no_ssl_validation', default=False,
50
+                help=_("Disables SSL certificate validation for controllers")),
51
+    cfg.BoolOpt('cache_connections', default=True,
52
+                help=_("Re-use HTTP/HTTPS connections to the controller.")),
53
+    cfg.StrOpt('ssl_cert_directory',
54
+               default='/etc/neutron/plugins/proxyagent/znic/ssl',
55
+               help=_("Directory containing ca_certs and host_certs "
56
+                      "certificate directories.")),
57
+    cfg.BoolOpt('sync_data', default=False,
58
+                help=_("Sync data on connect")),
59
+    cfg.BoolOpt('auto_sync_on_failure', default=True,
60
+                help=_("If neutron fails to create a resource because "
61
+                       "the backend controller doesn't know of a dependency, "
62
+                       "the plugin automatically triggers a full data "
63
+                       "synchronization to the controller.")),
64
+    cfg.IntOpt('consistency_interval', default=60,
65
+               help=_("Time between verifications that the backend controller "
66
+                      "database is consistent with Neutron")),
67
+    cfg.IntOpt('server_timeout', default=10,
68
+               help=_("Maximum number of seconds to wait for proxy request "
69
+                      "to connect and complete.")),
70
+    cfg.IntOpt('thread_pool_size', default=4,
71
+               help=_("Maximum number of threads to spawn to handle large "
72
+                      "volumes of port creations.")),
73
+]
74
+
75
+
76
+def get_rest_proxy_conf():
77
+    conf_proxy = cfg.ConfigOpts()
78
+    conf_proxy.register_opts(rest_proxy_opts, 'RESTPROXY')
79
+    conf_proxy(args=[], default_config_files=['/etc/neutron/plugin.ini'])
80
+    return conf_proxy
81
+
82
+
83
+class PostZenicRestError(exceptions.NeutronException):
84
+    message = _("The error occurred when posting to zenic: %(reason)s")
85
+
86
+    def __init__(self, **kwargs):
87
+        self.msg = self.message % kwargs
88
+
89
+
90
+class ZenicFirewallPlugin(FirewallPlugin):
91
+
92
+    """Implementation of the Zenic Firewall Service Plugin.
93
+
94
+    This class manages the workflow of FWaaS request/response.
95
+    Most DB related works are implemented in class
96
+    firewall_db.Firewall_db_mixin.
97
+    """
98
+
99
+    def __init__(self):
100
+        conf_proxy = get_rest_proxy_conf()
101
+        if conf_proxy.RESTPROXY.servers is not '':
102
+            self.servers = ZenicRestServerPool(
103
+                conf_proxy.RESTPROXY.servers,
104
+                conf_proxy.RESTPROXY.server_auth,
105
+                conf_proxy.RESTPROXY.server_ssl,
106
+                conf_proxy.RESTPROXY.no_ssl_validation,
107
+                conf_proxy.RESTPROXY.ssl_sticky,
108
+                conf_proxy.RESTPROXY.ssl_cert_directory,
109
+                conf_proxy.RESTPROXY.consistency_interval,
110
+                conf_proxy.RESTPROXY.server_timeout,
111
+                conf_proxy.RESTPROXY.cache_connections,
112
+                conf_proxy.RESTPROXY.base_url)
113
+        super(ZenicFirewallPlugin, self).__init__()
114
+
115
+    def create_firewall(self, context, firewall):
116
+        LOG.info(_("create_firewall firewall=%s"), firewall)
117
+        fw = super(ZenicFirewallPlugin, self).create_firewall(
118
+            context, firewall)
119
+        LOG.info(_("create_firewall firewall=%s"), fw)
120
+        try:
121
+            self.servers.create_firewall(context, fw)
122
+            self.set_firewall_status(context, fw['id'], const.ACTIVE)
123
+        except BaseException:
124
+            super(ZenicFirewallPlugin, self).delete_firewall(context,
125
+                                                             fw['id'])
126
+            raise PostZenicRestError(reason="create firewall!")
127
+        return fw
128
+
129
+    def update_firewall(self, context, id, firewall):
130
+        LOG.info(_("update_firewall firewall=%s"), firewall)
131
+        try:
132
+            self.servers.update_firewall(context, id, firewall)
133
+        except BaseException:
134
+            raise PostZenicRestError(reason="update firewall!")
135
+        fw = super(ZenicFirewallPlugin, self).update_firewall(
136
+            context, id, firewall)
137
+        self.set_firewall_status(context, id, const.ACTIVE)
138
+        return fw
139
+
140
+    def delete_firewall(self, context, id):
141
+        LOG.info(_("delete_firewall id = %s"), id)
142
+        try:
143
+            self.servers.delete_firewall(context, id)
144
+        except BaseException:
145
+            raise PostZenicRestError(reason="delete firewall!")
146
+        super(ZenicFirewallPlugin, self).delete_firewall(context, id)
147
+        self.firewall_deleted(context, id)
148
+
149
+    def create_firewall_policy(self, context, firewall_policy):
150
+        LOG.info(_("create_firewall_policy firewall_policy=%s"),
151
+                 firewall_policy)
152
+        fwp = super(ZenicFirewallPlugin,
153
+                    self).create_firewall_policy(context, firewall_policy)
154
+        LOG.info(_("create_firewall_policy firewall_policy=%s"), fwp)
155
+        try:
156
+            self.servers.create_firewall_policy(context, fwp)
157
+        except BaseException:
158
+            super(ZenicFirewallPlugin,
159
+                  self).delete_firewall_policy(context, fwp['id'])
160
+            raise PostZenicRestError(reason="create firewall policy!")
161
+        return fwp
162
+
163
+    def update_firewall_policy(self, context, id, firewall_policy):
164
+        LOG.info(_("update_firewall_policy firewall_policy=%s"),
165
+                 firewall_policy)
166
+        try:
167
+            self.servers.update_firewall_policy(context, id, firewall_policy)
168
+        except BaseException:
169
+            raise PostZenicRestError(reason="update firewall policy!")
170
+        fwp = super(ZenicFirewallPlugin,
171
+                    self).update_firewall_policy(context, id, firewall_policy)
172
+        self.update_policy_related_firewall_status(context, id, const.ACTIVE)
173
+        return fwp
174
+
175
+    def delete_firewall_policy(self, context, id):
176
+        LOG.info(_("delete_firewall_policy id = %s"), id)
177
+        try:
178
+            self.servers.delete_firewall_policy(context, id)
179
+        except BaseException:
180
+            raise PostZenicRestError(reason="delete firewall policy!")
181
+        super(ZenicFirewallPlugin, self).delete_firewall_policy(context, id)
182
+
183
+    def create_firewall_rule(self, context, firewall_rule):
184
+        LOG.info(_("create_firewall_policy firewall_rule=%s"), firewall_rule)
185
+        fwr = super(ZenicFirewallPlugin,
186
+                    self).create_firewall_rule(context, firewall_rule)
187
+        LOG.info(_("create_firewall_policy firewall_rule=%s"), fwr)
188
+        try:
189
+            self.servers.create_firewall_rule(context, fwr)
190
+        except BaseException:
191
+            super(ZenicFirewallPlugin,
192
+                  self).delete_firewall_rule(context, fwr['id'])
193
+            raise PostZenicRestError(reason="create firewall rule!")
194
+        return fwr
195
+
196
+    def update_firewall_rule(self, context, id, firewall_rule):
197
+        LOG.info(_("upate_firewall_rule firewall_rule=%s"), firewall_rule)
198
+        try:
199
+            self.servers.update_firewall_rule(context, id, firewall_rule)
200
+        except BaseException:
201
+            raise PostZenicRestError(reason="update firewall rule!")
202
+        fwr = super(ZenicFirewallPlugin,
203
+                    self).update_firewall_rule(context, id, firewall_rule)
204
+        firewall_policy_id = fwr['firewall_policy_id']
205
+        if firewall_policy_id:
206
+            self.update_policy_related_firewall_status(
207
+                context, firewall_policy_id, const.ACTIVE)
208
+        return fwr
209
+
210
+    def delete_firewall_rule(self, context, id):
211
+        LOG.info(_("delete_firewall_rule id = %s"), id)
212
+        try:
213
+            self.servers.delete_firewall_rule(context, id)
214
+        except BaseException:
215
+            raise PostZenicRestError(reason="delete firewall policy!")
216
+        super(ZenicFirewallPlugin, self).delete_firewall_rule(context, id)
217
+
218
+    def insert_rule(self, context, id, rule_info):
219
+        LOG.info(_("insert_rule rule_info=%s"), rule_info)
220
+        try:
221
+            self.servers.insert_rule(context, id, rule_info)
222
+        except BaseException:
223
+            raise PostZenicRestError(reason="insert rule!")
224
+        fwp = super(ZenicFirewallPlugin,
225
+                    self).insert_rule(context, id, rule_info)
226
+        self.update_policy_related_firewall_status(context, id, const.ACTIVE)
227
+        return fwp
228
+
229
+    def remove_rule(self, context, id, rule_info):
230
+        LOG.info(_("remove_rule rule_info=%s"), rule_info)
231
+        try:
232
+            self.servers.remove_rule(context, id, rule_info)
233
+        except BaseException:
234
+            raise PostZenicRestError(reason="remove rule!")
235
+        fwp = super(ZenicFirewallPlugin,
236
+                    self).remove_rule(context, id, rule_info)
237
+        self.update_policy_related_firewall_status(context, id, const.ACTIVE)
238
+        return fwp
239
+
240
+    def set_firewall_status(self, context, firewall_id, status):
241
+        """uses this to set a firewall's status."""
242
+        LOG.debug("set_firewall_status() called")
243
+        with context.session.begin(subtransactions=True):
244
+            fw_db = self._get_firewall(context, firewall_id)
245
+            # ignore changing status if firewall expects to be deleted
246
+            # That case means that while some pending operation has been
247
+            # performed on the backend, neutron server received delete request
248
+            # and changed firewall status to const.PENDING_DELETE
249
+            if fw_db.status == const.PENDING_DELETE:
250
+                LOG.debug("Firewall %(fw_id)s in PENDING_DELETE state, "
251
+                          "not changing to %(status)s",
252
+                          {'fw_id': firewall_id, 'status': status})
253
+                return False
254
+            if status in (const.ACTIVE, const.DOWN, const.INACTIVE):
255
+                fw_db.status = status
256
+                return True
257
+            else:
258
+                fw_db.status = const.ERROR
259
+                return False
260
+
261
+    def firewall_deleted(self, context, firewall_id):
262
+        """Agent uses this to indicate firewall is deleted."""
263
+        LOG.debug("firewall_deleted() called")
264
+        with context.session.begin(subtransactions=True):
265
+            fw_db = self._get_firewall(context, firewall_id)
266
+            # allow to delete firewalls in ERROR state
267
+            if fw_db.status in (const.PENDING_DELETE, const.ERROR):
268
+                self.delete_db_firewall_object(context, firewall_id)
269
+                return True
270
+            else:
271
+                LOG.warn(_('Firewall %(fw)s unexpectedly deleted by agent, '
272
+                           'status was %(status)s'),
273
+                         {'fw': firewall_id, 'status': fw_db.status})
274
+                fw_db.status = const.ERROR
275
+                return False
276
+
277
+    def update_policy_related_firewall_status(
278
+            self, context, firewall_policy_id, status):
279
+        firewall_policy = self.get_firewall_policy(context, firewall_policy_id)
280
+        if firewall_policy:
281
+            for firewall_id in firewall_policy['firewall_list']:
282
+                self.set_firewall_status(context, firewall_id, status)

+ 196
- 0
networking_zte/l3/all_l3_agents_scheduler.py View File

@@ -0,0 +1,196 @@
1
+# Copyright (c) 2013 OpenStack Foundation.
2
+#
3
+# Licensed under the Apache License, Version 2.0 (the "License");
4
+# you may not use this file except in compliance with the License.
5
+# You may obtain a copy of the License at
6
+#
7
+#    http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+# Unless required by applicable law or agreed to in writing, software
10
+# distributed under the License is distributed on an "AS IS" BASIS,
11
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12
+# implied.
13
+# See the License for the specific language governing permissions and
14
+# limitations under the License.
15
+
16
+import random
17
+import six
18
+
19
+import l3_agent_scheduler
20
+
21
+from eventlet import greenthread
22
+from neutron.db import agents_db
23
+from neutron.db import agentschedulers_db
24
+from neutron.db import l3_agentschedulers_db
25
+from neutron.db import l3_db
26
+from neutron.db import l3_hamode_db
27
+from neutron.db import models_v2
28
+from neutron.extensions import agent as ext_agent
29
+from neutron.extensions import l3_ext_ha_mode as l3_ha
30
+from oslo_config import cfg
31
+from oslo_db import exception as db_exc
32
+from oslo_log import log as logging
33
+from oslo_serialization import jsonutils
34
+from oslo_utils import timeutils
35
+from sqlalchemy.orm import exc as sa_exc
36
+
37
+__author__ = '10069907'
38
+
39
+LOG = logging.getLogger(__name__)
40
+cfg.CONF.register_opts(l3_hamode_db.L3_HA_OPTS)
41
+
42
+
43
+def method_patch(cls, bases, dct):
44
+    base = bases[0]
45
+    for name, value in dct.iteritems():
46
+        if name not in("__module__", "__metaclass__", "__doc__"):
47
+            setattr(base, name, value)
48
+    return base
49
+
50
+
51
+@six.add_metaclass(method_patch)
52
+class AddAgentToRouterBinding(agents_db.AgentDbMixin):
53
+    def _get_all_routers_with_interface_or_gateway(self, context):
54
+        try:
55
+            port_db = (context.session.query(models_v2.Port).
56
+                       enable_eagerloads(False).
57
+                       filter(models_v2.Port.device_owner.
58
+                              startswith("network:router_interface")).
59
+                       all())
60
+        except sa_exc.NoResultFound:
61
+            LOG.debug("No ports have port_id starting with router_interface")
62
+            return None
63
+
64
+        try:
65
+            router_db = (context.session.query(l3_db.Router).
66
+                         enable_eagerloads(False).all())
67
+        except sa_exc.NoResultFound:
68
+            LOG.debug("No router have Found")
69
+            return None
70
+        router_ids = [router.id for router in router_db]
71
+        return [
72
+            port.device_id for port in port_db if port.device_id in router_ids
73
+            ]
74
+
75
+    def _binding_router_to_agent(self, context, router_ids, agent_id):
76
+        for r_id in router_ids:
77
+            LOG.debug('_binding_router_to_agent, process:%s-%s' %
78
+                      (r_id, agent_id))
79
+            query = context.session.query(l3_agentschedulers_db.
80
+                                          RouterL3AgentBinding)
81
+            query = query.filter(l3_agentschedulers_db.RouterL3AgentBinding.
82
+                                 router_id == r_id,
83
+                                 l3_agentschedulers_db.RouterL3AgentBinding.
84
+                                 l3_agent_id == agent_id)
85
+            try:
86
+                query.one()
87
+                LOG.debug('find old router_agent_binding %s-%s '
88
+                          % (r_id, agent_id))
89
+            except sa_exc.NoResultFound:
90
+                with context.session.begin(subtransactions=True):
91
+                    binding = l3_agentschedulers_db.RouterL3AgentBinding()
92
+                    binding.l3_agent_id = agent_id
93
+                    binding.router_id = r_id
94
+                    try:
95
+                        context.session.add(binding)
96
+                        LOG.debug('add router_agent_binding %s-%s'
97
+                                  % (r_id, agent_id))
98
+                    except db_exc.DBError:
99
+                        LOG.debug('add router_agent_binding %s-%s fail'
100
+                                  % (r_id, agent_id))
101
+
102
+    def _update_l3_agent_router_bindings(self, context, agent_id):
103
+        router_ids_need_binding = \
104
+            self._get_all_routers_with_interface_or_gateway(context)
105
+        LOG.info('get all_router_with_port:%(r_id)s,and agent:%(agt_id)s',
106
+                 {'r_id': router_ids_need_binding, 'agt_id': agent_id})
107
+        if router_ids_need_binding is None:
108
+            return
109
+        self._binding_router_to_agent(context,
110
+                                      router_ids_need_binding, agent_id)
111
+
112
+    def _create_or_update_agent(self, context, agent):
113
+        with context.session.begin(subtransactions=True):
114
+            res_keys = ['agent_type', 'binary', 'host', 'topic']
115
+            res = dict((k, agent[k]) for k in res_keys)
116
+
117
+            configurations_dict = agent.get('configurations', {})
118
+            res['configurations'] = jsonutils.dumps(configurations_dict)
119
+            res['load'] = self._get_agent_load(agent)
120
+            current_time = timeutils.utcnow()
121
+            try:
122
+                agent_db = self._get_agent_by_type_and_host(
123
+                    context, agent['agent_type'], agent['host'])
124
+                if agent['topic'] == "l3_agent":
125
+                    self._update_l3_agent_router_bindings(context, agent_db.id)
126
+                res['heartbeat_timestamp'] = current_time
127
+                if agent.get('start_flag'):
128
+                    res['started_at'] = current_time
129
+                greenthread.sleep(0)
130
+                agent_db.update(res)
131
+            except ext_agent.AgentNotFoundByTypeHost:
132
+                greenthread.sleep(0)
133
+                res['created_at'] = current_time
134
+                res['started_at'] = current_time
135
+                res['heartbeat_timestamp'] = current_time
136
+                res['admin_state_up'] = True
137
+                agent_db = agents_db.Agent(**res)
138
+                greenthread.sleep(0)
139
+                context.session.add(agent_db)
140
+            greenthread.sleep(0)
141
+
142
+
143
+class AllL3AgentsScheduler(l3_agent_scheduler.L3Scheduler):
144
+    """allocate all L3 agent for a router."""
145
+
146
+    def get_all_l3_agents(self, plugin, context):
147
+        """Return L3 agents where a router could be scheduled."""
148
+        with context.session.begin(subtransactions=True):
149
+            query = context.session.query(agents_db.Agent)
150
+            query = query.filter(
151
+                agents_db.Agent.topic == 'l3_agent')
152
+            query = (query.filter_by(admin_state_up=True))
153
+
154
+            return [l3_agent
155
+                    for l3_agent in query
156
+                    if (agentschedulers_db.AgentSchedulerDbMixin.
157
+                        is_eligible_agent(True, l3_agent))]
158
+
159
+    def _schedule_router(self, plugin, context, router_id, candidates=None):
160
+        sync_router = plugin.get_router(context, router_id)
161
+        router_distributed = sync_router.get('distributed', False)
162
+        if router_distributed or sync_router.get('ha', False):
163
+            raise l3_ha.DistributedHARouterNotSupported()
164
+        if candidates is None:
165
+            candidates = self.get_all_l3_agents(plugin, context)
166
+            LOG.debug('all_cap:%s' % candidates)
167
+        if not candidates:
168
+            return
169
+        for chosen_agent in candidates:
170
+            query = context.session.query(
171
+                l3_agentschedulers_db.RouterL3AgentBinding)
172
+            query = query.filter(
173
+                l3_agentschedulers_db.RouterL3AgentBinding.router_id ==
174
+                router_id,
175
+                l3_agentschedulers_db.RouterL3AgentBinding.l3_agent_id ==
176
+                chosen_agent['id'])
177
+            try:
178
+                query.one()
179
+                LOG.debug('find old router_agent_binding %s-%s '
180
+                          % (router_id, chosen_agent['id']))
181
+            except sa_exc.NoResultFound:
182
+                self.bind_router(context, router_id, chosen_agent)
183
+        return chosen_agent
184
+
185
+    def schedule(self, plugin, context, router_id, candidates=None):
186
+        LOG.debug('AllL3AgentsScheduler.schedule')
187
+        return self._schedule_router(
188
+            plugin, context, router_id, candidates=candidates)
189
+
190
+    def _choose_router_agent(self, plugin, context, candidates):
191
+        """Choose an agent from candidates based on a specific policy."""
192
+        pass
193
+
194
+    def _choose_router_agents_for_ha(self, plugin, context, candidates):
195
+        num_agents = self.get_num_of_agents_for_ha(len(candidates))
196
+        return random.sample(candidates, num_agents)

+ 789
- 0
networking_zte/l3/zenic_agent.py View File

@@ -0,0 +1,789 @@
1
+# Copyright 2017 ZTE, Inc.
2
+#
3
+#    Licensed under the Apache License, Version 2.0 (the "License"); you may
4
+#    not use this file except in compliance with the License. You may obtain
5
+#    a copy of the License at
6
+#
7
+#         http://www.apache.org/licenses/LICENSE-2.0
8
+#
9
+#    Unless required by applicable law or agreed to in writing, software
10
+#    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11
+#    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12
+#    License for the specific language governing permissions and limitations
13
+#    under the License.
14
+#
15
+
16
+
17
+from networking_zte.common import servermanager
18
+from networking_zte.utils import cmcc_util
19
+try:
20
+    from neutron.agent.common import config as config
21
+except Exception:
22
+    from neutron.conf.agent import common as config
23
+try:
24
+    from neutron.agent.l3 import config as l3_config
25
+    from neutron.agent.l3 import ha
26
+except Exception:
27
+    from neutron.conf.agent.l3 import config as l3_config
28
+    from neutron.conf.agent.l3 import ha as ha_conf
29
+from neutron.agent.linux import external_process
30
+from neutron.agent.linux import interface
31
+from neutron.agent.linux import iptables_manager
32
+try:
33
+    from neutron.agent.metadata import config as metadata_config
34
+except Exception:
35
+    from neutron.conf.agent.metadata import config as metadata_config
36
+from neutron.agent import rpc as agent_rpc
37
+from neutron.common import config as common_config
38
+try:
39
+    from neutron_lib import constants as l3_constants
40
+except Exception:
41
+    from neutron.common import constants as l3_constants
42
+from neutron.common import eventlet_utils
43
+from neutron.common import rpc as n_rpc
44
+from neutron.common import topics
45
+try:
46
+    from neutron_lib.utils import net as utils
47
+except Exception:
48
+    from neutron.common import utils
49
+
50
+try:
51
+    from neutron import context as context
52
+except Exception:
53
+    from neutron_lib import context as context
54
+from neutron import manager
55
+try:
56
+    from neutron.openstack.common import loopingcall
57
+    from neutron.openstack.common import service
58
+except Exception:
59
+    from neutron.agent.linux import pd
60
+    from neutron.agent.linux import ra
61
+    from oslo_service import loopingcall
62
+    from oslo_service import service
63
+try:
64
+    from neutron import context as qcontext
65
+except Exception:
66
+    from neutron_lib import context as qcontext
67
+try:
68
+    from neutron.db.models import l3 as l3_db
69
+except Exception:
70
+    from neutron.db import l3_db
71
+from neutron import service as neutron_service
72
+from oslo_concurrency import lockutils
73
+from oslo_config import cfg
74
+from oslo_log import log as logging
75
+import oslo_messaging
76
+import sys
77
+import time
78
+
79
+
80
+eventlet_utils.monkey_patch()
81
+
82
+
83
+# NS_PREFIX = namespaces.NS_PREFIX
84
+# INTERNAL_DEV_PREFIX = namespaces.INTERNAL_DEV_PREFIX
85
+# EXTERNAL_DEV_PREFIX = namespaces.EXTERNAL_DEV_PREFIX
86
+# LOG = LOG.getLogger(__name__)
87
+# NS_PREFIX = 'qrouter-'
88
+# INTERNAL_DEV_PREFIX = 'qr-'
89
+# EXTERNAL_DEV_PREFIX = 'qg-'
90
+# RPC_LOOP_INTERVAL = 1
91
+# FLOATING_IP_CIDR_SUFFIX = '/32'
92
+#
93
+# SUBNET  = 'subnet'
94
+# PORT    = 'port'
95
+# ROUTER  = 'router'
96
+# FLOATING_IP = 'floating-ip'
97
+# VXLAN_TUNNEL = 'vxlan-tunnel'
98
+# SECURITY_GROUP = 'sg'
99
+# SECURITY_GROUP_RULE = 'sg-rule'
100
+# CLASSIFIER = 'classifier'
101
+
102
+SUCCESS_CODES = range(200, 207)
103
+FAILURE_CODES = [400, 401, 404, 409]
104
+
105
+# Number of routers to fetch from server at a time on resync.
106
+# Needed to reduce load on server side and to speed up resync on agent side.
107
+SYNC_ROUTERS_MAX_CHUNK_SIZE = 16
108
+
109
+rest_proxy_opts = [
110
+    cfg.ListOpt('servers', default=['localhost:8800'],
111
+                help=_("A comma separated list of Big Switch or Floodlight "
112
+                       "servers and port numbers. The plugin proxies the "
113
+                       "requests to the Big Switch/Floodlight server, "
114
+                       "which performs the networking configuration. Only one"
115
+                       "server is needed per deployment, but you may wish to"
116
+                       "deploy multiple servers to support failover.")),
117
+    cfg.StrOpt('server_auth', default=None, secret=True,
118
+               help=_("The username and password for authenticating against "
119
+                      " the Big Switch or Floodlight controller.")),
120
+    cfg.StrOpt('base_url', default='/restconf/operations/zenic-vdcapp-model:',
121
+               help=_("Base URL for restconf server ")),
122
+    cfg.BoolOpt('server_ssl', default=False,
123
+                help=_("If True, Use SSL when connecting to the Big Switch or "
124
+                       "Floodlight controller.")),
125
+    cfg.BoolOpt('ssl_sticky', default=True,
126
+                help=_("Trust and store the first certificate received for "
127
+                       "each controller address and use it to validate future "
128
+                       "connections to that address.")),
129
+    cfg.BoolOpt('no_ssl_validation', default=False,
130
+                help=_("Disables SSL certificate validation for controllers")),
131
+    cfg.BoolOpt('cache_connections', default=True,
132
+                help=_("Re-use HTTP/HTTPS connections to the controller.")),
133
+    cfg.StrOpt('ssl_cert_directory',
134
+               default='/etc/neutron/plugins/proxyagent/znic/ssl',
135
+               help=_("Directory containing ca_certs and host_certs "
136
+                      "certificate directories.")),
137
+    cfg.BoolOpt('sync_data', default=False,
138
+                help=_("Sync data on connect")),
139
+    cfg.BoolOpt('auto_sync_on_failure', default=True,
140
+                help=_("If neutron fails to create a resource because "
141
+                       "the backend controller doesn't know of a dependency, "
142
+                       "the plugin automatically triggers a full data "
143
+                       "synchronization to the controller.")),
144
+    cfg.IntOpt('consistency_interval', default=60,
145
+               help=_("Time between verifications that the backend controller "
146
+                      "database is consistent with Neutron")),
147
+    cfg.IntOpt('server_timeout', default=10,
148
+               help=_("Maximum number of seconds to wait for proxy request "
149
+                      "to connect and complete.")),
150
+    cfg.IntOpt('thread_pool_size', default=4,
151
+               help=_("Maximum number of threads to spawn to handle large "
152
+                      "volumes of port creations.")),
153
+    cfg.StrOpt('neutron_id', default='neutron-' + utils.get_hostname(),
154
+               deprecated_name='quantum_id',
155
+               help=_("User defined identifier for this Neutron deployment")),
156
+    cfg.BoolOpt('add_meta_server_route', default=True,
157
+               help=_("Flag to decide if a route to the metadata server "
158
+                      "should be injected into the VM")),
159
+    cfg.StrOpt('zenic_version', default="50.1",
160
+               help=_("Version number of the zenic controller corresponding "
161
+                      "to the zenic agent")),
162
+    cfg.StrOpt('up_gw_status', default="True",
163
+               help=_("up gwport status bind to router")),
164
+    cfg.StrOpt('op_version', default="",
165
+               help=_("Version number of the zenic plugins")),
166
+    cfg.StrOpt('sync_router', default="False",
167
+               help=_("Flag to decide if plugin use sync router function")),
168
+]
169
+
170
+LOG = logging.getLogger(__name__)
171
+
172
+
173
+class ZenicPluginApi(agent_rpc.PluginApi):
174
+    pass
175
+
176
+
177
+class ZenicL3RestServerPool(servermanager.ServerPool):
178
+    """Zenic L3 Rest Server Pool for Zenic L3 Agent.
179
+
180
+    This server pool has the router and floatingip operations
181
+    of create, update and delete, to the Zenic Controller.
182
+    """
183
+
184
+    def __init__(
185
+            self,
186
+            servers,
187
+            auth,
188
+            zenic_version,
189
+            ssl,
190
+            no_ssl_validation,
191
+            ssl_sticky,
192
+            ssl_cert_directory,
193
+            consistency_interval,
194
+            timeout=False,
195
+            cache_connections=True,
196
+            base_uri='/restconf/operations/zenic-vdcapp-model:',
197
+            op_version="",
198
+            success_codes=SUCCESS_CODES,
199
+            failure_codes=FAILURE_CODES,
200
+            name='ZenicL3RestProxy'):
201
+        super(
202
+            ZenicL3RestServerPool,
203
+            self).__init__(
204
+            servers,
205
+            auth,
206
+            ssl,
207
+            no_ssl_validation,
208
+            ssl_sticky,
209
+            ssl_cert_directory,
210
+            consistency_interval,
211
+            timeout,
212
+            cache_connections,
213
+            base_uri,
214
+            success_codes,
215
+            failure_codes,
216
+            name)
217
+        version = zenic_version.split('.')
218
+        version = version[0] + version[1]
219
+        LOG.debug(_("zenic_version = %s"), version)
220
+        if (version.isdigit() is False) or (int(version) < 403):
221
+            LOG.error(_("zenic_version error!zenic_version = %s"), version)
222
+        self.zenic_version = int(version)
223
+        self.floating_status = {}
224
+        self.op_version = op_version
225
+        self.cmcc = cmcc_util.CmccUtil()
226
+
227
+    @staticmethod
228
+    def validate_dict(instance, key, default_val):
229
+        return instance[key] if (key in instance and
230
+                                 instance[key]) else default_val
231
+
232
+    def construct_router_rest_msg(self, router_info, action):
233
+        # LOG.info(_('construct_router_info r_info:{0}'.format(router_info)))
234
+        if action == 'DELETE' or action == 'GET':
235
+            router_rest_data = {"input": {"id": router_info}}
236
+            return router_rest_data
237
+        else:
238
+            internal_interfaces = router_info.get('_interfaces', set())
239
+            internal_interfaces_subnets = list()
240
+            if internal_interfaces:
241
+                internal_interfaces_subnets =\
242
+                    [intf['subnets'] for intf in internal_interfaces]
243
+                LOG.debug("subnets:%s", internal_interfaces_subnets)
244
+                for subnet in internal_interfaces_subnets:
245
+                    LOG.debug('subnet:%s', subnet)
246
+            routes_injects = router_info.get('routes', set())
247
+            LOG.debug('internal_interfaces:{0}'.format(internal_interfaces))
248
+            real_gw_port = router_info.get('gw_port_id', '')
249
+            if not real_gw_port:
250
+                real_gw_port = ''
251
+            real_gw_port = self.cmcc.filter_gw_port(
252
+                self.op_version, router=router_info, gw_port=real_gw_port)
253
+            d = []
254
+            for c in internal_interfaces_subnets:
255
+                a = [subnet['id'] for subnet in c]
256
+                for i in a:
257
+                    d.append(i)
258
+            b = [router_inject for router_inject in routes_injects]
259
+            router_rest_data =\
260
+                {"input": {"id": router_info['id'],
261
+                           "name": router_info['name'],
262
+                           "admin_state_up": router_info['admin_state_up'],
263
+                           "tenant_id": router_info['tenant_id'],
264
+                           "ext-gw-port": real_gw_port,
265
+                           "enable_snat": router_info.get('enable_snat', True),
266
+                           "router-interfaces": d,
267
+                           "routes": b}
268
+                 }
269
+
270
+            if self.zenic_version > 403:
271
+                if '_floatingips' in router_info:
272
+                    routes_floatingips = router_info.get('_floatingips', set())
273
+                    floating_ip = []
274
+                    for routes_floatingip in routes_floatingips:
275
+                        if 'host' in routes_floatingip:
276
+                            del routes_floatingip['host']
277
+                        if 'description' in routes_floatingip:
278
+                            del routes_floatingip['description']
279
+                        if 'dns_name' in routes_floatingip:
280
+                            del routes_floatingip['dns_name']
281
+                        if 'created_at' in routes_floatingip:
282
+                            del routes_floatingip['created_at']
283
+                        if 'updated_at' in routes_floatingip:
284
+                            del routes_floatingip['updated_at']
285
+                        if 'dns_domain' in routes_floatingip:
286
+                            del routes_floatingip['dns_domain']
287
+                        if 'revision_number' in routes_floatingip:
288
+                            del routes_floatingip['revision_number']
289
+                        if 'fixed_ip_address_scope' in routes_floatingip:
290
+                            del routes_floatingip['fixed_ip_address_scope']
291
+                        if 'project_id' in routes_floatingip:
292
+                            del routes_floatingip['project_id']
293
+                        if 'floating_port_id' in routes_floatingip:
294
+                            del routes_floatingip['floating_port_id']
295
+                        routes_floatingip['status'] = \
296
+                            l3_constants.FLOATINGIP_STATUS_ACTIVE
297
+                        floating_ip.append(routes_floatingip)
298
+                        if router_info['id'] not in self.floating_status:
299
+                            self.floating_status[router_info['id']] = {
300
+                                routes_floatingip['id']:
301
+                                l3_constants.FLOATINGIP_STATUS_ACTIVE}
302
+                        else:
303
+                            status = self.floating_status[router_info['id']]
304
+                            status[routes_floatingip['id']] = \
305
+                                l3_constants.FLOATINGIP_STATUS_ACTIVE
306
+                    input = router_rest_data['input']
307
+                    input["floating-ips"] = floating_ip
308
+                else:
309
+                    input = router_rest_data['input']
310
+                    input["floating-ips"] = []
311
+        rest_info = '\n'
312
+        for k, v in router_rest_data['input'].items():
313
+            rest_info += '{0} is {1}\n'.format(k, v)
314
+            rest_info += '{0} is {1}\n'.format(k, v)
315
+        LOG.debug('rest_router_data:{0}'.format(rest_info))
316
+        return router_rest_data
317
+
318
+    def rest_update_router(self, router_info):
319
+        data = self.construct_router_rest_msg(router_info, 'ADD')
320
+        resource = 'update-router'
321
+        err_str = "Unable to create remote router: %s"
322
+        resp = self.rest_action('POST', resource, data, err_str)
323
+        if resp[0] == 0:
324
+            return False
325
+        return True
326
+
327
+    def rest_delete_router(self, router_id):
328
+        LOG.debug('While deleting,'
329
+                  'construct_router_info router_id:{0}'.format(router_id))
330
+        data = self.construct_router_rest_msg(router_id, 'DELETE')
331
+        resource = 'del-router'
332
+        err_str = "Unable to delete remote router: %s"
333
+        resp = self.rest_action('POST', resource, data, err_str)
334
+        if resp[0] == 0:
335
+            return False
336
+        return True
337
+
338
+    @staticmethod
339
+    def construct_all_routers_rest_msg(router_info):
340
+        router_rest_data = {
341
+            "input": {
342
+                "router-list": list(router_info)}
343
+        }
344
+        return router_rest_data
345
+
346
+    def rest_all_router_ids(self, all_router_ids):
347
+        LOG.info(_('While rest_all_router_ids, '
348
+                   'construct_router_info %s'), all_router_ids)
349
+        data = self.construct_all_routers_rest_msg(all_router_ids)
350
+        resource = 'sync-router-info'
351
+        err_str = "Unable to rest_all_router_ids: %s"
352
+        self.rest_action('POST', resource, data, err_str)
353
+        return True
354
+
355
+
356
+class L3PluginApi(object):
357
+    """Agent side of the l3 agent RPC API.
358
+
359
+    API version history:
360
+        1.0 - Initial version.
361
+        1.1 - Floating IP operational status updates
362
+
363
+    """
364
+
365
+    BASE_RPC_API_VERSION = '1.0'
366
+
367
+    def __init__(self, topic, host):
368
+        self.host = host
369
+        target = oslo_messaging.Target(topic=topic, version='1.0')
370
+        self.client = n_rpc.get_client(target)
371
+
372
+    def get_routers(self, context, router_ids=None):
373
+        """Make a remote process call to retrieve the sync data for routers."""
374
+        cctxt = self.client.prepare()
375
+        return cctxt.call(context, 'sync_routers', host=self.host,
376
+                          router_ids=router_ids)
377
+
378
+    def get_service_plugin_list(self, context):
379
+        """Make a call to get the list of activated services."""
380
+        cctxt = self.client.prepare(version='1.3')
381
+        return cctxt.call(context, 'get_service_plugin_list')
382
+
383
+    def update_floatingip_statuses(self, context, router_id, fip_statuses):
384
+        """Call the plugin update floating IPs's operational status."""
385
+        cctxt = self.client.prepare(version='1.1')
386
+        return cctxt.call(context, 'update_floatingip_statuses',
387
+                          router_id=router_id, fip_statuses=fip_statuses)
388
+
389
+
390
+class RouterInfo(object):
391
+
392
+    def __init__(self, router_id, root_helper, router):
393
+        self.router_id = router_id
394
+        self.ex_gw_port = None
395
+        self._snat_enabled = None
396
+        self._snat_action = None
397
+        self.internal_ports = []
398
+        self.root_helper = root_helper
399
+        # Invoke the setter for establishing initial SNAT action
400
+        self.router = router
401
+        self.ns_name = None
402
+        self.iptables_manager = iptables_manager.IptablesManager(
403
+            root_helper=root_helper,
404
+            # FIXME(danwent): use_ipv6=True,
405
+            namespace=self.ns_name)
406
+        self.routes = []
407
+
408
+    @property
409
+    def router(self):
410
+        return self._router
411
+
412
+    @router.setter
413
+    def router(self, value):
414
+        self._router = value
415
+        if not self._router:
416
+            return
417
+        # enable_snat by default if it wasn't specified by plugin
418
+        self._snat_enabled = self._router.get('enable_snat', True)
419
+        # Set a SNAT action for the router
420
+        if self._router.get('gw_port'):
421
+            self._snat_action = ('add_rules' if self._snat_enabled
422
+                                 else 'remove_rules')
423
+        elif self.ex_gw_port:
424
+            # Gateway port was removed, remove rules
425
+            self._snat_action = 'remove_rules'
426
+
427
+
428
+def get_rest_proxy_conf():
429
+    conf_proxy = cfg.ConfigOpts()
430
+    conf_proxy.register_opts(rest_proxy_opts, 'RESTPROXY')
431
+    conf_proxy(args=[], default_config_files=['/etc/neutron/plugin.ini'])
432
+    return conf_proxy
433
+
434
+
435
+def register_opts(conf):
436
+    conf.register_opts(l3_config.OPTS)
437
+    conf.register_opts(metadata_config.SHARED_OPTS)
438
+    try:
439
+        conf.register_opts(ha.OPTS)
440
+    except Exception:
441
+        ha_conf.register_l3_agent_ha_opts(conf)
442
+    config.register_interface_driver_opts_helper(conf)
443
+    config.register_agent_state_opts_helper(conf)
444
+    conf.register_opts(interface.OPTS)
445
+    conf.register_opts(external_process.OPTS)
446
+    try:
447
+        config.register_use_namespaces_opts_helper(conf)
448
+    except Exception:
449
+        conf.register_opts(pd.OPTS)
450
+        conf.register_opts(ra.OPTS)
451
+        config.register_availability_zone_opts_helper(conf)
452
+
453
+
454
+class ZenicAgent(manager.Manager):
455
+    """Manager for L3NatAgent
456
+
457
+        API version history:
458
+        1.0 initial Version
459
+        1.1 changed the type of the routers parameter
460
+            to the routers_updated method.
461
+            It was previously a list of routers in dict format.
462
+            It is now a list of router IDs only.
463
+            Per rpc versioning rules,  it is backwards compatible.
464
+    """
465
+    RPC_API_VERSION = '1.1'
466
+
467
+    OPTS = [
468
+        cfg.StrOpt('external_network_bridge', default='br-ex',
469
+                   help=_("Name of bridge used for external network "
470
+                          "traffic.")),
471
+        cfg.IntOpt('metadata_port',
472
+                   default=9697,
473
+                   help=_("TCP Port used by Neutron metadata namespace "
474
+                          "proxy.")),
475
+        cfg.IntOpt('send_arp_for_ha',
476
+                   default=0,
477
+                   help=_("Send this many gratuitous ARPs for HA setup, if "
478
+                          "less than or equal to 0, the feature is disabled")),
479
+        cfg.StrOpt('router_id', default='',
480
+                   help=_("If namespaces is disabled, the l3 agent can only"
481
+                          " configure a router that has the matching router "
482
+                          "ID.")),
483
+        cfg.BoolOpt('handle_internal_only_routers',
484
+                    default=True,
485
+                    help=_("Agent should implement routers with no gateway")),
486
+        cfg.StrOpt('gateway_external_network_id', default='',
487
+                   help=_("UUID of external network for routers implemented "
488
+                          "by the agents.")),
489
+        cfg.BoolOpt('enable_metadata_proxy', default=True,
490
+                    help=_("Allow running metadata proxy.")),
491
+        cfg.BoolOpt('router_delete_namespaces', default=False,
492
+                    help=_("Delete namespace after removing a router.")),
493
+        cfg.StrOpt('metadata_proxy_socket',
494
+                   default='$state_path/metadata_proxy',
495
+                   help=_('Location of Metadata Proxy UNIX domain '
496
+                          'socket')),
497
+    ]
498
+    target = oslo_messaging.Target(version='1.2')
499
+
500
+    def __init__(self, host, conf=None):
501
+        if conf:
502
+            self.conf = conf
503
+        else:
504
+            self.conf = cfg.CONF
505
+        self.root_helper = config.get_root_helper(self.conf)
506
+        self.router_info = {}
507
+        self.context = context.get_admin_context_without_session()
508
+        self.plugin_rpc = L3PluginApi(topics.L3PLUGIN, host)
509
+        self.fullsync = True
510
+        self.updated_routers = set()
511
+        self.removed_routers = set()
512
+        self.sync_progress = False
513
+        self.servers = None
514
+        self.fail_update_rest_router_id = set()
515
+        self.fail_delete_rest_router_id = set()
516
+        conf_proxy = get_rest_proxy_conf()
517
+        self.whole_syncing_not_succ_yet = False
518
+        self.sync_protect_tick = 0
519
+        self.agent_id = 'zenic-agent-%s' % self.conf.host
520
+        self.zenic_rpc = ZenicPluginApi(topics.PLUGIN)
521
+        self.up_gw_status = conf_proxy.RESTPROXY.up_gw_status
522
+        self.sync_router = conf_proxy.RESTPROXY.sync_router
523
+        if conf_proxy.RESTPROXY.servers is not '':
524
+            self.servers = ZenicL3RestServerPool(
525
+                conf_proxy.RESTPROXY.servers,
526
+                conf_proxy.RESTPROXY.server_auth,
527
+                conf_proxy.RESTPROXY.zenic_version,
528
+                conf_proxy.RESTPROXY.server_ssl,
529
+                conf_proxy.RESTPROXY.no_ssl_validation,
530
+                conf_proxy.RESTPROXY.ssl_sticky,
531
+                conf_proxy.RESTPROXY.ssl_cert_directory,
532
+                conf_proxy.RESTPROXY.consistency_interval,
533
+                conf_proxy.RESTPROXY.server_timeout,
534
+                conf_proxy.RESTPROXY.cache_connections,
535
+                conf_proxy.RESTPROXY.base_url,
536
+                conf_proxy.RESTPROXY.op_version)
537
+        # self.rpc_loop = loopingcall.FixedIntervalLoopingCall(
538
+        #     self._rpc_loop)
539
+        # self.rpc_loop.start(interval=RPC_LOOP_INTERVAL)
540
+        super(ZenicAgent, self).__init__(host=host)
541
+        self.target_ex_net_id = None
542
+        self.sync_routers_chunk_size = SYNC_ROUTERS_MAX_CHUNK_SIZE
543
+
544
+    def router_deleted(self, context, router_id):
545
+        """Deal with router deletion RPC message."""
546
+        LOG.info(_('zenic_agent Got router deleted notification for %s'),
547
+                 router_id)
548
+        try:
549
+            with lockutils.lock("zenic_agent_remove_router"):
550
+                LOG.debug('router_deleted Got remove mutex')
551
+                self.removed_routers.add(router_id)
552
+        except Exception as e:
553
+            LOG.debug("lockutils, except:%s", str(e))
554
+
555
+    def routers_updated(self, context, routers):
556
+        """Deal with routers modification and creation RPC message."""
557
+        LOG.info(_(' zenic_agent Got routers updated notification :%s'),
558
+                 routers)
559
+        if routers:
560
+            # This is needed for backward compatibility
561
+            if isinstance(routers[0], dict):
562
+                routers = [router['id'] for router in routers]
563
+            try:
564
+                with lockutils.lock("zenic_agent_update_router"):
565
+                    LOG.info(_('routers_updated Got update mutex'))
566
+                    self.updated_routers.update(routers)
567
+            except Exception as e:
568
+                LOG.debug("lockutils, except:%s", str(e))
569
+
570
+    def router_added_to_agent(self, context, payload):
571
+        pass
572
+
573
+    def _process_update_rest_fail_routers(self, routers):
574
+        for r in routers:
575
+            if self.servers:
576
+                if self.servers.rest_update_router(r):
577
+                    self.fail_update_rest_router_id.discard(r['id'])
578
+
579
+    def _sync_all_valid_routers(self, routers):
580
+        # pool = eventlet.GreenPool()
581
+        return self.servers.rest_all_router_ids(routers)
582
+
583
+    def _process_routers(self, routers):
584
+        # pool = eventlet.GreenPool()
585
+        for r in routers:
586
+            if self.servers:
587
+                if not self.servers.rest_update_router(r):
588
+                    self.fail_update_rest_router_id.add(r['id'])
589
+                else:
590
+                    internal_interfaces = r.get('_interfaces', set())
591
+                    internal_interfaces_devices = list()
592
+                    if internal_interfaces:
593
+                        internal_interfaces_devices = \
594
+                            [intf['mac_address']
595
+                             for intf in internal_interfaces]
596
+                    for device in internal_interfaces_devices:
597
+                        LOG.info(_('up router internal %s status'), device)
598
+                        self.zenic_rpc.update_device_up(
599
+                            self.context,
600
+                            device,
601
+                            self.agent_id,
602
+                            self.conf.host)
603
+                    if self.up_gw_status == "True":
604
+                        if r.get('gw_port_id'):
605
+                            device = r.get('gw_port')['mac_address']
606
+                            LOG.info(_('up router gw %s status'), device)
607
+                            self.zenic_rpc.update_device_up(
608
+                                self.context,
609
+                                device,
610
+                                self.agent_id,
611
+                                self.conf.host)
612
+                    if r['id'] in self.servers.floating_status:
613
+                        LOG.debug(_('update floatingip_statuses: %s'),
614
+                                  self.servers.floating_status[r['id']])
615
+                        self.plugin_rpc.update_floatingip_statuses(
616
+                            self.context,
617
+                            r['id'],
618
+                            self.servers.floating_status[r['id']])
619
+                        self.servers.floating_status[r['id']] = {}
620
+                        if '_floatingips' not in r:
621
+                            del self.servers.floating_status[r['id']]
622
+
623
+    @staticmethod
624
+    def get_all_router_ids(context):
625
+        query = context.session.query(l3_db.Router.id)
626
+        return [item[0] for item in query]
627
+
628
+    def _sync_all_router_restconf(self, context):
629
+        admin_context = qcontext.get_admin_context()
630
+        routers = self.get_all_router_ids(admin_context)
631
+        LOG.info(_('zenic_agent, starting, get_all_routers:%s'), routers)
632
+        routers = set(router for router in routers)
633
+        self.updated_routers.update(routers)
634
+        now_valid_rout