~ubuntu-branches/ubuntu/vivid/neutron/vivid-updates

« back to all changes in this revision

Viewing changes to neutron/plugins/vmware/vshield/edge_appliance_driver.py

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2015-03-30 11:17:19 UTC
  • mfrom: (1.1.21)
  • Revision ID: package-import@ubuntu.com-20150330111719-h0gx7233p4jkkgfh
Tags: 1:2015.1~b3-0ubuntu1
* New upstream milestone release:
  - d/control: Align version requirements with upstream.
  - d/control: Add new dependency on oslo-log.
  - d/p/*: Rebase.
  - d/control,d/neutron-plugin-hyperv*: Dropped, decomposed into
    separate project upstream.
  - d/control,d/neutron-plugin-openflow*: Dropped, decomposed into
    separate project upstream.
  - d/neutron-common.install: Add neutron-rootwrap-daemon and 
    neutron-keepalived-state-change binaries.
  - d/rules: Ignore neutron-hyperv-agent when installing; only for Windows.
  - d/neutron-plugin-cisco.install: Drop neutron-cisco-cfg-agent as
    decomposed into separate project upstream.
  - d/neutron-plugin-vmware.install: Drop neutron-check-nsx-config and
    neutron-nsx-manage as decomposed into separate project upstream.
  - d/control: Add dependency on python-neutron-fwaas to neutron-l3-agent.
* d/pydist-overrides: Add overrides for oslo packages.
* d/control: Fixup type in package description (LP: #1263539).
* d/p/fixup-driver-test-execution.patch: Cherry pick fix from upstream VCS
  to support unit test exection in out-of-tree vendor drivers.
* d/neutron-common.postinst: Allow general access to /etc/neutron but limit
  access to root/neutron to /etc/neutron/neutron.conf to support execution
  of unit tests in decomposed vendor drivers.
* d/control: Add dependency on python-neutron-fwaas to neutron-l3-agent
  package.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
# Copyright 2013 VMware, 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
 
from oslo.serialization import jsonutils
16
 
from oslo.utils import excutils
17
 
 
18
 
from neutron.i18n import _LE
19
 
from neutron.openstack.common import log as logging
20
 
from neutron.plugins.vmware.common import utils
21
 
from neutron.plugins.vmware.vshield.common import constants as vcns_const
22
 
from neutron.plugins.vmware.vshield.common import exceptions
23
 
from neutron.plugins.vmware.vshield.tasks import constants
24
 
from neutron.plugins.vmware.vshield.tasks import tasks
25
 
 
26
 
LOG = logging.getLogger(__name__)
27
 
 
28
 
 
29
 
class EdgeApplianceDriver(object):
30
 
    def __init__(self):
31
 
        # store the last task per edge that has the latest config
32
 
        self.updated_task = {
33
 
            'nat': {},
34
 
            'route': {},
35
 
        }
36
 
 
37
 
    def _assemble_edge(self, name, appliance_size="compact",
38
 
                       deployment_container_id=None, datacenter_moid=None,
39
 
                       enable_aesni=True, hypervisor_assist=False,
40
 
                       enable_fips=False, remote_access=False):
41
 
        edge = {
42
 
            'name': name,
43
 
            'fqdn': name,
44
 
            'hypervisorAssist': hypervisor_assist,
45
 
            'type': 'gatewayServices',
46
 
            'enableAesni': enable_aesni,
47
 
            'enableFips': enable_fips,
48
 
            'cliSettings': {
49
 
                'remoteAccess': remote_access
50
 
            },
51
 
            'appliances': {
52
 
                'applianceSize': appliance_size
53
 
            },
54
 
            'vnics': {
55
 
                'vnics': []
56
 
            }
57
 
        }
58
 
        if deployment_container_id:
59
 
            edge['appliances']['deploymentContainerId'] = (
60
 
                deployment_container_id)
61
 
        if datacenter_moid:
62
 
            edge['datacenterMoid'] = datacenter_moid
63
 
 
64
 
        return edge
65
 
 
66
 
    def _assemble_edge_appliance(self, resource_pool_id, datastore_id):
67
 
        appliance = {}
68
 
        if resource_pool_id:
69
 
            appliance['resourcePoolId'] = resource_pool_id
70
 
        if datastore_id:
71
 
            appliance['datastoreId'] = datastore_id
72
 
        return appliance
73
 
 
74
 
    def _assemble_edge_vnic(self, name, index, portgroup_id,
75
 
                            primary_address=None, subnet_mask=None,
76
 
                            secondary=None,
77
 
                            type="internal",
78
 
                            enable_proxy_arp=False,
79
 
                            enable_send_redirects=True,
80
 
                            is_connected=True,
81
 
                            mtu=1500):
82
 
        vnic = {
83
 
            'index': index,
84
 
            'name': name,
85
 
            'type': type,
86
 
            'portgroupId': portgroup_id,
87
 
            'mtu': mtu,
88
 
            'enableProxyArp': enable_proxy_arp,
89
 
            'enableSendRedirects': enable_send_redirects,
90
 
            'isConnected': is_connected
91
 
        }
92
 
        if primary_address and subnet_mask:
93
 
            address_group = {
94
 
                'primaryAddress': primary_address,
95
 
                'subnetMask': subnet_mask
96
 
            }
97
 
            if secondary:
98
 
                address_group['secondaryAddresses'] = {
99
 
                    'ipAddress': secondary,
100
 
                    'type': 'IpAddressesDto'
101
 
                }
102
 
 
103
 
            vnic['addressGroups'] = {
104
 
                'addressGroups': [address_group]
105
 
            }
106
 
 
107
 
        return vnic
108
 
 
109
 
    def _edge_status_to_level(self, status):
110
 
        if status == 'GREEN':
111
 
            status_level = vcns_const.RouterStatus.ROUTER_STATUS_ACTIVE
112
 
        elif status in ('GREY', 'YELLOW'):
113
 
            status_level = vcns_const.RouterStatus.ROUTER_STATUS_DOWN
114
 
        else:
115
 
            status_level = vcns_const.RouterStatus.ROUTER_STATUS_ERROR
116
 
        return status_level
117
 
 
118
 
    def _enable_loadbalancer(self, edge):
119
 
        if not edge.get('featureConfigs') or (
120
 
            not edge['featureConfigs'].get('features')):
121
 
            edge['featureConfigs'] = {'features': []}
122
 
        edge['featureConfigs']['features'].append(
123
 
            {'featureType': 'loadbalancer_4.0',
124
 
             'enabled': True})
125
 
 
126
 
    def get_edge_status(self, edge_id):
127
 
        try:
128
 
            response = self.vcns.get_edge_status(edge_id)[1]
129
 
            status_level = self._edge_status_to_level(
130
 
                response['edgeStatus'])
131
 
        except exceptions.VcnsApiException as e:
132
 
            LOG.exception(_LE("VCNS: Failed to get edge status:\n%s"),
133
 
                          e.response)
134
 
            status_level = vcns_const.RouterStatus.ROUTER_STATUS_ERROR
135
 
            try:
136
 
                desc = jsonutils.loads(e.response)
137
 
                if desc.get('errorCode') == (
138
 
                    vcns_const.VCNS_ERROR_CODE_EDGE_NOT_RUNNING):
139
 
                    status_level = (
140
 
                        vcns_const.RouterStatus.ROUTER_STATUS_DOWN)
141
 
            except ValueError:
142
 
                LOG.exception(e.response)
143
 
 
144
 
        return status_level
145
 
 
146
 
    def get_edges_statuses(self):
147
 
        edges_status_level = {}
148
 
        edges = self._get_edges()
149
 
        for edge in edges['edgePage'].get('data', []):
150
 
            edge_id = edge['id']
151
 
            status = edge['edgeStatus']
152
 
            edges_status_level[edge_id] = self._edge_status_to_level(status)
153
 
 
154
 
        return edges_status_level
155
 
 
156
 
    def _update_interface(self, task):
157
 
        edge_id = task.userdata['edge_id']
158
 
        config = task.userdata['config']
159
 
        LOG.debug("VCNS: start updating vnic %s", config)
160
 
        try:
161
 
            self.vcns.update_interface(edge_id, config)
162
 
        except exceptions.VcnsApiException as e:
163
 
            with excutils.save_and_reraise_exception():
164
 
                LOG.exception(_LE("VCNS: Failed to update vnic %(config)s:\n"
165
 
                                  "%(response)s"), {
166
 
                                    'config': config,
167
 
                                    'response': e.response})
168
 
        except Exception:
169
 
            with excutils.save_and_reraise_exception():
170
 
                LOG.exception(_LE("VCNS: Failed to update vnic %d"),
171
 
                              config['index'])
172
 
 
173
 
        return constants.TaskStatus.COMPLETED
174
 
 
175
 
    def update_interface(self, router_id, edge_id, index, network,
176
 
                         address=None, netmask=None, secondary=None,
177
 
                         jobdata=None):
178
 
        LOG.debug("VCNS: update vnic %(index)d: %(addr)s %(netmask)s", {
179
 
            'index': index, 'addr': address, 'netmask': netmask})
180
 
        if index == vcns_const.EXTERNAL_VNIC_INDEX:
181
 
            name = vcns_const.EXTERNAL_VNIC_NAME
182
 
            intf_type = 'uplink'
183
 
        elif index == vcns_const.INTERNAL_VNIC_INDEX:
184
 
            name = vcns_const.INTERNAL_VNIC_NAME
185
 
            intf_type = 'internal'
186
 
        else:
187
 
            msg = _("Vnic %d currently not supported") % index
188
 
            raise exceptions.VcnsGeneralException(msg)
189
 
 
190
 
        config = self._assemble_edge_vnic(
191
 
            name, index, network, address, netmask, secondary, type=intf_type)
192
 
 
193
 
        userdata = {
194
 
            'edge_id': edge_id,
195
 
            'config': config,
196
 
            'jobdata': jobdata
197
 
        }
198
 
        task_name = "update-interface-%s-%d" % (edge_id, index)
199
 
        task = tasks.Task(task_name, router_id,
200
 
                          self._update_interface, userdata=userdata)
201
 
        task.add_result_monitor(self.callbacks.interface_update_result)
202
 
        self.task_manager.add(task)
203
 
        return task
204
 
 
205
 
    def _deploy_edge(self, task):
206
 
        userdata = task.userdata
207
 
        name = userdata['router_name']
208
 
        LOG.debug("VCNS: start deploying edge %s", name)
209
 
        request = userdata['request']
210
 
        try:
211
 
            header = self.vcns.deploy_edge(request)[0]
212
 
            objuri = header['location']
213
 
            job_id = objuri[objuri.rfind("/") + 1:]
214
 
            response = self.vcns.get_edge_id(job_id)[1]
215
 
            edge_id = response['edgeId']
216
 
            LOG.debug("VCNS: deploying edge %s", edge_id)
217
 
            userdata['edge_id'] = edge_id
218
 
            status = constants.TaskStatus.PENDING
219
 
        except exceptions.VcnsApiException:
220
 
            with excutils.save_and_reraise_exception():
221
 
                LOG.exception(_LE("VCNS: deploy edge failed for router %s."),
222
 
                              name)
223
 
 
224
 
        return status
225
 
 
226
 
    def _status_edge(self, task):
227
 
        edge_id = task.userdata['edge_id']
228
 
        try:
229
 
            response = self.vcns.get_edge_deploy_status(edge_id)[1]
230
 
            task.userdata['retries'] = 0
231
 
            system_status = response.get('systemStatus', None)
232
 
            if system_status is None:
233
 
                status = constants.TaskStatus.PENDING
234
 
            elif system_status == 'good':
235
 
                status = constants.TaskStatus.COMPLETED
236
 
            else:
237
 
                status = constants.TaskStatus.ERROR
238
 
        except exceptions.VcnsApiException:
239
 
            with excutils.save_and_reraise_exception():
240
 
                LOG.exception(_LE("VCNS: Edge %s status query failed."),
241
 
                              edge_id)
242
 
        except Exception:
243
 
            retries = task.userdata.get('retries', 0) + 1
244
 
            if retries < 3:
245
 
                task.userdata['retries'] = retries
246
 
                LOG.exception(_LE("VCNS: Unable to retrieve edge %(edge_id)s "
247
 
                                  "status. Retry %(retries)d."),
248
 
                              {'edge_id': edge_id,
249
 
                               'retries': retries})
250
 
                status = constants.TaskStatus.PENDING
251
 
            else:
252
 
                LOG.exception(_LE("VCNS: Unable to retrieve edge %s status. "
253
 
                                 "Abort."), edge_id)
254
 
                status = constants.TaskStatus.ERROR
255
 
        LOG.debug("VCNS: Edge %s status", edge_id)
256
 
        return status
257
 
 
258
 
    def _result_edge(self, task):
259
 
        router_name = task.userdata['router_name']
260
 
        edge_id = task.userdata.get('edge_id')
261
 
        if task.status != constants.TaskStatus.COMPLETED:
262
 
            LOG.error(_LE("VCNS: Failed to deploy edge %(edge_id)s "
263
 
                          "for %(name)s, status %(status)d"), {
264
 
                            'edge_id': edge_id,
265
 
                            'name': router_name,
266
 
                            'status': task.status
267
 
                        })
268
 
        else:
269
 
            LOG.debug("VCNS: Edge %(edge_id)s deployed for "
270
 
                      "router %(name)s", {
271
 
                          'edge_id': edge_id, 'name': router_name
272
 
                      })
273
 
 
274
 
    def _delete_edge(self, task):
275
 
        edge_id = task.userdata['edge_id']
276
 
        LOG.debug("VCNS: start destroying edge %s", edge_id)
277
 
        status = constants.TaskStatus.COMPLETED
278
 
        if edge_id:
279
 
            try:
280
 
                self.vcns.delete_edge(edge_id)
281
 
            except exceptions.ResourceNotFound:
282
 
                pass
283
 
            except exceptions.VcnsApiException as e:
284
 
                LOG.exception(_LE("VCNS: Failed to delete %(edge_id)s:\n"
285
 
                                  "%(response)s"),
286
 
                              {'edge_id': edge_id, 'response': e.response})
287
 
                status = constants.TaskStatus.ERROR
288
 
            except Exception:
289
 
                LOG.exception(_LE("VCNS: Failed to delete %s"), edge_id)
290
 
                status = constants.TaskStatus.ERROR
291
 
 
292
 
        return status
293
 
 
294
 
    def _get_edges(self):
295
 
        try:
296
 
            return self.vcns.get_edges()[1]
297
 
        except exceptions.VcnsApiException as e:
298
 
            with excutils.save_and_reraise_exception():
299
 
                LOG.exception(_LE("VCNS: Failed to get edges:\n%s"),
300
 
                              e.response)
301
 
 
302
 
    def deploy_edge(self, router_id, name, internal_network, jobdata=None,
303
 
                    wait_for_exec=False, loadbalancer_enable=True):
304
 
        task_name = 'deploying-%s' % name
305
 
        edge_name = name
306
 
        edge = self._assemble_edge(
307
 
            edge_name, datacenter_moid=self.datacenter_moid,
308
 
            deployment_container_id=self.deployment_container_id,
309
 
            appliance_size='large', remote_access=True)
310
 
        appliance = self._assemble_edge_appliance(self.resource_pool_id,
311
 
                                                  self.datastore_id)
312
 
        if appliance:
313
 
            edge['appliances']['appliances'] = [appliance]
314
 
 
315
 
        vnic_external = self._assemble_edge_vnic(
316
 
            vcns_const.EXTERNAL_VNIC_NAME, vcns_const.EXTERNAL_VNIC_INDEX,
317
 
            self.external_network, type="uplink")
318
 
        edge['vnics']['vnics'].append(vnic_external)
319
 
        vnic_inside = self._assemble_edge_vnic(
320
 
            vcns_const.INTERNAL_VNIC_NAME, vcns_const.INTERNAL_VNIC_INDEX,
321
 
            internal_network,
322
 
            vcns_const.INTEGRATION_EDGE_IPADDRESS,
323
 
            vcns_const.INTEGRATION_SUBNET_NETMASK,
324
 
            type="internal")
325
 
        edge['vnics']['vnics'].append(vnic_inside)
326
 
        if loadbalancer_enable:
327
 
            self._enable_loadbalancer(edge)
328
 
        userdata = {
329
 
            'request': edge,
330
 
            'router_name': name,
331
 
            'jobdata': jobdata
332
 
        }
333
 
        task = tasks.Task(task_name, router_id,
334
 
                          self._deploy_edge,
335
 
                          status_callback=self._status_edge,
336
 
                          result_callback=self._result_edge,
337
 
                          userdata=userdata)
338
 
        task.add_executed_monitor(self.callbacks.edge_deploy_started)
339
 
        task.add_result_monitor(self.callbacks.edge_deploy_result)
340
 
        self.task_manager.add(task)
341
 
 
342
 
        if wait_for_exec:
343
 
            # wait until the deploy task is executed so edge_id is available
344
 
            task.wait(constants.TaskState.EXECUTED)
345
 
 
346
 
        return task
347
 
 
348
 
    def delete_edge(self, router_id, edge_id, jobdata=None):
349
 
        task_name = 'delete-%s' % edge_id
350
 
        userdata = {
351
 
            'router_id': router_id,
352
 
            'edge_id': edge_id,
353
 
            'jobdata': jobdata
354
 
        }
355
 
        task = tasks.Task(task_name, router_id, self._delete_edge,
356
 
                          userdata=userdata)
357
 
        task.add_result_monitor(self.callbacks.edge_delete_result)
358
 
        self.task_manager.add(task)
359
 
        return task
360
 
 
361
 
    def _assemble_nat_rule(self, action, original_address,
362
 
                           translated_address,
363
 
                           vnic_index=vcns_const.EXTERNAL_VNIC_INDEX,
364
 
                           enabled=True):
365
 
        nat_rule = {}
366
 
        nat_rule['action'] = action
367
 
        nat_rule['vnic'] = vnic_index
368
 
        nat_rule['originalAddress'] = original_address
369
 
        nat_rule['translatedAddress'] = translated_address
370
 
        nat_rule['enabled'] = enabled
371
 
        return nat_rule
372
 
 
373
 
    def get_nat_config(self, edge_id):
374
 
        try:
375
 
            return self.vcns.get_nat_config(edge_id)[1]
376
 
        except exceptions.VcnsApiException as e:
377
 
            with excutils.save_and_reraise_exception():
378
 
                LOG.exception(_LE("VCNS: Failed to get nat config:\n%s"),
379
 
                              e.response)
380
 
 
381
 
    def _create_nat_rule(self, task):
382
 
        # TODO(fank): use POST for optimization
383
 
        #             return rule_id for future reference
384
 
        rule = task.userdata['rule']
385
 
        LOG.debug("VCNS: start creating nat rules: %s", rule)
386
 
        edge_id = task.userdata['edge_id']
387
 
        nat = self.get_nat_config(edge_id)
388
 
        location = task.userdata['location']
389
 
 
390
 
        del nat['version']
391
 
 
392
 
        if location is None or location == vcns_const.APPEND:
393
 
            nat['rules']['natRulesDtos'].append(rule)
394
 
        else:
395
 
            nat['rules']['natRulesDtos'].insert(location, rule)
396
 
 
397
 
        try:
398
 
            self.vcns.update_nat_config(edge_id, nat)
399
 
            status = constants.TaskStatus.COMPLETED
400
 
        except exceptions.VcnsApiException as e:
401
 
            LOG.exception(_LE("VCNS: Failed to create snat rule:\n%s"),
402
 
                          e.response)
403
 
            status = constants.TaskStatus.ERROR
404
 
 
405
 
        return status
406
 
 
407
 
    def create_snat_rule(self, router_id, edge_id, src, translated,
408
 
                         jobdata=None, location=None):
409
 
        LOG.debug("VCNS: create snat rule %(src)s/%(translated)s", {
410
 
            'src': src, 'translated': translated})
411
 
        snat_rule = self._assemble_nat_rule("snat", src, translated)
412
 
        userdata = {
413
 
            'router_id': router_id,
414
 
            'edge_id': edge_id,
415
 
            'rule': snat_rule,
416
 
            'location': location,
417
 
            'jobdata': jobdata
418
 
        }
419
 
        task_name = "create-snat-%s-%s-%s" % (edge_id, src, translated)
420
 
        task = tasks.Task(task_name, router_id, self._create_nat_rule,
421
 
                          userdata=userdata)
422
 
        task.add_result_monitor(self.callbacks.snat_create_result)
423
 
        self.task_manager.add(task)
424
 
        return task
425
 
 
426
 
    def _delete_nat_rule(self, task):
427
 
        # TODO(fank): pass in rule_id for optimization
428
 
        #             handle routes update for optimization
429
 
        edge_id = task.userdata['edge_id']
430
 
        address = task.userdata['address']
431
 
        addrtype = task.userdata['addrtype']
432
 
        LOG.debug("VCNS: start deleting %(type)s rules: %(addr)s", {
433
 
            'type': addrtype, 'addr': address})
434
 
        nat = self.get_nat_config(edge_id)
435
 
        del nat['version']
436
 
        status = constants.TaskStatus.COMPLETED
437
 
        for nat_rule in nat['rules']['natRulesDtos']:
438
 
            if nat_rule[addrtype] == address:
439
 
                rule_id = nat_rule['ruleId']
440
 
                try:
441
 
                    self.vcns.delete_nat_rule(edge_id, rule_id)
442
 
                except exceptions.VcnsApiException as e:
443
 
                    LOG.exception(_LE("VCNS: Failed to delete snat rule:\n"
444
 
                                      "%s"), e.response)
445
 
                    status = constants.TaskStatus.ERROR
446
 
 
447
 
        return status
448
 
 
449
 
    def delete_snat_rule(self, router_id, edge_id, src, jobdata=None):
450
 
        LOG.debug("VCNS: delete snat rule %s", src)
451
 
        userdata = {
452
 
            'edge_id': edge_id,
453
 
            'address': src,
454
 
            'addrtype': 'originalAddress',
455
 
            'jobdata': jobdata
456
 
        }
457
 
        task_name = "delete-snat-%s-%s" % (edge_id, src)
458
 
        task = tasks.Task(task_name, router_id, self._delete_nat_rule,
459
 
                          userdata=userdata)
460
 
        task.add_result_monitor(self.callbacks.snat_delete_result)
461
 
        self.task_manager.add(task)
462
 
        return task
463
 
 
464
 
    def create_dnat_rule(self, router_id, edge_id, dst, translated,
465
 
                         jobdata=None, location=None):
466
 
        # TODO(fank): use POST for optimization
467
 
        #             return rule_id for future reference
468
 
        LOG.debug("VCNS: create dnat rule %(dst)s/%(translated)s", {
469
 
            'dst': dst, 'translated': translated})
470
 
        dnat_rule = self._assemble_nat_rule(
471
 
            "dnat", dst, translated)
472
 
        userdata = {
473
 
            'router_id': router_id,
474
 
            'edge_id': edge_id,
475
 
            'rule': dnat_rule,
476
 
            'location': location,
477
 
            'jobdata': jobdata
478
 
        }
479
 
        task_name = "create-dnat-%s-%s-%s" % (edge_id, dst, translated)
480
 
        task = tasks.Task(task_name, router_id, self._create_nat_rule,
481
 
                          userdata=userdata)
482
 
        task.add_result_monitor(self.callbacks.dnat_create_result)
483
 
        self.task_manager.add(task)
484
 
        return task
485
 
 
486
 
    def delete_dnat_rule(self, router_id, edge_id, translated,
487
 
                         jobdata=None):
488
 
        # TODO(fank): pass in rule_id for optimization
489
 
        LOG.debug("VCNS: delete dnat rule %s", translated)
490
 
        userdata = {
491
 
            'edge_id': edge_id,
492
 
            'address': translated,
493
 
            'addrtype': 'translatedAddress',
494
 
            'jobdata': jobdata
495
 
        }
496
 
        task_name = "delete-dnat-%s-%s" % (edge_id, translated)
497
 
        task = tasks.Task(task_name, router_id, self._delete_nat_rule,
498
 
                          userdata=userdata)
499
 
        task.add_result_monitor(self.callbacks.dnat_delete_result)
500
 
        self.task_manager.add(task)
501
 
        return task
502
 
 
503
 
    def _update_nat_rule(self, task):
504
 
        # TODO(fank): use POST for optimization
505
 
        #             return rule_id for future reference
506
 
        edge_id = task.userdata['edge_id']
507
 
        if task != self.updated_task['nat'][edge_id]:
508
 
            # this task does not have the latest config, abort now
509
 
            # for speedup
510
 
            return constants.TaskStatus.ABORT
511
 
 
512
 
        rules = task.userdata['rules']
513
 
        LOG.debug("VCNS: start updating nat rules: %s", rules)
514
 
 
515
 
        nat = {
516
 
            'featureType': 'nat',
517
 
            'rules': {
518
 
                'natRulesDtos': rules
519
 
            }
520
 
        }
521
 
 
522
 
        try:
523
 
            self.vcns.update_nat_config(edge_id, nat)
524
 
            status = constants.TaskStatus.COMPLETED
525
 
        except exceptions.VcnsApiException as e:
526
 
            LOG.exception(_LE("VCNS: Failed to create snat rule:\n%s"),
527
 
                          e.response)
528
 
            status = constants.TaskStatus.ERROR
529
 
 
530
 
        return status
531
 
 
532
 
    def update_nat_rules(self, router_id, edge_id, snats, dnats,
533
 
                         jobdata=None):
534
 
        LOG.debug("VCNS: update nat rule\n"
535
 
                  "SNAT:%(snat)s\n"
536
 
                  "DNAT:%(dnat)s\n", {
537
 
                      'snat': snats, 'dnat': dnats})
538
 
        nat_rules = []
539
 
 
540
 
        for dnat in dnats:
541
 
            nat_rules.append(self._assemble_nat_rule(
542
 
                'dnat', dnat['dst'], dnat['translated']))
543
 
            nat_rules.append(self._assemble_nat_rule(
544
 
                'snat', dnat['translated'], dnat['dst']))
545
 
 
546
 
        for snat in snats:
547
 
            nat_rules.append(self._assemble_nat_rule(
548
 
                'snat', snat['src'], snat['translated']))
549
 
 
550
 
        userdata = {
551
 
            'edge_id': edge_id,
552
 
            'rules': nat_rules,
553
 
            'jobdata': jobdata,
554
 
        }
555
 
        task_name = "update-nat-%s" % edge_id
556
 
        task = tasks.Task(task_name, router_id, self._update_nat_rule,
557
 
                          userdata=userdata)
558
 
        task.add_result_monitor(self.callbacks.nat_update_result)
559
 
        self.updated_task['nat'][edge_id] = task
560
 
        self.task_manager.add(task)
561
 
        return task
562
 
 
563
 
    def _update_routes(self, task):
564
 
        edge_id = task.userdata['edge_id']
565
 
        if (task != self.updated_task['route'][edge_id] and
566
 
            task.userdata.get('skippable', True)):
567
 
            # this task does not have the latest config, abort now
568
 
            # for speedup
569
 
            return constants.TaskStatus.ABORT
570
 
        gateway = task.userdata['gateway']
571
 
        routes = task.userdata['routes']
572
 
        LOG.debug("VCNS: start updating routes for %s", edge_id)
573
 
        static_routes = []
574
 
        for route in routes:
575
 
            static_routes.append({
576
 
                "description": "",
577
 
                "vnic": vcns_const.INTERNAL_VNIC_INDEX,
578
 
                "network": route['cidr'],
579
 
                "nextHop": route['nexthop']
580
 
            })
581
 
        request = {
582
 
            "staticRoutes": {
583
 
                "staticRoutes": static_routes
584
 
            }
585
 
        }
586
 
        if gateway:
587
 
            request["defaultRoute"] = {
588
 
                "description": "default-gateway",
589
 
                "gatewayAddress": gateway,
590
 
                "vnic": vcns_const.EXTERNAL_VNIC_INDEX
591
 
            }
592
 
        try:
593
 
            self.vcns.update_routes(edge_id, request)
594
 
            status = constants.TaskStatus.COMPLETED
595
 
        except exceptions.VcnsApiException as e:
596
 
            LOG.exception(_LE("VCNS: Failed to update routes:\n%s"),
597
 
                          e.response)
598
 
            status = constants.TaskStatus.ERROR
599
 
 
600
 
        return status
601
 
 
602
 
    def update_routes(self, router_id, edge_id, gateway, routes,
603
 
                      skippable=True, jobdata=None):
604
 
        if gateway:
605
 
            gateway = gateway.split('/')[0]
606
 
 
607
 
        userdata = {
608
 
            'edge_id': edge_id,
609
 
            'gateway': gateway,
610
 
            'routes': routes,
611
 
            'skippable': skippable,
612
 
            'jobdata': jobdata
613
 
        }
614
 
        task_name = "update-routes-%s" % (edge_id)
615
 
        task = tasks.Task(task_name, router_id, self._update_routes,
616
 
                          userdata=userdata)
617
 
        task.add_result_monitor(self.callbacks.routes_update_result)
618
 
        self.updated_task['route'][edge_id] = task
619
 
        self.task_manager.add(task)
620
 
        return task
621
 
 
622
 
    def create_lswitch(self, name, tz_config, tags=None,
623
 
                       port_isolation=False, replication_mode="service"):
624
 
        lsconfig = {
625
 
            'display_name': utils.check_and_truncate(name),
626
 
            "tags": tags or [],
627
 
            "type": "LogicalSwitchConfig",
628
 
            "_schema": "/ws.v1/schema/LogicalSwitchConfig",
629
 
            "transport_zones": tz_config
630
 
        }
631
 
        if port_isolation is bool:
632
 
            lsconfig["port_isolation_enabled"] = port_isolation
633
 
        if replication_mode:
634
 
            lsconfig["replication_mode"] = replication_mode
635
 
 
636
 
        response = self.vcns.create_lswitch(lsconfig)[1]
637
 
        return response
638
 
 
639
 
    def delete_lswitch(self, lswitch_id):
640
 
        self.vcns.delete_lswitch(lswitch_id)
641
 
 
642
 
    def get_loadbalancer_config(self, edge_id):
643
 
        try:
644
 
            header, response = self.vcns.get_loadbalancer_config(
645
 
                edge_id)
646
 
        except exceptions.VcnsApiException:
647
 
            with excutils.save_and_reraise_exception():
648
 
                LOG.exception(_LE("Failed to get service config"))
649
 
        return response
650
 
 
651
 
    def enable_service_loadbalancer(self, edge_id):
652
 
        config = self.get_loadbalancer_config(
653
 
            edge_id)
654
 
        if not config['enabled']:
655
 
            config['enabled'] = True
656
 
        try:
657
 
            self.vcns.enable_service_loadbalancer(edge_id, config)
658
 
        except exceptions.VcnsApiException:
659
 
            with excutils.save_and_reraise_exception():
660
 
                LOG.exception(_LE("Failed to enable loadbalancer "
661
 
                                  "service config"))