A common library that interfaces with VMware NSX.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

2119 行
64KB

  1. # Copyright 2017 VMware, Inc.
  2. # All Rights Reserved
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License"); you may
  5. # not use this file except in compliance with the License. You may obtain
  6. # a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  12. # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  13. # License for the specific language governing permissions and limitations
  14. # under the License.
  15. #
  16. import abc
  17. from distutils import version
  18. from oslo_log import log as logging
  19. import six
  20. from vmware_nsxlib.v3 import nsx_constants
  21. from vmware_nsxlib.v3.policy import constants
  22. from vmware_nsxlib.v3 import utils
  23. LOG = logging.getLogger(__name__)
  24. LOG = logging.getLogger(__name__)
  25. TENANTS_PATH_PATTERN = "%s/"
  26. DOMAINS_PATH_PATTERN = TENANTS_PATH_PATTERN + "domains/"
  27. IP_BLOCKS_PATH_PATTERN = TENANTS_PATH_PATTERN + "ip-blocks/"
  28. IP_POOLS_PATH_PATTERN = TENANTS_PATH_PATTERN + "ip-pools/"
  29. SEGMENTS_PATH_PATTERN = TENANTS_PATH_PATTERN + "segments/"
  30. PROVIDERS_PATH_PATTERN = TENANTS_PATH_PATTERN + "providers/"
  31. TIER0S_PATH_PATTERN = TENANTS_PATH_PATTERN + "tier-0s/"
  32. TIER1S_PATH_PATTERN = TENANTS_PATH_PATTERN + "tier-1s/"
  33. SERVICES_PATH_PATTERN = TENANTS_PATH_PATTERN + "services/"
  34. ENFORCEMENT_POINT_PATTERN = (TENANTS_PATH_PATTERN +
  35. "sites/default/enforcement-points/")
  36. TRANSPORT_ZONE_PATTERN = ENFORCEMENT_POINT_PATTERN + "%s/transport-zones/"
  37. EDGE_CLUSTER_PATTERN = ENFORCEMENT_POINT_PATTERN + "%s/edge-clusters/"
  38. SEGMENT_SECURITY_PROFILES_PATH_PATTERN = (TENANTS_PATH_PATTERN +
  39. "segment-security-profiles/")
  40. QOS_PROFILES_PATH_PATTERN = TENANTS_PATH_PATTERN + "qos-profiles/"
  41. SPOOFGUARD_PROFILES_PATH_PATTERN = (TENANTS_PATH_PATTERN +
  42. "spoofguard-profiles/")
  43. IP_DISCOVERY_PROFILES_PATH_PATTERN = (TENANTS_PATH_PATTERN +
  44. "ip-discovery-profiles/")
  45. MAC_DISCOVERY_PROFILES_PATH_PATTERN = (TENANTS_PATH_PATTERN +
  46. "mac-discovery-profiles/")
  47. IPV6_NDRA_PROFILES_PATH_PATTERN = (TENANTS_PATH_PATTERN +
  48. "ipv6-ndra-profiles/")
  49. WAF_PROFILES_PATH_PATTERN = (TENANTS_PATH_PATTERN +
  50. "waf-profiles/")
  51. CERTIFICATE_PATH_PATTERN = TENANTS_PATH_PATTERN + "certificates/"
  52. EXCLUDE_LIST_PATH_PATTERN = (TENANTS_PATH_PATTERN +
  53. "settings/firewall/security/exclude-list")
  54. REALIZATION_PATH = "infra/realized-state/realized-entities?intent_path=%s"
  55. DHCP_REALY_PATTERN = TENANTS_PATH_PATTERN + "dhcp-relay-configs/"
  56. MDPROXY_PATTERN = TENANTS_PATH_PATTERN + "metadata-proxies/"
  57. TIER0_LOCALE_SERVICES_PATH_PATTERN = (TIER0S_PATH_PATTERN +
  58. "%s/locale-services/")
  59. TIER1_LOCALE_SERVICES_PATH_PATTERN = (TIER1S_PATH_PATTERN +
  60. "%s/locale-services/")
  61. @six.add_metaclass(abc.ABCMeta)
  62. class ResourceDef(object):
  63. def __init__(self, nsx_version=None, **kwargs):
  64. self.attrs = kwargs
  65. # nsx_version should be passed in on init if the resource has
  66. # version-dependant attributes. Otherwise this is ignored
  67. self.nsx_version = nsx_version
  68. # init default tenant
  69. self.attrs['tenant'] = self.get_tenant()
  70. self.body = {}
  71. # Whether this entry needs to be deleted
  72. self.delete = False
  73. # As of now, for some defs (ex: services) child entry is required,
  74. # meaning parent creation will fail without the child.
  75. # Unfortunately in transactional API policy still fails us, even if
  76. # child is specified as ChildEntry in same transaction.
  77. # To provide a workaround, we need keep reference to the child and
  78. # populate child entry inside parent clause in transactional API.
  79. # TODO(annak): remove this if/when policy solves this
  80. self.mandatory_child_def = None
  81. def set_delete(self):
  82. self.delete = True
  83. def get_delete(self):
  84. return self.delete
  85. def get_obj_dict(self):
  86. body = self.body if self.body else {}
  87. if self.resource_type():
  88. body['resource_type'] = self.resource_type()
  89. self._set_attr_if_specified(body, 'name', 'display_name')
  90. self._set_attrs_if_specified(body, ['description', 'tags'])
  91. resource_id = self.get_id()
  92. if resource_id:
  93. body['id'] = resource_id
  94. return body
  95. # This is needed for sake of update due to policy issue.
  96. # Policy refuses to update without requires attributes provided,
  97. # so we need to run an extra GET to acquire these.
  98. # This should be removed when/if this issue is fixed on backend.
  99. def set_obj_dict(self, obj_dict):
  100. self.body = obj_dict
  101. @abc.abstractproperty
  102. def path_pattern(self):
  103. pass
  104. @abc.abstractproperty
  105. def path_ids(self):
  106. pass
  107. @staticmethod
  108. def resource_type():
  109. pass
  110. @classmethod
  111. def resource_class(cls):
  112. # Returns base resource type for polymorphic objects
  113. # if not overriden, would return resource_type
  114. return cls.resource_type()
  115. @staticmethod
  116. def resource_use_cache():
  117. return False
  118. def path_defs(self):
  119. pass
  120. def get_id(self):
  121. if self.attrs and self.path_ids:
  122. return self.attrs.get(self.path_ids[-1])
  123. def get_attr(self, attr):
  124. return self.attrs.get(attr)
  125. def has_attr(self, attr):
  126. return attr in self.attrs
  127. def get_tenant(self):
  128. if self.attrs.get('tenant'):
  129. return self.attrs.get('tenant')
  130. return constants.POLICY_INFRA_TENANT
  131. def get_section_path(self):
  132. path_ids = [self.get_attr(path_id) for path_id in self.path_ids[:-1]]
  133. return self.path_pattern % (tuple(path_ids))
  134. def get_resource_path(self):
  135. resource_id = self.get_id()
  136. if resource_id:
  137. return self.get_section_path() + resource_id
  138. return self.get_section_path()
  139. def get_resource_full_path(self):
  140. return '/' + self.get_resource_path()
  141. @property
  142. def get_last_section_dict_key(self):
  143. last_section = self.path_pattern.split("/")[-2]
  144. return last_section.replace('-', '_')
  145. @staticmethod
  146. def sub_entries_path():
  147. pass
  148. def _get_body_from_kwargs(self, **kwargs):
  149. if 'body' in kwargs:
  150. body = kwargs['body']
  151. else:
  152. body = {}
  153. return body
  154. # Helper to set attr in body if user specified it
  155. # Can be used if body name is different than attr name
  156. # If value is different than self.get_attr(attr), it can be set in arg
  157. def _set_attr_if_specified(self, body, attr,
  158. body_attr=None, value=None):
  159. if self.has_attr(attr):
  160. value = value if value is not None else self.get_attr(attr)
  161. if body_attr:
  162. # Body attr is different that attr exposed by resource def
  163. body[body_attr] = value
  164. else:
  165. # Body attr is the same
  166. body[attr] = value
  167. # Helper to set attrs in body if user specified them
  168. # Body name must match attr name
  169. def _set_attrs_if_specified(self, body, attr_list):
  170. for attr in attr_list:
  171. self._set_attr_if_specified(body, attr)
  172. # Helper to set attr in body if user specified it
  173. # and current nsx version supports it
  174. # Body name must match attr name
  175. def _set_attr_if_supported(self, body, attr, value=None):
  176. if self.has_attr(attr) and self._version_dependant_attr_supported(
  177. attr):
  178. value = value if value is not None else self.get_attr(attr)
  179. body[attr] = value
  180. # Helper to set attrs in body if user specified them
  181. # and current nsx version supports it
  182. # Body name must match attr name
  183. def _set_attrs_if_supported(self, body, attr_list):
  184. for attr in attr_list:
  185. self._set_attr_if_supported(body, attr)
  186. def _version_dependant_attr_supported(self, attr):
  187. """Check if a version dependent attr is supported on current NSX
  188. For each resource def, there could be some attributes which only exist
  189. on NSX after certain versions. This abstract method provides a skeleton
  190. to define version requirements of version-dependent attributes.
  191. By design, Devs should use _set_attr_if_supported() to add any attrs
  192. that are only known to NSX after a certain version. This method works
  193. as a registry for _set_attrs_if_supported() to know the baseline
  194. version of each version dependent attr.
  195. Non-version-dependent attributes should be added to the request body
  196. by using _set_attr_if_specified(). This method defaults to false since
  197. any version dependent attr unknown to this lib should be excluded
  198. for security and safety reasons.
  199. """
  200. return False
  201. @classmethod
  202. def get_single_entry(cls, obj_body):
  203. """Return the single sub-entry from the object body.
  204. If there are no entries, or more than 1 - return None.
  205. """
  206. entries_path = cls.sub_entries_path()
  207. if not entries_path:
  208. # This sub class doesn't support this
  209. return
  210. if (entries_path not in obj_body or
  211. len(obj_body[entries_path]) != 1):
  212. return
  213. return obj_body[entries_path][0]
  214. def bodyless(self):
  215. """Return True if args contain only keys and meta attrs"""
  216. meta = ['resource_type']
  217. meta.extend(self.path_ids)
  218. body_args = [key for key in self.attrs.keys()
  219. if key not in meta]
  220. return len(body_args) == 0
  221. def set_default_mandatory_vals(self):
  222. pass
  223. class TenantDef(ResourceDef):
  224. @property
  225. def path_pattern(self):
  226. return TENANTS_PATH_PATTERN
  227. @staticmethod
  228. def resource_type():
  229. return 'Infra'
  230. def path_defs(self):
  231. return ()
  232. @property
  233. def path_ids(self):
  234. return ('tenant',)
  235. def get_resource_path(self):
  236. return 'infra/'
  237. def get_section_path(self):
  238. return 'infra/'
  239. class DomainDef(ResourceDef):
  240. @property
  241. def path_pattern(self):
  242. return DOMAINS_PATH_PATTERN
  243. @property
  244. def path_ids(self):
  245. return ('tenant', 'domain_id')
  246. @staticmethod
  247. def resource_type():
  248. return 'Domain'
  249. def path_defs(self):
  250. return (TenantDef,)
  251. class RouteAdvertisement(object):
  252. types = {'static_routes': constants.ADV_RULE_TYPE_TIER1_STATIC_ROUTES,
  253. 'subnets': constants.ADV_RULE_TIER1_CONNECTED,
  254. 'nat': constants.ADV_RULE_TIER1_NAT,
  255. 'lb_vip': constants.ADV_RULE_TIER1_LB_VIP,
  256. 'lb_snat': constants.ADV_RULE_TIER1_LB_SNAT,
  257. 'dns_forwarder_ip': constants.ADV_RULE_TIER1_DNS_FORWARDER_IP,
  258. 'ipsec_endpoints': constants.ADV_RULE_TIER1_IPSEC_LOCAL_ENDPOINT}
  259. def __init__(self, **kwargs):
  260. self.attrs = kwargs
  261. def get_obj_dict(self):
  262. return [value for key, value in self.types.items()
  263. if self.attrs.get(key) is True]
  264. def set_obj_dict(self, obj_dict):
  265. # This initializes object based on list coming from backend
  266. # f.e. [TIER1_NAT, TIER1_LB_SNAT]
  267. for key, value in self.types.items():
  268. self.attrs[key] = value in obj_dict
  269. def update(self, **kwargs):
  270. # "None" will be passed as value when user does not specify adv type
  271. # True/False will be passed when user wants to switch adv ON/OFF
  272. for key, value in kwargs.items():
  273. if value is not None:
  274. self.attrs[key] = value
  275. class RouterDef(ResourceDef):
  276. def path_defs(self):
  277. return (TenantDef,)
  278. def get_obj_dict(self):
  279. body = super(RouterDef, self).get_obj_dict()
  280. self._set_attrs_if_specified(body, ['failover_mode',
  281. 'force_whitelisting',
  282. 'default_rule_logging',
  283. 'disable_firewall'])
  284. # Add dhcp relay config
  285. # TODO(asarfaty): this can be either dhcp or dhcp relay config
  286. if self.has_attr('dhcp_config'):
  287. paths = ""
  288. if self.get_attr('dhcp_config'):
  289. dhcp_conf = DhcpRelayConfigDef(
  290. config_id=self.get_attr('dhcp_config'),
  291. tenant=self.get_tenant())
  292. paths = [dhcp_conf.get_resource_full_path()]
  293. self._set_attr_if_specified(body, 'dhcp_config',
  294. body_attr='dhcp_config_paths',
  295. value=paths)
  296. if self.has_attr('ipv6_ndra_profile_id'):
  297. paths = ""
  298. if self.get_attr('ipv6_ndra_profile_id'):
  299. ndra_profile = Ipv6NdraProfileDef(
  300. profile_id=self.get_attr('ipv6_ndra_profile_id'),
  301. tenant=self.get_tenant())
  302. paths = [ndra_profile.get_resource_full_path()]
  303. self._set_attr_if_specified(body, 'ipv6_ndra_profile_id',
  304. body_attr='ipv6_profile_paths',
  305. value=paths)
  306. return body
  307. class Tier0Def(RouterDef):
  308. @property
  309. def path_pattern(self):
  310. return TIER0S_PATH_PATTERN
  311. @property
  312. def path_ids(self):
  313. return ('tenant', 'tier0_id')
  314. @staticmethod
  315. def resource_type():
  316. return 'Tier0'
  317. @staticmethod
  318. def resource_use_cache():
  319. return True
  320. def get_obj_dict(self):
  321. body = super(Tier0Def, self).get_obj_dict()
  322. self._set_attrs_if_specified(body, ['ha_mode', 'transit_subnets'])
  323. return body
  324. class Tier1Def(RouterDef):
  325. @property
  326. def path_pattern(self):
  327. return TIER1S_PATH_PATTERN
  328. @property
  329. def path_ids(self):
  330. return ('tenant', 'tier1_id')
  331. @staticmethod
  332. def resource_type():
  333. return 'Tier1'
  334. def get_obj_dict(self):
  335. body = super(Tier1Def, self).get_obj_dict()
  336. if self.has_attr('tier0'):
  337. tier0 = self.get_attr('tier0')
  338. tier0_path = ""
  339. if tier0:
  340. tenant = TENANTS_PATH_PATTERN % self.get_tenant()
  341. tier0_path = "/%stier-0s/%s" % (tenant, tier0)
  342. self._set_attr_if_specified(body, 'tier0',
  343. body_attr='tier0_path',
  344. value=tier0_path)
  345. if self.has_attr('route_advertisement'):
  346. body['route_advertisement_types'] = self.get_attr(
  347. 'route_advertisement').get_obj_dict()
  348. self._set_attrs_if_specified(body, ['enable_standby_relocation'])
  349. if self.has_attr('route_advertisement_rules'):
  350. body['route_advertisement_rules'] = [
  351. a.get_obj_dict()
  352. if isinstance(a, RouteAdvertisementRule) else a
  353. for a in self.get_attr('route_advertisement_rules')]
  354. return body
  355. @staticmethod
  356. def get_route_adv(obj_dict):
  357. route_adv = RouteAdvertisement()
  358. if 'route_advertisement_types' in obj_dict:
  359. route_adv.set_obj_dict(obj_dict['route_advertisement_types'])
  360. return route_adv
  361. class RouterLocaleServiceDef(ResourceDef):
  362. @staticmethod
  363. def resource_type():
  364. return 'LocaleServices'
  365. def get_obj_dict(self):
  366. body = super(RouterLocaleServiceDef, self).get_obj_dict()
  367. self._set_attr_if_specified(body, 'edge_cluster_path')
  368. return body
  369. class Tier0LocaleServiceDef(RouterLocaleServiceDef):
  370. @property
  371. def path_pattern(self):
  372. return TIER0_LOCALE_SERVICES_PATH_PATTERN
  373. @property
  374. def path_ids(self):
  375. return ('tenant', 'tier0_id', 'service_id')
  376. def path_defs(self):
  377. return (TenantDef, Tier0Def)
  378. class Tier1LocaleServiceDef(RouterLocaleServiceDef):
  379. @property
  380. def path_pattern(self):
  381. return TIER1_LOCALE_SERVICES_PATH_PATTERN
  382. @property
  383. def path_ids(self):
  384. return ('tenant', 'tier1_id', 'service_id')
  385. def path_defs(self):
  386. return (TenantDef, Tier1Def)
  387. class Tier0InterfaceDef(ResourceDef):
  388. @staticmethod
  389. def resource_type():
  390. return 'Tier0Interface'
  391. @property
  392. def path_pattern(self):
  393. return TIER0_LOCALE_SERVICES_PATH_PATTERN + "%s/interfaces/"
  394. @property
  395. def path_ids(self):
  396. return ('tenant', 'tier0_id', 'service_id', 'interface_id')
  397. class Tier1InterfaceDef(ResourceDef):
  398. @staticmethod
  399. def resource_type():
  400. return 'Tier1Interface'
  401. @property
  402. def path_pattern(self):
  403. return TIER1_LOCALE_SERVICES_PATH_PATTERN + "%s/interfaces/"
  404. def get_obj_dict(self):
  405. body = super(Tier1InterfaceDef, self).get_obj_dict()
  406. if self.has_attr('subnets'):
  407. # subnets expected to be of type InterfaceSubnet
  408. if self.get_attr('subnets'):
  409. subnets = [subnet.get_obj_dict()
  410. if isinstance(subnet, InterfaceSubnet) else subnet
  411. for subnet in self.get_attr('subnets')]
  412. self._set_attr_if_specified(body, 'subnets',
  413. value=subnets)
  414. if self.has_attr('segment_id'):
  415. path = ""
  416. if self.get_attr('segment_id'):
  417. tier1 = SegmentDef(segment_id=self.get_attr('segment_id'),
  418. tenant=self.get_tenant())
  419. path = tier1.get_resource_full_path()
  420. self._set_attr_if_specified(body, 'segment_id',
  421. body_attr='segment_path',
  422. value=path)
  423. if self.has_attr('ipv6_ndra_profile_id'):
  424. paths = ""
  425. if self.get_attr('ipv6_ndra_profile_id'):
  426. ndra_profile = Ipv6NdraProfileDef(
  427. profile_id=self.get_attr('ipv6_ndra_profile_id'),
  428. tenant=self.get_tenant())
  429. paths = [ndra_profile.get_resource_full_path()]
  430. self._set_attr_if_specified(body, 'ipv6_ndra_profile_id',
  431. body_attr='ipv6_profile_paths',
  432. value=paths)
  433. return body
  434. @property
  435. def path_ids(self):
  436. return ('tenant', 'tier1_id', 'service_id', 'interface_id')
  437. class RouterNatRule(ResourceDef):
  438. @staticmethod
  439. def resource_type():
  440. return 'PolicyNatRule'
  441. def get_obj_dict(self):
  442. body = super(RouterNatRule, self).get_obj_dict()
  443. self._set_attrs_if_specified(body, ['action',
  444. 'source_network',
  445. 'destination_network',
  446. 'translated_network',
  447. 'firewall_match',
  448. 'log',
  449. 'sequence_number',
  450. 'enabled'])
  451. return body
  452. def set_default_mandatory_vals(self):
  453. if not self.has_attr('action'):
  454. self.attrs['action'] = constants.NAT_ACTION_DNAT
  455. class Tier1NatDef(RouterDef):
  456. @property
  457. def path_pattern(self):
  458. return TIER1S_PATH_PATTERN + "%s/nat"
  459. @property
  460. def path_ids(self):
  461. return ('tenant', 'tier1_id')
  462. @staticmethod
  463. def resource_type():
  464. return 'PolicyNat'
  465. class Tier1NatRule(RouterNatRule):
  466. @property
  467. def path_pattern(self):
  468. return TIER1S_PATH_PATTERN + "%s/nat/%s/nat-rules/"
  469. @property
  470. def path_ids(self):
  471. return ('tenant', 'tier1_id', 'nat_id', 'nat_rule_id')
  472. def path_defs(self):
  473. return (TenantDef, Tier1Def, Tier1NatDef)
  474. class RouteAdvertisementRule(object):
  475. def __init__(self, name, action=constants.ADV_RULE_PERMIT,
  476. prefix_operator=constants.ADV_RULE_OPERATOR_GE,
  477. route_advertisement_types=None,
  478. subnets=None):
  479. self.name = name
  480. self.action = action
  481. self.prefix_operator = prefix_operator
  482. self.route_advertisement_types = route_advertisement_types
  483. self.subnets = subnets
  484. def get_obj_dict(self):
  485. return {'name': self.name,
  486. 'action': self.action,
  487. 'prefix_operator': self.prefix_operator,
  488. 'route_advertisement_types': self.route_advertisement_types,
  489. 'subnets': self.subnets}
  490. class RouterStaticRoute(ResourceDef):
  491. @staticmethod
  492. def resource_type():
  493. return 'StaticRoutes'
  494. def get_obj_dict(self):
  495. body = super(RouterStaticRoute, self).get_obj_dict()
  496. self._set_attrs_if_specified(body, ['network'])
  497. # next hops
  498. if self.has_attr('next_hop'):
  499. next_hop = self.get_attr('next_hop')
  500. next_hops = [{'ip_address': next_hop}]
  501. self._set_attr_if_specified(body, 'next_hop',
  502. body_attr='next_hops',
  503. value=next_hops)
  504. return body
  505. class Tier1StaticRoute(RouterStaticRoute):
  506. @property
  507. def path_pattern(self):
  508. return TIER1S_PATH_PATTERN + "%s/static-routes/"
  509. @property
  510. def path_ids(self):
  511. return ('tenant', 'tier1_id', 'static_route_id')
  512. def path_defs(self):
  513. return (TenantDef, Tier1Def)
  514. class Tier0StaticRoute(RouterStaticRoute):
  515. @property
  516. def path_pattern(self):
  517. return TIER0S_PATH_PATTERN + "%s/static-routes/"
  518. @property
  519. def path_ids(self):
  520. return ('tenant', 'tier0_id', 'static_route_id')
  521. def path_defs(self):
  522. return (TenantDef, Tier0Def)
  523. class Tier0NatDef(RouterDef):
  524. @property
  525. def path_pattern(self):
  526. return TIER0S_PATH_PATTERN + "%s/nat"
  527. @property
  528. def path_ids(self):
  529. return ('tenant', 'tier0_id')
  530. @staticmethod
  531. def resource_type():
  532. return 'PolicyNat'
  533. class Tier0NatRule(RouterNatRule):
  534. @property
  535. def path_pattern(self):
  536. return TIER0S_PATH_PATTERN + "%s/nat/%s/nat-rules/"
  537. @property
  538. def path_ids(self):
  539. return ('tenant', 'tier0_id', 'nat_id', 'nat_rule_id')
  540. def path_defs(self):
  541. return (TenantDef, Tier0Def, Tier0NatDef)
  542. class Subnet(object):
  543. def __init__(self, gateway_address, dhcp_ranges=None):
  544. self.gateway_address = gateway_address
  545. self.dhcp_ranges = dhcp_ranges
  546. def get_obj_dict(self):
  547. body = {'gateway_address': self.gateway_address}
  548. if self.dhcp_ranges:
  549. body['dhcp_ranges'] = self.dhcp_ranges
  550. return body
  551. class InterfaceSubnet(object):
  552. def __init__(self, ip_addresses, prefix_len):
  553. self.ip_addresses = ip_addresses
  554. self.prefix_len = prefix_len
  555. def get_obj_dict(self):
  556. body = {'ip_addresses': self.ip_addresses,
  557. 'prefix_len': self.prefix_len}
  558. return body
  559. class BaseSegmentDef(ResourceDef):
  560. def get_obj_dict(self):
  561. body = super(BaseSegmentDef, self).get_obj_dict()
  562. if self.has_attr('subnets'):
  563. # Note(asarfaty): removing subnets through PATCH api is not
  564. # supported
  565. if self.get_attr('subnets'):
  566. subnets = [subnet.get_obj_dict()
  567. for subnet in self.get_attr('subnets')]
  568. self._set_attr_if_specified(body, 'subnets',
  569. value=subnets)
  570. if self.has_attr('ip_pool_id'):
  571. ip_pool_id = self.get_attr('ip_pool_id')
  572. adv_cfg = self._get_adv_config(ip_pool_id)
  573. self._set_attr_if_specified(body, 'ip_pool_id',
  574. body_attr='advanced_config',
  575. value=adv_cfg)
  576. self._set_attrs_if_specified(body, ['domain_name', 'vlan_ids'])
  577. return body
  578. @staticmethod
  579. def resource_type():
  580. return 'Segment'
  581. def _get_adv_config(self, ip_pool_id):
  582. ip_pool_def = IpPoolDef(ip_pool_id=ip_pool_id)
  583. ip_pool_path = ip_pool_def.get_resource_full_path()
  584. return {'address_pool_paths': [ip_pool_path]}
  585. class Tier1SegmentDef(BaseSegmentDef):
  586. '''Tier1 segments can not move to different tier1 '''
  587. @property
  588. def path_pattern(self):
  589. return TIER1S_PATH_PATTERN + "%s/segments/"
  590. @property
  591. def path_ids(self):
  592. return ('tenant', 'tier1_id', 'segment_id')
  593. def path_defs(self):
  594. return (TenantDef, Tier1Def)
  595. class SegmentDef(BaseSegmentDef):
  596. '''These segments don't belong to particular tier1.
  597. And can be attached and re-attached to different tier1s
  598. '''
  599. @property
  600. def path_pattern(self):
  601. return SEGMENTS_PATH_PATTERN
  602. @property
  603. def path_ids(self):
  604. return ('tenant', 'segment_id')
  605. def path_defs(self):
  606. return (TenantDef,)
  607. def _version_dependant_attr_supported(self, attr):
  608. if (version.LooseVersion(self.nsx_version) >=
  609. version.LooseVersion(nsx_constants.NSX_VERSION_3_0_0)):
  610. if attr == 'metadata_proxy_id':
  611. return True
  612. else:
  613. LOG.warning(
  614. "Ignoring %s for %s %s: this feature is not supported."
  615. "Current NSX version: %s. Minimum supported version: %s",
  616. attr, self.resource_type, self.attrs.get('name', ''),
  617. self.nsx_version, nsx_constants.NSX_VERSION_3_0_0)
  618. return False
  619. return False
  620. def get_obj_dict(self):
  621. body = super(SegmentDef, self).get_obj_dict()
  622. if self.has_attr('tier1_id'):
  623. path = ""
  624. if self.get_attr('tier1_id'):
  625. tier1 = Tier1Def(tier1_id=self.get_attr('tier1_id'),
  626. tenant=self.get_tenant())
  627. path = tier1.get_resource_full_path()
  628. self._set_attr_if_specified(body, 'tier1_id',
  629. body_attr='connectivity_path',
  630. value=path)
  631. if self.has_attr('tier0_id'):
  632. path = ""
  633. if self.get_attr('tier0_id'):
  634. tier0 = Tier0Def(tier0_id=self.get_attr('tier0_id'),
  635. tenant=self.get_tenant())
  636. path = tier0.get_resource_full_path()
  637. self._set_attr_if_specified(body, 'tier0_id',
  638. body_attr='connectivity_path',
  639. value=path)
  640. if self.has_attr('transport_zone_id'):
  641. path = ""
  642. if self.get_attr('transport_zone_id'):
  643. tz = TransportZoneDef(
  644. tz_id=self.get_attr('transport_zone_id'),
  645. ep_id=constants.DEFAULT_ENFORCEMENT_POINT,
  646. tenant=self.get_tenant())
  647. path = tz.get_resource_full_path()
  648. self._set_attr_if_specified(body, 'transport_zone_id',
  649. body_attr='transport_zone_path',
  650. value=path)
  651. if (self.has_attr('metadata_proxy_id') and
  652. self._version_dependant_attr_supported('metadata_proxy_id')):
  653. paths = ""
  654. if self.get_attr('metadata_proxy_id'):
  655. mdproxy = MetadataProxyDef(
  656. mdproxy_id=self.get_attr('metadata_proxy_id'),
  657. tenant=self.get_tenant())
  658. paths = [mdproxy.get_resource_full_path()]
  659. self._set_attr_if_specified(body, 'metadata_proxy_id',
  660. body_attr='metadata_proxy_paths',
  661. value=paths)
  662. return body
  663. class PortAddressBinding(object):
  664. def __init__(self, ip_address, mac_address, vlan_id=None):
  665. self.ip_address = ip_address
  666. self.mac_address = mac_address
  667. self.vlan_id = vlan_id
  668. def get_obj_dict(self):
  669. data = {'ip_address': self.ip_address,
  670. 'mac_address': self.mac_address}
  671. if self.vlan_id is not None:
  672. data['vlan_id'] = self.vlan_id
  673. return data
  674. class SegmentPortDef(ResourceDef):
  675. '''Infra segment port'''
  676. @property
  677. def path_pattern(self):
  678. return SEGMENTS_PATH_PATTERN + "%s/ports/"
  679. @property
  680. def path_ids(self):
  681. return ('tenant', 'segment_id', 'port_id')
  682. @staticmethod
  683. def resource_type():
  684. return 'SegmentPort'
  685. def path_defs(self):
  686. return (TenantDef, SegmentDef)
  687. def get_obj_dict(self):
  688. body = super(SegmentPortDef, self).get_obj_dict()
  689. address_bindings = self.get_attr('address_bindings')
  690. if address_bindings:
  691. body['address_bindings'] = [binding.get_obj_dict()
  692. for binding in address_bindings]
  693. if (self.has_attr('attachment_type') or self.has_attr('vif_id') or
  694. self.has_attr('hyperbus_mode')):
  695. if (not self.get_attr('attachment_type') and
  696. not self.get_attr('vif_id') and
  697. not self.get_attr('hyperbus_mode')):
  698. # detach operation
  699. body['attachment'] = None
  700. else:
  701. attachment = {}
  702. if self.get_attr('attachment_type'):
  703. attachment['type'] = self.get_attr('attachment_type')
  704. if self.get_attr('vif_id'):
  705. attachment['id'] = self.get_attr('vif_id')
  706. if self.get_attr('hyperbus_mode'):
  707. self._set_attr_if_supported(attachment, 'hyperbus_mode')
  708. self._set_attrs_if_specified(attachment,
  709. ['context_id',
  710. 'app_id',
  711. 'traffic_tag',
  712. 'allocate_addresses'])
  713. body['attachment'] = attachment
  714. return body
  715. def _version_dependant_attr_supported(self, attr):
  716. if (version.LooseVersion(self.nsx_version) >=
  717. version.LooseVersion(nsx_constants.NSX_VERSION_3_0_0)):
  718. if attr == 'hyperbus_mode':
  719. return True
  720. LOG.warning(
  721. "Ignoring %s for %s %s: this feature is not supported."
  722. "Current NSX version: %s. Minimum supported version: %s",
  723. attr, self.resource_type, self.attrs.get('name', ''),
  724. self.nsx_version, nsx_constants.NSX_VERSION_3_0_0)
  725. return False
  726. class SegmentBindingMapDefBase(ResourceDef):
  727. @property
  728. def path_ids(self):
  729. return ('tenant', 'segment_id', 'map_id')
  730. def path_defs(self):
  731. return (TenantDef, SegmentDef)
  732. class SegmentSecProfilesBindingMapDef(SegmentBindingMapDefBase):
  733. @property
  734. def path_pattern(self):
  735. return (SEGMENTS_PATH_PATTERN +
  736. "%s/segment-security-profile-binding-maps/")
  737. @staticmethod
  738. def resource_type():
  739. return 'SegmentSecurityProfileBindingMap'
  740. def get_obj_dict(self):
  741. body = super(SegmentSecProfilesBindingMapDef, self).get_obj_dict()
  742. if self.has_attr('segment_security_profile_id'):
  743. path = ""
  744. if self.get_attr('segment_security_profile_id'):
  745. profile = SegmentSecurityProfileDef(
  746. profile_id=self.get_attr('segment_security_profile_id'),
  747. tenant=self.get_tenant())
  748. path = profile.get_resource_full_path()
  749. self._set_attr_if_specified(
  750. body, 'segment_security_profile_id',
  751. body_attr='segment_security_profile_path',
  752. value=path)
  753. if self.has_attr('spoofguard_profile_id'):
  754. path = ""
  755. if self.get_attr('spoofguard_profile_id'):
  756. profile = SpoofguardProfileDef(
  757. profile_id=self.get_attr('spoofguard_profile_id'),
  758. tenant=self.get_tenant())
  759. path = profile.get_resource_full_path()
  760. self._set_attr_if_specified(
  761. body, 'spoofguard_profile_id',
  762. body_attr='spoofguard_profile_path',
  763. value=path)
  764. return body
  765. class SegmentPortBindingMapDefBase(ResourceDef):
  766. @property
  767. def path_ids(self):
  768. return ('tenant', 'segment_id', 'port_id', 'map_id')
  769. def path_defs(self):
  770. return (TenantDef, SegmentDef, SegmentPortDef)
  771. class SegmentPortSecProfilesBindingMapDef(SegmentPortBindingMapDefBase):
  772. @property
  773. def path_pattern(self):
  774. return (SEGMENTS_PATH_PATTERN +
  775. "%s/ports/%s/port-security-profile-binding-maps/")
  776. @staticmethod
  777. def resource_type():
  778. return 'PortSecurityProfileBindingMap'
  779. def get_obj_dict(self):
  780. body = super(SegmentPortSecProfilesBindingMapDef, self).get_obj_dict()
  781. if self.has_attr('segment_security_profile_id'):
  782. path = ""
  783. if self.get_attr('segment_security_profile_id'):
  784. profile = SegmentSecurityProfileDef(
  785. profile_id=self.get_attr('segment_security_profile_id'),
  786. tenant=self.get_tenant())
  787. path = profile.get_resource_full_path()
  788. self._set_attr_if_specified(
  789. body, 'segment_security_profile_id',
  790. body_attr='segment_security_profile_path',
  791. value=path)
  792. if self.has_attr('spoofguard_profile_id'):
  793. path = ""
  794. if self.get_attr('spoofguard_profile_id'):
  795. profile = SpoofguardProfileDef(
  796. profile_id=self.get_attr('spoofguard_profile_id'),
  797. tenant=self.get_tenant())
  798. path = profile.get_resource_full_path()
  799. self._set_attr_if_specified(
  800. body, 'spoofguard_profile_id',
  801. body_attr='spoofguard_profile_path',
  802. value=path)
  803. return body
  804. class SegmentPortDiscoveryProfilesBindingMapDef(SegmentPortBindingMapDefBase):
  805. @property
  806. def path_pattern(self):
  807. return (SEGMENTS_PATH_PATTERN +
  808. "%s/ports/%s/port-discovery-profile-binding-maps/")
  809. @staticmethod
  810. def resource_type():
  811. return 'PortDiscoveryProfileBindingMap'
  812. def get_obj_dict(self):
  813. body = super(SegmentPortDiscoveryProfilesBindingMapDef,
  814. self).get_obj_dict()
  815. if self.has_attr('mac_discovery_profile_id'):
  816. path = ""
  817. if self.get_attr('mac_discovery_profile_id'):
  818. profile = MacDiscoveryProfileDef(
  819. profile_id=self.get_attr('mac_discovery_profile_id'),
  820. tenant=self.get_tenant())
  821. path = profile.get_resource_full_path()
  822. self._set_attr_if_specified(
  823. body, 'mac_discovery_profile_id',
  824. body_attr='mac_discovery_profile_path',
  825. value=path)
  826. if self.has_attr('ip_discovery_profile_id'):
  827. path = ""
  828. if self.get_attr('ip_discovery_profile_id'):
  829. profile = IpDiscoveryProfileDef(
  830. profile_id=self.get_attr('ip_discovery_profile_id'),
  831. tenant=self.get_tenant())
  832. path = profile.get_resource_full_path()
  833. self._set_attr_if_specified(
  834. body, 'ip_discovery_profile_id',
  835. body_attr='ip_discovery_profile_path',
  836. value=path)
  837. return body
  838. class SegmentPortQoSProfilesBindingMapDef(SegmentPortBindingMapDefBase):
  839. @property
  840. def path_pattern(self):
  841. return (SEGMENTS_PATH_PATTERN +
  842. "%s/ports/%s/port-qos-profile-binding-maps/")
  843. @staticmethod
  844. def resource_type():
  845. return 'PortQoSProfileBindingMap'
  846. def get_obj_dict(self):
  847. body = super(SegmentPortQoSProfilesBindingMapDef,
  848. self).get_obj_dict()
  849. if self.has_attr('qos_profile_id'):
  850. path = ""
  851. if self.get_attr('qos_profile_id'):
  852. profile = QosProfileDef(
  853. profile_id=self.get_attr('qos_profile_id'),
  854. tenant=self.get_tenant())
  855. path = profile.get_resource_full_path()
  856. self._set_attr_if_specified(
  857. body, 'qos_profile_id',
  858. body_attr='qos_profile_path',
  859. value=path)
  860. return body
  861. class Tier1SegmentPortDef(SegmentPortDef):
  862. '''Tier1 segment port'''
  863. @property
  864. def path_pattern(self):
  865. return TIER1S_PATH_PATTERN + "%s/segments/%s/ports/"
  866. @property
  867. def path_ids(self):
  868. return ('tenant', 'tier1_id', 'segment_id', 'port_id')
  869. def path_defs(self):
  870. return (TenantDef, Tier1Def, SegmentDef)
  871. class IpBlockDef(ResourceDef):
  872. '''Infra IpBlock'''
  873. @property
  874. def path_pattern(self):
  875. return IP_BLOCKS_PATH_PATTERN
  876. @property
  877. def path_ids(self):
  878. return ('tenant', 'ip_block_id')
  879. @staticmethod
  880. def resource_type():
  881. return 'IpAddressBlock'
  882. def path_defs(self):
  883. return (TenantDef,)
  884. def get_obj_dict(self):
  885. body = super(IpBlockDef, self).get_obj_dict()
  886. self._set_attr_if_specified(body, 'cidr')
  887. return body
  888. class IpPoolDef(ResourceDef):
  889. '''Infra IpPool'''
  890. @property
  891. def path_pattern(self):
  892. return IP_POOLS_PATH_PATTERN
  893. @property
  894. def path_ids(self):
  895. return ('tenant', 'ip_pool_id')
  896. @staticmethod
  897. def resource_type():
  898. return 'IpAddressPool'
  899. def path_defs(self):
  900. return (TenantDef,)
  901. class IpPoolAllocationDef(ResourceDef):
  902. '''Infra IpPoolAllocation'''
  903. @property
  904. def path_pattern(self):
  905. return IP_POOLS_PATH_PATTERN + "%s/ip-allocations/"
  906. @property
  907. def path_ids(self):
  908. return ('tenant', 'ip_pool_id', 'ip_allocation_id')
  909. @staticmethod
  910. def resource_type():
  911. return 'IpAddressAllocation'
  912. def path_defs(self):
  913. return (TenantDef, IpPoolDef)
  914. def get_obj_dict(self):
  915. body = super(IpPoolAllocationDef, self).get_obj_dict()
  916. self._set_attr_if_specified(body, 'allocation_ip')
  917. return body
  918. class IpPoolSubnetDef(ResourceDef):
  919. '''Infra IpPool Subnet'''
  920. @property
  921. def path_pattern(self):
  922. return IP_POOLS_PATH_PATTERN + "%s/ip-subnets/"
  923. @property
  924. def path_ids(self):
  925. return ('tenant', 'ip_pool_id', 'ip_subnet_id')
  926. @classmethod
  927. def resource_class(cls):
  928. return 'IpAddressPoolSubnet'
  929. def path_defs(self):
  930. return (TenantDef, IpPoolDef)
  931. class IpPoolBlockSubnetDef(IpPoolSubnetDef):
  932. '''Infra IpPoolSubnet belonging to IpBlock'''
  933. @staticmethod
  934. def resource_type():
  935. return 'IpAddressPoolBlockSubnet'
  936. def get_obj_dict(self):
  937. body = super(IpPoolBlockSubnetDef, self).get_obj_dict()
  938. self._set_attrs_if_specified(body, ['auto_assign_gateway', 'size'])
  939. if self.has_attr('ip_block_id'):
  940. # Format the IP Block ID to its path
  941. ip_block_id = self.get_attr('ip_block_id')
  942. ip_block_def = IpBlockDef(ip_block_id=ip_block_id,
  943. tenant=self.get_tenant())
  944. ip_block_path = ip_block_def.get_resource_full_path()
  945. self._set_attr_if_specified(
  946. body, 'ip_block_id', body_attr='ip_block_path',
  947. value=ip_block_path)
  948. self._set_attr_if_supported(body, 'start_ip')
  949. return body
  950. def _version_dependant_attr_supported(self, attr):
  951. if (version.LooseVersion(self.nsx_version) >=
  952. version.LooseVersion(nsx_constants.NSX_VERSION_3_0_0)):
  953. if attr == 'start_ip':
  954. return True
  955. LOG.warning(
  956. "Ignoring %s for %s %s: this feature is not supported."
  957. "Current NSX version: %s. Minimum supported version: %s",
  958. attr, self.resource_type, self.attrs.get('name', ''),
  959. self.nsx_version, nsx_constants.NSX_VERSION_3_0_0)
  960. return False
  961. class IpPoolStaticSubnetDef(IpPoolSubnetDef):
  962. '''Infra IpPool static subnet'''
  963. @staticmethod
  964. def resource_type():
  965. return 'IpAddressPoolStaticSubnet'
  966. def get_obj_dict(self):
  967. body = super(IpPoolStaticSubnetDef, self).get_obj_dict()
  968. self._set_attrs_if_specified(body, ['cidr',
  969. 'allocation_ranges',
  970. 'gateway_ip'])
  971. return body
  972. class Condition(object):
  973. def __init__(self, value, key=constants.CONDITION_KEY_TAG,
  974. member_type=constants.CONDITION_MEMBER_PORT,
  975. operator=constants.CONDITION_OP_EQUALS):
  976. self.value = value
  977. self.key = key
  978. self.member_type = member_type
  979. self.operator = operator
  980. def get_obj_dict(self):
  981. return {'resource_type': 'Condition',
  982. 'member_type': self.member_type,
  983. 'key': self.key,
  984. 'value': self.value,
  985. 'operator': self.operator}
  986. class IPAddressExpression(object):
  987. def __init__(self, ip_addresses):
  988. self.ip_addresses = ip_addresses
  989. def get_obj_dict(self):
  990. return {'resource_type': 'IPAddressExpression',
  991. 'ip_addresses': self.ip_addresses}
  992. class PathExpression(object):
  993. def __init__(self, paths):
  994. self.paths = paths
  995. def get_obj_dict(self):
  996. return {'resource_type': 'PathExpression',
  997. 'paths': self.paths}
  998. class ConjunctionOperator(object):
  999. def __init__(self, operator=constants.CONDITION_OP_AND):
  1000. self.operator = operator
  1001. def get_obj_dict(self):
  1002. return {'resource_type': 'ConjunctionOperator',
  1003. 'conjunction_operator': self.operator}
  1004. class NestedExpression(object):
  1005. def __init__(self, expressions=None):
  1006. self.expressions = expressions or []
  1007. def get_obj_dict(self):
  1008. return {'resource_type': 'NestedExpression',
  1009. 'expressions': [ex.get_obj_dict() for ex in self.expressions]}
  1010. class GroupDef(ResourceDef):
  1011. @property
  1012. def path_pattern(self):
  1013. return DOMAINS_PATH_PATTERN + "%s/groups/"
  1014. @property
  1015. def path_ids(self):
  1016. return ('tenant', 'domain_id', 'group_id')
  1017. @staticmethod
  1018. def resource_type():
  1019. return 'Group'
  1020. def path_defs(self):
  1021. return (TenantDef, DomainDef)
  1022. def get_obj_dict(self):
  1023. body = super(GroupDef, self).get_obj_dict()
  1024. conds = self.get_attr('conditions')
  1025. if conds:
  1026. conds = conds if isinstance(conds, list) else [conds]
  1027. if conds:
  1028. body['expression'] = [condition.get_obj_dict()
  1029. for condition in conds]
  1030. return body
  1031. class ServiceDef(ResourceDef):
  1032. def __init__(self, **kwargs):
  1033. super(ServiceDef, self).__init__(**kwargs)
  1034. self.service_entries = []
  1035. @property
  1036. def path_pattern(self):
  1037. return SERVICES_PATH_PATTERN
  1038. @property
  1039. def path_ids(self):
  1040. return ('tenant', 'service_id')
  1041. @staticmethod
  1042. def resource_type():
  1043. return 'Service'
  1044. def path_defs(self):
  1045. return (TenantDef,)
  1046. def get_obj_dict(self):
  1047. body = super(ServiceDef, self).get_obj_dict()
  1048. entries = [entry.get_obj_dict()
  1049. for entry in self.service_entries]
  1050. if entries:
  1051. body['service_entries'] = entries
  1052. return body
  1053. @staticmethod
  1054. def sub_entries_path():
  1055. return ServiceEntryDef().get_last_section_dict_key
  1056. class ServiceEntryDef(ResourceDef):
  1057. @property
  1058. def path_pattern(self):
  1059. return SERVICES_PATH_PATTERN + "%s/service-entries/"
  1060. @property
  1061. def path_ids(self):
  1062. return ('tenant', 'service_id', 'entry_id')
  1063. def path_defs(self):
  1064. return (TenantDef, ServiceDef)
  1065. @classmethod
  1066. def resource_class(cls):
  1067. return 'ServiceEntry'
  1068. class L4ServiceEntryDef(ServiceEntryDef):
  1069. @staticmethod
  1070. def resource_type():
  1071. return 'L4PortSetServiceEntry'
  1072. def get_obj_dict(self):
  1073. body = super(L4ServiceEntryDef, self).get_obj_dict()
  1074. self._set_attr_if_specified(body, 'protocol', 'l4_protocol')
  1075. self._set_attr_if_specified(body, 'dest_ports', 'destination_ports')
  1076. self._set_attr_if_specified(body, 'source_ports', 'source_ports')
  1077. return body
  1078. class IcmpServiceEntryDef(ServiceEntryDef):
  1079. @staticmethod
  1080. def resource_type():
  1081. return 'ICMPTypeServiceEntry'
  1082. def get_obj_dict(self):
  1083. body = super(IcmpServiceEntryDef, self).get_obj_dict()
  1084. if self.get_attr('version'):
  1085. body['protocol'] = 'ICMPv' + str(self.get_attr('version'))
  1086. for attr in ('icmp_type', 'icmp_code'):
  1087. # Note that icmp_type and icmp_code could be 0.
  1088. if self.get_attr(attr) is not None:
  1089. body[attr] = self.get_attr(attr)
  1090. return body
  1091. class IPProtocolServiceEntryDef(ServiceEntryDef):
  1092. @staticmethod
  1093. def resource_type():
  1094. return 'IPProtocolServiceEntry'
  1095. def get_obj_dict(self):
  1096. body = super(IPProtocolServiceEntryDef, self).get_obj_dict()
  1097. if self.get_attr('protocol_number') is not None:
  1098. # Note that protocol_number could be 0.
  1099. body['protocol_number'] = self.get_attr('protocol_number')
  1100. return body
  1101. class SecurityPolicyBaseDef(ResourceDef):
  1102. @property
  1103. def path_ids(self):
  1104. return ('tenant', 'domain_id', 'map_id')
  1105. def path_defs(self):
  1106. return (TenantDef, DomainDef)
  1107. def get_obj_dict(self):
  1108. body = super(SecurityPolicyBaseDef, self).get_obj_dict()
  1109. self._set_attr_if_specified(body, 'category')
  1110. if self.has_attr('map_sequence_number'):
  1111. seq_number = self.get_attr('map_sequence_number')
  1112. self._set_attr_if_specified(body, 'map_sequence_number',
  1113. body_attr='sequence_number',
  1114. value=seq_number)
  1115. return body
  1116. class CommunicationMapDef(SecurityPolicyBaseDef):
  1117. """AKA security policy"""
  1118. @property
  1119. def path_pattern(self):
  1120. return (DOMAINS_PATH_PATTERN + "%s/security-policies/")
  1121. @staticmethod
  1122. def resource_type():
  1123. return 'SecurityPolicy'
  1124. @staticmethod
  1125. def sub_entries_path():
  1126. return CommunicationMapEntryDef().get_last_section_dict_key
  1127. class GatewayPolicyDef(SecurityPolicyBaseDef):
  1128. @property
  1129. def path_pattern(self):
  1130. return (DOMAINS_PATH_PATTERN + "%s/gateway-policies/")
  1131. @staticmethod
  1132. def resource_type():
  1133. return 'GatewayPolicy'
  1134. @staticmethod
  1135. def sub_entries_path():
  1136. return GatewayPolicyRuleDef().get_last_section_dict_key
  1137. class SecurityPolicyRuleBaseDef(ResourceDef):
  1138. def get_groups_path(self, domain_id, group_ids):
  1139. if not group_ids:
  1140. return [constants.ANY_GROUP]
  1141. return [GroupDef(domain_id=domain_id,
  1142. group_id=group_id,
  1143. tenant=self.get_tenant()).get_resource_full_path()
  1144. for group_id in group_ids]
  1145. def get_service_path(self, service_id):
  1146. return ServiceDef(
  1147. service_id=service_id,
  1148. tenant=self.get_tenant()).get_resource_full_path()
  1149. def get_services_path(self, service_ids):
  1150. if service_ids:
  1151. return [self.get_service_path(service_id)
  1152. for service_id in service_ids]
  1153. return [constants.ANY_SERVICE]
  1154. @property
  1155. def path_ids(self):
  1156. return ('tenant', 'domain_id', 'map_id', 'entry_id')
  1157. @staticmethod
  1158. def resource_type():
  1159. return 'Rule'
  1160. def get_obj_dict(self):
  1161. body = super(SecurityPolicyRuleBaseDef, self).get_obj_dict()
  1162. domain_id = self.get_attr('domain_id')
  1163. if self.has_attr('source_groups'):
  1164. body['source_groups'] = self.get_groups_path(
  1165. domain_id, self.get_attr('source_groups'))
  1166. if self.has_attr('dest_groups'):
  1167. body['destination_groups'] = self.get_groups_path(
  1168. domain_id, self.get_attr('dest_groups'))
  1169. self._set_attrs_if_specified(body, ['sequence_number', 'scope',
  1170. 'action', 'direction', 'logged',
  1171. 'ip_protocol', 'tag'])
  1172. if self.has_attr('service_ids'):
  1173. service_ids = self.get_attr('service_ids')
  1174. body['services'] = self.get_services_path(service_ids)
  1175. return body
  1176. @classmethod
  1177. def adapt_from_rule_dict(cls, rule_dict, domain_id, map_id):
  1178. entry_id = rule_dict.pop('id', None)
  1179. name = rule_dict.pop('display_name', None)
  1180. rule_def = cls(tenant=constants.POLICY_INFRA_TENANT,
  1181. domain_id=domain_id, map_id=map_id, entry_id=entry_id,
  1182. name=name)
  1183. rule_def.set_obj_dict(rule_dict)
  1184. return rule_def
  1185. class CommunicationMapEntryDef(SecurityPolicyRuleBaseDef):
  1186. @property
  1187. def path_pattern(self):
  1188. return (DOMAINS_PATH_PATTERN +
  1189. "%s/security-policies/%s/rules/")
  1190. def path_defs(self):
  1191. return (TenantDef, DomainDef, CommunicationMapDef)
  1192. class GatewayPolicyRuleDef(SecurityPolicyRuleBaseDef):
  1193. @property
  1194. def path_pattern(self):
  1195. return (DOMAINS_PATH_PATTERN +
  1196. "%s/gateway-policies/%s/rules/")
  1197. def path_defs(self):
  1198. return (TenantDef, DomainDef, GatewayPolicyDef)
  1199. # Currently supports only NSXT
  1200. class EnforcementPointDef(ResourceDef):
  1201. @property
  1202. def path_pattern(self):
  1203. return ENFORCEMENT_POINT_PATTERN
  1204. @property
  1205. def path_ids(self):
  1206. return ('tenant', 'ep_id')
  1207. @staticmethod
  1208. def resource_type():
  1209. return 'EnforcementPoint'
  1210. def path_defs(self):
  1211. return (TenantDef,)
  1212. def get_obj_dict(self):
  1213. body = super(EnforcementPointDef, self).get_obj_dict()
  1214. body['id'] = self.get_id()
  1215. if 'connection_info' not in body:
  1216. body['connection_info'] = {'resource_type': 'NSXTConnectionInfo'}
  1217. info = body['connection_info']
  1218. self._set_attrs_if_specified(info,
  1219. ['thumbprint', 'username', 'password',
  1220. 'ip_address'])
  1221. if self.get_attr('ip_address'):
  1222. info['enforcement_point_address'] = self.get_attr('ip_address')
  1223. if self.get_attr('edge_cluster_id'):
  1224. body['connection_info']['edge_cluster_ids'] = [
  1225. self.get_attr('edge_cluster_id')]
  1226. if self.get_attr('transport_zone_id'):
  1227. body['connection_info']['transport_zone_ids'] = [
  1228. self.get_attr('transport_zone_id')]
  1229. return body
  1230. class TransportZoneDef(ResourceDef):
  1231. @property
  1232. def path_pattern(self):
  1233. return TRANSPORT_ZONE_PATTERN
  1234. @property
  1235. def path_ids(self):
  1236. return ('tenant', 'ep_id', 'tz_id')
  1237. @staticmethod
  1238. def resource_type():
  1239. return 'PolicyTransportZone'
  1240. @staticmethod
  1241. def resource_use_cache():
  1242. return True
  1243. class EdgeClusterDef(ResourceDef):
  1244. @property
  1245. def path_pattern(self):
  1246. return EDGE_CLUSTER_PATTERN
  1247. @property
  1248. def path_ids(self):
  1249. return ('tenant', 'ep_id', 'ec_id')
  1250. @staticmethod
  1251. def resource_type():
  1252. return 'PolicyEdgeCluster'
  1253. @staticmethod
  1254. def resource_use_cache():
  1255. return True
  1256. class EdgeClusterNodeDef(ResourceDef):
  1257. @property
  1258. def path_pattern(self):
  1259. return (EDGE_CLUSTER_PATTERN + '%s/edge-nodes/')
  1260. @property
  1261. def path_ids(self):
  1262. return ('tenant', 'ep_id', 'ec_id', 'node_id')
  1263. @staticmethod
  1264. def resource_type():
  1265. return 'PolicyEdgeNode'
  1266. @staticmethod
  1267. def resource_use_cache():
  1268. return True
  1269. # Currently assumes one deployment point per id
  1270. class DeploymentMapDef(ResourceDef):
  1271. @property
  1272. def path_pattern(self):
  1273. return (DOMAINS_PATH_PATTERN + '%s/domain-deployment-maps/')
  1274. @property
  1275. def path_ids(self):
  1276. return ('tenant', 'domain_id', 'map_id')
  1277. @staticmethod
  1278. def resource_type():
  1279. return 'DeploymentMap'
  1280. def path_defs(self):
  1281. return (TenantDef, DomainDef)
  1282. def get_obj_dict(self):
  1283. body = super(DeploymentMapDef, self).get_obj_dict()
  1284. body['id'] = self.get_id()
  1285. ep_id = self.get_attr('ep_id')
  1286. tenant = self.get_tenant()
  1287. body['enforcement_point_path'] = EnforcementPointDef(
  1288. ep_id=ep_id,
  1289. tenant=tenant).get_resource_full_path() if ep_id else None
  1290. return body
  1291. class SegmentSecurityProfileDef(ResourceDef):
  1292. DEFAULT_PROFILE = 'default-segment-security-profile'
  1293. @property
  1294. def path_pattern(self):
  1295. return SEGMENT_SECURITY_PROFILES_PATH_PATTERN
  1296. @property
  1297. def path_ids(self):
  1298. return ('tenant', 'profile_id')
  1299. @staticmethod
  1300. def resource_type():
  1301. return 'SegmentSecurityProfile'
  1302. def path_defs(self):
  1303. return (TenantDef,)
  1304. def get_obj_dict(self):
  1305. body = super(SegmentSecurityProfileDef, self).get_obj_dict()
  1306. self._set_attrs_if_specified(body, ['bpdu_filter_enable',
  1307. 'dhcp_client_block_enabled',
  1308. 'dhcp_client_block_v6_enabled',
  1309. 'dhcp_server_block_enabled',
  1310. 'dhcp_server_block_v6_enabled',
  1311. 'non_ip_traffic_block_enabled',
  1312. 'ra_guard_enabled',
  1313. 'rate_limits_enabled'])
  1314. return body
  1315. class QoSObjectBase(object):
  1316. keys = []
  1317. def __init__(self, **kwargs):
  1318. self.attrs = kwargs
  1319. def get_obj_dict(self):
  1320. obj_dict = {}
  1321. for key in self.attrs:
  1322. if key in self.keys:
  1323. obj_dict[key] = self.attrs[key]
  1324. return obj_dict
  1325. class QoSRateLimiter(QoSObjectBase):
  1326. INGRESS_RATE_LIMITER_TYPE = 'IngressRateLimiter'
  1327. EGRESS_RATE_LIMITER_TYPE = 'EgressRateLimiter'
  1328. INGRESS_BRD_RATE_LIMITER_TYPE = 'IngressBroadcastRateLimiter'
  1329. keys = ['resource_type',
  1330. 'average_bandwidth', # Mb/s
  1331. 'peak_bandwidth', # Mb/s
  1332. 'burst_size', # byes
  1333. 'enabled'
  1334. ]
  1335. class QoSDscp(QoSObjectBase):
  1336. QOS_DSCP_TRUSTED = 'TRUSTED'
  1337. QOS_DSCP_UNTRUSTED = 'UNTRUSTED'
  1338. keys = ['mode', 'priority']
  1339. class QosProfileDef(ResourceDef):
  1340. @property
  1341. def path_pattern(self):
  1342. return QOS_PROFILES_PATH_PATTERN
  1343. @property
  1344. def path_ids(self):
  1345. return ('tenant', 'profile_id')
  1346. @staticmethod
  1347. def resource_type():
  1348. return 'QoSProfile'
  1349. def path_defs(self):
  1350. return (TenantDef,)
  1351. def get_obj_dict(self):
  1352. body = super(QosProfileDef, self).get_obj_dict()
  1353. self._set_attr_if_specified(body, 'class_of_service')
  1354. if self.has_attr('dscp'):
  1355. value = None
  1356. if self.get_attr('dscp'):
  1357. value = self.get_attr('dscp').get_obj_dict()
  1358. self._set_attr_if_specified(body, 'dscp', value=value)
  1359. if self.has_attr('shaper_configurations'):
  1360. value = None
  1361. if self.get_attr('shaper_configurations'):
  1362. value = [s.get_obj_dict()
  1363. for s in self.get_attr('shaper_configurations')]
  1364. self._set_attr_if_specified(body, 'shaper_configurations',
  1365. value=value)
  1366. return body
  1367. class SpoofguardProfileDef(ResourceDef):
  1368. DEFAULT_PROFILE = 'default-spoofguard-profile'
  1369. @property
  1370. def path_pattern(self):
  1371. return SPOOFGUARD_PROFILES_PATH_PATTERN
  1372. @property
  1373. def path_ids(self):
  1374. return ('tenant', 'profile_id')
  1375. @staticmethod
  1376. def resource_type():
  1377. return 'SpoofGuardProfile'
  1378. def path_defs(self):
  1379. return (TenantDef,)
  1380. def get_obj_dict(self):
  1381. body = super(SpoofguardProfileDef, self).get_obj_dict()
  1382. # TODO(asarfaty): add all attributes here
  1383. self._set_attr_if_specified(body, 'address_binding_whitelist')
  1384. return body
  1385. class IpDiscoveryProfileDef(ResourceDef):
  1386. DEFAULT_PROFILE = 'default-ip-discovery-profile'
  1387. @property
  1388. def path_pattern(self):
  1389. return IP_DISCOVERY_PROFILES_PATH_PATTERN
  1390. @property
  1391. def path_ids(self):
  1392. return ('tenant', 'profile_id')
  1393. @staticmethod
  1394. def resource_type():
  1395. return 'IPDiscoveryProfile'
  1396. def path_defs(self):
  1397. return (TenantDef,)
  1398. def get_obj_dict(self):
  1399. body = super(IpDiscoveryProfileDef, self).get_obj_dict()
  1400. # TODO(asarfaty): add all attributes here. currently used for read only
  1401. return body
  1402. class MacDiscoveryProfileDef(ResourceDef):
  1403. DEFAULT_PROFILE = 'default-mac-discovery-profile'
  1404. @property
  1405. def path_pattern(self):
  1406. return MAC_DISCOVERY_PROFILES_PATH_PATTERN
  1407. @property
  1408. def path_ids(self):
  1409. return ('tenant', 'profile_id')
  1410. @staticmethod
  1411. def resource_type():
  1412. return 'MacDiscoveryProfile'
  1413. def path_defs(self):
  1414. return (TenantDef,)
  1415. def get_obj_dict(self):
  1416. body = super(MacDiscoveryProfileDef, self).get_obj_dict()
  1417. self._set_attrs_if_specified(body, ['mac_change_enabled',
  1418. 'mac_learning_enabled',
  1419. 'unknown_unicast_flooding_enabled',
  1420. 'mac_limit_policy', 'mac_limit'])
  1421. return body
  1422. class Ipv6NdraProfileDef(ResourceDef):
  1423. @property
  1424. def path_pattern(self):
  1425. return IPV6_NDRA_PROFILES_PATH_PATTERN
  1426. @property
  1427. def path_ids(self):
  1428. return ('tenant', 'profile_id')
  1429. @staticmethod
  1430. def resource_type():
  1431. return 'Ipv6NdraProfile'
  1432. def path_defs(self):
  1433. return (TenantDef,)
  1434. def get_obj_dict(self):
  1435. body = super(Ipv6NdraProfileDef, self).get_obj_dict()
  1436. self._set_attrs_if_specified(body, ['ra_mode',
  1437. 'reachable_timer',
  1438. 'retransmit_interval'])
  1439. # Use default settings for dns and RA for now
  1440. # TODO(annak): expose when required
  1441. body['dns_config'] = {}
  1442. body['ra_config'] = {}
  1443. return body
  1444. class DhcpRelayConfigDef(ResourceDef):
  1445. @property
  1446. def path_pattern(self):
  1447. return DHCP_REALY_PATTERN
  1448. @property
  1449. def path_ids(self):
  1450. return ('tenant', 'config_id')
  1451. @staticmethod
  1452. def resource_type():
  1453. return 'DhcpRelayConfig'
  1454. def path_defs(self):
  1455. return (TenantDef,)
  1456. def get_obj_dict(self):
  1457. body = super(DhcpRelayConfigDef, self).get_obj_dict()
  1458. self._set_attr_if_specified(body, 'server_addresses')
  1459. return body
  1460. class WAFProfileDef(ResourceDef):
  1461. @property
  1462. def path_pattern(self):
  1463. return WAF_PROFILES_PATH_PATTERN
  1464. @property
  1465. def path_ids(self):
  1466. return ('tenant', 'profile_id')
  1467. @staticmethod
  1468. def resource_type():
  1469. return 'WAFProfile'
  1470. def path_defs(self):
  1471. return (TenantDef,)
  1472. def get_obj_dict(self):
  1473. body = super(WAFProfileDef, self).get_obj_dict()
  1474. # TODO(asarfaty): add all attributes here.
  1475. # Currently used for read only
  1476. return body
  1477. class MetadataProxyDef(ResourceDef):
  1478. @property
  1479. def path_pattern(self):
  1480. return MDPROXY_PATTERN
  1481. @property
  1482. def path_ids(self):
  1483. return ('tenant', 'mdproxy_id')
  1484. @staticmethod
  1485. def resource_type():
  1486. return 'MetadataProxyConfig'
  1487. @staticmethod
  1488. def resource_use_cache():
  1489. return True
  1490. def path_defs(self):
  1491. return (TenantDef,)
  1492. def get_obj_dict(self):
  1493. body = super(MetadataProxyDef, self).get_obj_dict()
  1494. self._set_attrs_if_specified(body, ['edge_cluster_path',
  1495. 'enable_standby_relocation',
  1496. 'secret', 'server_address'])
  1497. return body
  1498. class CertificateDef(ResourceDef):
  1499. @property
  1500. def path_pattern(self):
  1501. return CERTIFICATE_PATH_PATTERN
  1502. @property
  1503. def path_ids(self):
  1504. return ('tenant', 'certificate_id')
  1505. @staticmethod
  1506. def resource_type():
  1507. return "TlsTrustData"
  1508. def get_obj_dict(self):
  1509. body = super(CertificateDef, self).get_obj_dict()
  1510. self._set_attrs_if_specified(body, ['pem_encoded', 'key_algo',
  1511. 'private_key', 'passphrase'])
  1512. return body
  1513. class ExcludeListDef(ResourceDef):
  1514. @property
  1515. def path_pattern(self):
  1516. return EXCLUDE_LIST_PATH_PATTERN
  1517. @property
  1518. def path_ids(self):
  1519. # Adding dummy 2nd key to satisfy get_section_path
  1520. # This resource has no keys, since it is a single object
  1521. return ('tenant', 'Dummy')
  1522. @staticmethod
  1523. def resource_type():
  1524. return "PolicyExcludeList"
  1525. def get_obj_dict(self):
  1526. body = super(ExcludeListDef, self).get_obj_dict()
  1527. self._set_attr_if_specified(body, 'members')
  1528. return body
  1529. class NsxPolicyApi(object):
  1530. def __init__(self, client):
  1531. self.client = client
  1532. self.cache = utils.NsxLibCache(utils.DEFAULT_CACHE_AGE_SEC)
  1533. self.partial_updates = True
  1534. def disable_partial_updates(self):
  1535. self.partial_updates = False
  1536. def partial_updates_supported(self):
  1537. return self.partial_updates
  1538. def create_or_update(self, resource_def, partial_updates=False):
  1539. """Create or update a policy object.
  1540. This api will update an existing object, or create a new one if it
  1541. doesn't exist.
  1542. The policy API supports PATCH for create/update operations
  1543. """
  1544. path = resource_def.get_resource_path()
  1545. if resource_def.resource_use_cache():
  1546. self.cache.remove(path)
  1547. body = resource_def.get_obj_dict()
  1548. headers = None
  1549. if partial_updates:
  1550. headers = {'nsx-enable-partial-patch': 'true'}
  1551. self.client.patch(path, body, headers=headers)
  1552. def create_with_parent(self, parent_def, resource_def):
  1553. path = parent_def.get_resource_path()
  1554. body = parent_def.get_obj_dict()
  1555. if isinstance(resource_def, list):
  1556. child_dict_key = resource_def[0].get_last_section_dict_key
  1557. body[child_dict_key] = [r.get_obj_dict() for r in resource_def]
  1558. else:
  1559. child_dict_key = resource_def.get_last_section_dict_key
  1560. body[child_dict_key] = [resource_def.get_obj_dict()]
  1561. self.client.patch(path, body)
  1562. def delete(self, resource_def):
  1563. path = resource_def.get_resource_path()
  1564. if resource_def.resource_use_cache():
  1565. self.cache.remove(path)
  1566. self.client.delete(path)
  1567. def get(self, resource_def, silent=False):
  1568. path = resource_def.get_resource_path()
  1569. if resource_def.resource_use_cache():
  1570. # try to get it from the cache
  1571. result = self.cache.get(path)
  1572. if result:
  1573. return result
  1574. # call the client
  1575. result = self.client.get(path, silent=silent)
  1576. if resource_def.resource_use_cache():
  1577. # add the result to the cache
  1578. self.cache.update(path, result)
  1579. return result
  1580. def list(self, resource_def, silent=False):
  1581. path = resource_def.get_section_path()
  1582. return self.client.list(path, silent=silent)
  1583. def get_realized_entities(self, path, silent=False):
  1584. return self.client.list(REALIZATION_PATH % path,
  1585. silent=silent)['results']
  1586. def get_realized_entity(self, path, silent=False):
  1587. # Return first realization entity if exists
  1588. # Useful for resources with single realization entity
  1589. entities = self.get_realized_entities(path, silent=silent)
  1590. if entities:
  1591. return entities[0]
  1592. def get_realized_state(self, path, silent=False):
  1593. entity = self.get_realized_entity(path, silent=silent)
  1594. if entity:
  1595. return entity['state']