| #!/usr/bin/python |
| # Copyright 2017 Mirantis, Inc. |
| # |
| # Licensed under the Apache License, Version 2.0 (the "License"); |
| # you may not use this file except in compliance with the License. |
| # You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, software |
| # distributed under the License is distributed on an "AS IS" BASIS, |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| # See the License for the specific language governing permissions and |
| # limitations under the License. |
| |
| from netaddr import IPNetwork |
| |
| try: |
| from vnc_api import vnc_api |
| from vnc_api.vnc_api import LinklocalServiceEntryType, \ |
| LinklocalServicesTypes, GlobalVrouterConfig |
| from vnc_api.gen.resource_client import VirtualRouter, AnalyticsNode, \ |
| ConfigNode, DatabaseNode, BgpRouter |
| from vnc_api.gen.resource_xsd import AddressFamilies, BgpSessionAttributes, \ |
| BgpSession, BgpPeeringAttributes, BgpRouterParams |
| HAS_CONTRAIL = True |
| except ImportError: |
| HAS_CONTRAIL = False |
| |
| __opts__ = {} |
| |
| |
| def __virtual__(): |
| ''' |
| Only load this module if vnc_api library is installed. |
| ''' |
| if HAS_CONTRAIL: |
| return 'contrail' |
| |
| return False |
| |
| |
| def _auth(**kwargs): |
| ''' |
| Set up Contrail API credentials. |
| ''' |
| user = kwargs.get('user') |
| password = kwargs.get('password') |
| tenant_name = kwargs.get('project') |
| api_host = kwargs.get('api_server_ip') |
| api_port = kwargs.get('api_server_port') |
| api_base_url = kwargs.get('api_base_url') |
| use_ssl = False |
| auth_host = kwargs.get('auth_host_ip') |
| vnc_lib = vnc_api.VncApi(user, password, tenant_name, |
| api_host, api_port, api_base_url, wait_for_connect=True, |
| api_server_use_ssl=use_ssl, auth_host=auth_host) |
| |
| return vnc_lib |
| |
| |
| def _get_config(vnc_client, global_system_config = 'default-global-system-config'): |
| try: |
| gsc_obj = vnc_client.global_system_config_read(id=global_system_config) |
| except vnc_api.NoIdError: |
| gsc_obj = vnc_client.global_system_config_read(fq_name_str=global_system_config) |
| except: |
| gsc_obj = None |
| |
| return gsc_obj |
| |
| |
| def _get_rt_inst_obj(vnc_client): |
| |
| # TODO pick fqname hardcode from common |
| rt_inst_obj = vnc_client.routing_instance_read( |
| fq_name=['default-domain', 'default-project', |
| 'ip-fabric', '__default__']) |
| |
| return rt_inst_obj |
| |
| |
| def _get_ip(ip_w_pfx): |
| return str(IPNetwork(ip_w_pfx).ip) |
| |
| |
| |
| def virtual_router_list(**kwargs): |
| ''' |
| Return a list of all Contrail virtual routers |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.virtual_router_list |
| ''' |
| ret = {} |
| vnc_client = _auth(**kwargs) |
| vrouter_objs = vnc_client._objects_list('virtual-router', detail=True) |
| for vrouter_obj in vrouter_objs: |
| ret[vrouter_obj.name] = { |
| 'ip_address': vrouter_obj.virtual_router_ip_address, |
| 'dpdk_enabled': vrouter_obj.virtual_router_dpdk_enabled |
| } |
| return ret |
| |
| |
| def virtual_router_get(name, **kwargs): |
| ''' |
| Return a specific Contrail virtual router |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.virtual_router_get cmp01 |
| ''' |
| ret = {} |
| vrouter_objs = virtual_router_list(**kwargs) |
| if name in vrouter_objs: |
| ret[name] = vrouter_objs.get(name) |
| if len(ret) == 0: |
| return {'Error': 'Error in retrieving virtual router.'} |
| return ret |
| |
| |
| def virtual_router_create(name, ip_address, dpdk_enabled=False, **kwargs): |
| ''' |
| Create specific Contrail virtual router |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.virtual_router_create cmp02 10.10.10.102 |
| ''' |
| ret = {} |
| vnc_client = _auth(**kwargs) |
| gsc_obj = _get_config(vnc_client) |
| vrouter_objs = virtual_router_list(**kwargs) |
| if name in vrouter_objs: |
| return {'Error': 'Virtual router %s already exists' % name} |
| else: |
| vrouter_obj = VirtualRouter( |
| name, gsc_obj, |
| virtual_router_ip_address=ip_address) |
| vrouter_obj.set_virtual_router_dpdk_enabled(dpdk_enabled) |
| vnc_client.virtual_router_create(vrouter_obj) |
| ret = virtual_router_list(**kwargs) |
| return ret[name] |
| |
| |
| def virtual_router_delete(name, **kwargs): |
| ''' |
| Delete specific Contrail virtual router |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.virtual_router_delete cmp01 |
| ''' |
| vnc_client = _auth(**kwargs) |
| gsc_obj = _get_config(vnc_client) |
| vrouter_obj = VirtualRouter(name, gsc_obj) |
| vnc_client.virtual_router_delete( |
| fq_name=vrouter_obj.get_fq_name()) |
| |
| |
| def analytics_node_list(**kwargs): |
| ''' |
| Return a list of all Contrail analytics nodes |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.analytics_node_list |
| ''' |
| ret = {} |
| vnc_client = _auth(**kwargs) |
| node_objs = vnc_client._objects_list('analytics-node', detail=True) |
| for node_obj in node_objs: |
| ret[node_obj.name] = node_obj.__dict__ |
| return ret |
| |
| |
| def analytics_node_get(name, **kwargs): |
| ''' |
| Return a specific Contrail analytics node |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.analytics_node_get nal01 |
| ''' |
| ret = {} |
| vrouter_objs = analytics_node_list(**kwargs) |
| if name in vrouter_objs: |
| ret[name] = vrouter_objs.get(name) |
| if len(ret) == 0: |
| return {'Error': 'Error in retrieving analytics node.'} |
| return ret |
| |
| |
| def analytics_node_create(name, ip_address, **kwargs): |
| ''' |
| Create specific Contrail analytics node |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.analytics_node_create ntw03 10.10.10.103 |
| ''' |
| ret = {} |
| vnc_client = _auth(**kwargs) |
| gsc_obj = _get_config(vnc_client) |
| analytics_node_objs = analytics_node_list(**kwargs) |
| if name in analytics_node_objs: |
| return {'Error': 'Analytics node %s already exists' % name} |
| else: |
| analytics_node_obj = AnalyticsNode( |
| name, gsc_obj, |
| analytics_node_ip_address=ip_address) |
| vnc_client.analytics_node_create(analytics_node_obj) |
| ret = analytics_node_list(**kwargs) |
| return ret[name] |
| |
| |
| def analytics_node_delete(name, **kwargs): |
| ''' |
| Delete specific Contrail analytics node |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.analytics_node_delete cmp01 |
| ''' |
| vnc_client = _auth(**kwargs) |
| gsc_obj = _get_config(vnc_client) |
| analytics_node_obj = AnalyticsNode(name, gsc_obj) |
| vnc_client.analytics_node_delete( |
| fq_name=analytics_node_obj.get_fq_name()) |
| |
| |
| def config_node_list(**kwargs): |
| ''' |
| Return a list of all Contrail config nodes |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.config_node_list |
| ''' |
| ret = {} |
| vnc_client = _auth(**kwargs) |
| node_objs = vnc_client._objects_list('config-node', detail=True) |
| for node_obj in node_objs: |
| ret[node_obj.name] = node_obj.__dict__ |
| return ret |
| |
| |
| def config_node_get(name, **kwargs): |
| ''' |
| Return a specific Contrail config node |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.config_node_get nal01 |
| ''' |
| ret = {} |
| vrouter_objs = config_node_list(**kwargs) |
| if name in vrouter_objs: |
| ret[name] = vrouter_objs.get(name) |
| if len(ret) == 0: |
| return {'Error': 'Error in retrieving config node.'} |
| return ret |
| |
| |
| def config_node_create(name, ip_address, **kwargs): |
| ''' |
| Create specific Contrail config node |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.config_node_create ntw03 10.10.10.103 |
| ''' |
| ret = {} |
| vnc_client = _auth(**kwargs) |
| gsc_obj = _get_config(vnc_client) |
| config_node_objs = config_node_list(**kwargs) |
| if name in config_node_objs: |
| return {'Error': 'Config node %s already exists' % name} |
| else: |
| config_node_obj = ConfigNode( |
| name, gsc_obj, |
| config_node_ip_address=ip_address) |
| vnc_client.config_node_create(config_node_obj) |
| ret = config_node_list(**kwargs) |
| return ret[name] |
| |
| |
| def config_node_delete(name, **kwargs): |
| ''' |
| Delete specific Contrail config node |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.config_node_delete cmp01 |
| ''' |
| vnc_client = _auth(**kwargs) |
| gsc_obj = _get_config(vnc_client) |
| config_node_obj = ConfigNode(name, gsc_obj) |
| vnc_client.config_node_delete( |
| fq_name=config_node_obj.get_fq_name()) |
| |
| |
| def bgp_router_list(**kwargs): |
| ''' |
| Return a list of all Contrail BGP routers |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.bgp_router_list |
| ''' |
| ret = {} |
| vnc_client = _auth(**kwargs) |
| bgp_router_objs = vnc_client._objects_list('bgp-router', detail=True) |
| for bgp_router_obj in bgp_router_objs: |
| ret[bgp_router_obj.name] = bgp_router_obj.__dict__ |
| return ret |
| |
| |
| def bgp_router_get(name, **kwargs): |
| ''' |
| Return a specific Contrail BGP router |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.bgp_router_get nal01 |
| ''' |
| ret = {} |
| bgp_router_objs = bgp_router_list(**kwargs) |
| if name in bgp_router_objs: |
| ret[name] = bgp_router_objs.get(name) |
| if len(ret) == 0: |
| return {'Error': 'Error in retrieving BGP router.'} |
| return ret |
| |
| |
| def bgp_router_create(name, type, ip_address, asn=64512, **kwargs): |
| ''' |
| Create specific Contrail control node |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.bgp_router_create ntw03 control-node 10.10.10.103 |
| salt '*' contrail.bgp_router_create mx01 router 10.10.10.105 |
| ''' |
| ret = {} |
| vnc_client = _auth(**kwargs) |
| |
| bgp_router_objs = bgp_router_list(**kwargs) |
| if name in bgp_router_objs: |
| return {'Error': 'control node %s already exists' % name} |
| else: |
| address_families = ['route-target', 'inet-vpn', 'e-vpn', 'erm-vpn', |
| 'inet6-vpn'] |
| if type != 'control-node': |
| address_families.remove('erm-vpn') |
| |
| bgp_addr_fams = AddressFamilies(address_families) |
| bgp_sess_attrs = [ |
| BgpSessionAttributes(address_families=bgp_addr_fams)] |
| bgp_sessions = [BgpSession(attributes=bgp_sess_attrs)] |
| bgp_peering_attrs = BgpPeeringAttributes(session=bgp_sessions) |
| rt_inst_obj = _get_rt_inst_obj(vnc_client) |
| |
| if type == 'control-node': |
| vendor = 'contrail' |
| elif type == 'router': |
| vendor = 'mx' |
| else: |
| vendor = 'unknown' |
| |
| router_params = BgpRouterParams(router_type=type, |
| vendor=vendor, autonomous_system=int(asn), |
| identifier=_get_ip(ip_address), |
| address=_get_ip(ip_address), |
| port=179, address_families=bgp_addr_fams) |
| bgp_router_obj = BgpRouter(name, rt_inst_obj, |
| bgp_router_parameters=router_params) |
| vnc_client.bgp_router_create(bgp_router_obj) |
| ret = bgp_router_list(**kwargs) |
| return ret[name] |
| |
| |
| def bgp_router_delete(name, **kwargs): |
| ''' |
| Delete specific Contrail control node |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.bgp_router_delete mx01 |
| ''' |
| vnc_client = _auth(**kwargs) |
| gsc_obj = _get_control(vnc_client) |
| bgp_router_obj = BgpRouter(name, gsc_obj) |
| vnc_client.bgp_router_delete( |
| fq_name=bgp_router_obj.get_fq_name()) |
| |
| |
| def database_node_list(**kwargs): |
| ''' |
| Return a list of all Contrail database nodes |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.database_node_list |
| ''' |
| ret = {} |
| vnc_client = _auth(**kwargs) |
| node_objs = vnc_client._objects_list('database-node', detail=True) |
| for node_obj in node_objs: |
| ret[node_obj.name] = node_obj.__dict__ |
| return ret |
| |
| |
| def database_node_get(name, **kwargs): |
| ''' |
| Return a specific Contrail database node |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.database_node_get nal01 |
| ''' |
| ret = {} |
| vrouter_objs = database_node_list(**kwargs) |
| if name in vrouter_objs: |
| ret[name] = vrouter_objs.get(name) |
| if len(ret) == 0: |
| return {'Error': 'Error in retrieving database node.'} |
| return ret |
| |
| |
| def database_node_create(name, ip_address, **kwargs): |
| ''' |
| Create specific Contrail database node |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.database_node_create ntw03 10.10.10.103 |
| ''' |
| ret = {} |
| vnc_client = _auth(**kwargs) |
| gsc_obj = _get_config(vnc_client) |
| database_node_objs = database_node_list(**kwargs) |
| if name in database_node_objs: |
| return {'Error': 'Database node %s already exists' % name} |
| else: |
| database_node_obj = DatabaseNode( |
| name, gsc_obj, |
| database_node_ip_address=ip_address) |
| vnc_client.database_node_create(database_node_obj) |
| ret = database_node_list(**kwargs) |
| return ret[name] |
| |
| |
| def database_node_delete(name, **kwargs): |
| ''' |
| Delete specific Contrail database node |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.database_node_delete cmp01 |
| ''' |
| vnc_client = _auth(**kwargs) |
| gsc_obj = _get_database(vnc_client) |
| database_node_obj = databaseNode(name, gsc_obj) |
| vnc_client.database_node_delete( |
| fq_name=database_node_obj.get_fq_name()) |
| |
| |
| |
| |
| def _get_vrouter_config(vnc_client): |
| try: |
| config = vnc_client.global_vrouter_config_read( |
| fq_name=['default-global-system-config', 'default-global-vrouter-config']) |
| except Exception: |
| config = None |
| |
| return config |
| |
| |
| |
| def linklocal_service_list(**kwargs): |
| ''' |
| Return a list of all Contrail link local services |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.linklocal_service_list |
| ''' |
| ret = {} |
| vnc_client = _auth(**kwargs) |
| |
| current_config = _get_vrouter_config(vnc_client) |
| if current_config is None: |
| return ret |
| |
| service_list_res = current_config.get_linklocal_services() |
| if service_list_res is None: |
| service_list_obj = {'linklocal_service_entry': []} |
| else: |
| service_list_obj = service_list_res.__dict__ |
| for _, value in service_list_obj.iteritems(): |
| for entry in value: |
| service = entry.__dict__ |
| if 'linklocal_service_name' in service: |
| ret[service['linklocal_service_name']] = service |
| return ret |
| |
| |
| def linklocal_service_get(name, **kwargs): |
| ''' |
| Return a specific Contrail link local service |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.linklocal_service_get llservice |
| ''' |
| ret = {} |
| services = linklocal_service_list(**kwargs) |
| if name in services: |
| ret[name] = services.get(name) |
| if len(ret) == 0: |
| return {'Error': 'Error in retrieving link local service "{0}"'.format(name)} |
| return ret |
| |
| |
| def linklocal_service_create(name, lls_ip, lls_port, ipf_dns_or_ip, ipf_port, **kwargs): |
| ''' |
| Create specific Contrail link local service |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.linklocal_service_create \ |
| llservice 10.10.10.103 22 '["20.20.20.20", "30.30.30.30"]' 22 |
| salt '*' contrail.linklocal_service_create \ |
| llservice 10.10.10.103 22 link-local.service.dns-name 22 |
| ''' |
| ret = {} |
| vnc_client = _auth(**kwargs) |
| |
| current_config = _get_vrouter_config(vnc_client) |
| |
| service_entry = LinklocalServiceEntryType( |
| linklocal_service_name=name, |
| linklocal_service_ip=lls_ip, |
| linklocal_service_port=lls_port, |
| ip_fabric_service_port=ipf_port) |
| if isinstance(ipf_dns_or_ip, basestring): |
| service_entry.ip_fabric_DNS_service_name = ipf_dns_or_ip |
| elif isinstance(ipf_dns_or_ip, list): |
| service_entry.ip_fabric_service_ip = ipf_dns_or_ip |
| service_entry.ip_fabric_DNS_service_name = '' |
| |
| if current_config is None: |
| new_services = LinklocalServicesTypes([service_entry]) |
| new_config = GlobalVrouterConfig(linklocal_services=new_services) |
| vnc_client.global_vrouter_config_create(new_config) |
| else: |
| _current_service_list = current_config.get_linklocal_services() |
| if _current_service_list is None: |
| service_list = {'linklocal_service_entry': []} |
| else: |
| service_list = _current_service_list.__dict__ |
| new_services = [service_entry] |
| for key, value in service_list.iteritems(): |
| if key != 'linklocal_service_entry': |
| continue |
| for _entry in value: |
| entry = _entry.__dict__ |
| if 'linklocal_service_name' in entry: |
| if entry['linklocal_service_name'] == name: |
| return {'Error': 'Link local service "{0}" already exists'.format(name)} |
| new_services.append(_entry) |
| service_list[key] = new_services |
| new_config = GlobalVrouterConfig(linklocal_services=service_list) |
| vnc_client.global_vrouter_config_update(new_config) |
| ret = linklocal_service_list(**kwargs) |
| return ret[name] |
| |
| |
| def linklocal_service_delete(name, **kwargs): |
| ''' |
| Delete specific link local service entry |
| |
| CLI Example: |
| |
| .. code-block:: bash |
| |
| salt '*' contrail.linklocal_service_delete llservice |
| ''' |
| vnc_client = _auth(**kwargs) |
| |
| current_config = _get_vrouter_config(vnc_client) |
| |
| found = False |
| if current_config is not None: |
| _current_service_list = current_config.get_linklocal_services() |
| if _current_service_list is None: |
| service_list = {'linklocal_service_entry': []} |
| else: |
| service_list = _current_service_list.__dict__ |
| new_services = [] |
| for key, value in service_list.iteritems(): |
| if key != 'linklocal_service_entry': |
| continue |
| for _entry in value: |
| entry = _entry.__dict__ |
| if 'linklocal_service_name' in entry: |
| if entry['linklocal_service_name'] == name: |
| found = True |
| else: |
| new_services.append(_entry) |
| service_list[key] = new_services |
| new_config = GlobalVrouterConfig(linklocal_services=service_list) |
| vnc_client.global_vrouter_config_update(new_config) |
| if not found: |
| return {'Error': 'Link local service "{0}" not found'.format(name)} |