class ControlProvisioner(object):
    def __init__(self, args_str=None):
        self._args = None
        if not args_str:
            args_str = ' '.join(sys.argv[1:])
        self._parse_args(args_str)
        if self._args.peer_list:
            peer_list = self._args.peer_list.split(',')
        else:
            peer_list = None
        if self._args.router_asn and not self._args.oper:
            self._vnc_lib = VncApiAdmin(
                self._args.use_admin_api,
                self._args.admin_user,
                self._args.admin_password,
                self._args.admin_tenant_name,
                self._args.api_server_ip,
                self._args.api_server_port,
                '/',
                api_server_use_ssl=self._args.api_server_use_ssl)

            # Update global system config also with this ASN
            gsc_obj = self._vnc_lib.global_system_config_read(
                fq_name=['default-global-system-config'])
            gsc_obj.set_autonomous_system(self._args.router_asn)
            if self._args.ibgp_auto_mesh is not None:
                gsc_obj.set_ibgp_auto_mesh(self._args.ibgp_auto_mesh)

            if self._args.set_graceful_restart_parameters == True:
                gr_params = GracefulRestartParametersType()
                gr_params.set_restart_time(
                    int(self._args.graceful_restart_time))
                gr_params.set_long_lived_restart_time(
                    int(self._args.long_lived_graceful_restart_time))
                gr_params.set_end_of_rib_timeout(
                    int(self._args.end_of_rib_timeout))
                gr_params.set_enable(self._args.graceful_restart_enable)
                gr_params.set_bgp_helper_enable(
                    self._args.graceful_restart_bgp_helper_enable)
                gr_params.set_xmpp_helper_enable(
                    self._args.graceful_restart_xmpp_helper_enable)
                gsc_obj.set_graceful_restart_parameters(gr_params)
            self._vnc_lib.global_system_config_update(gsc_obj)
            return

        bp_obj = BgpProvisioner(
            self._args.admin_user,
            self._args.admin_password,
            self._args.admin_tenant_name,
            self._args.api_server_ip,
            self._args.api_server_port,
            api_server_use_ssl=self._args.api_server_use_ssl,
            use_admin_api=self._args.use_admin_api,
            sub_cluster_name=self._args.sub_cluster_name,
            peer_list=peer_list)
        if self._args.oper == 'add':
            if self._args.sub_cluster_name:
                bp_obj.add_bgp_router('external-control-node',
                                      self._args.host_name, self._args.host_ip,
                                      self._args.router_asn,
                                      self._args.address_families,
                                      self._args.md5,
                                      self._args.local_autonomous_system,
                                      self._args.bgp_server_port)
            else:
                bp_obj.add_bgp_router(
                    'control-node', self._args.host_name, self._args.host_ip,
                    self._args.router_asn, self._args.address_families,
                    self._args.md5, self._args.local_autonomous_system,
                    self._args.bgp_server_port)
        elif self._args.oper == 'del':
            bp_obj.del_bgp_router(self._args.host_name)
        else:
            print "Unknown operation %s. Only 'add' and 'del' supported"\
                % (self._args.oper)

    # end __init__

    def gr_time_type(self, value):
        time = int(value)
        if time < 0 or time > 4095:
            raise argparse.ArgumentTypeError(
                "graceful_restart_time %s must be in range (0..4095)" % value)
        return time

    def llgr_time_type(self, value):
        time = int(value)
        if time < 0 or time > 16777215:
            raise argparse.ArgumentTypeError(
                "long_lived_graceful_restart_time %s must be in range (0..16777215)"
                % value)
        return time

    def _parse_args(self, args_str):
        '''
        Eg. python provision_control.py --host_name a3s30.contrail.juniper.net
                                        --host_ip 10.1.1.1
                                        --router_asn 64512
                                        --ibgp_auto_mesh|--no_ibgp_auto_mesh
                                        --api_server_ip 127.0.0.1
                                        --api_server_port 8082
                                        --api_server_use_ssl False
                                        --oper <add | del>
                                        --md5 <key value>|None(optional)
                                        --bgp_server_port <port>|None(optional)
                                        --local_autonomous_system <ASN value>|None(optional)
                                        --graceful_restart_time 300
                                        --long_lived_graceful_restart_time 300
                                        --end_of_rib_timeout 300
                                        --set_graceful_restart_parameters False
                                        --graceful_restart_bgp_helper_enable False
                                        --graceful_restart_xmpp_helper_enable False
                                        --graceful_restart_enable False

        '''

        # Source any specified config/ini file
        # Turn off help, so we print all options in response to -h
        conf_parser = argparse.ArgumentParser(add_help=False)

        conf_parser.add_argument("-c",
                                 "--conf_file",
                                 help="Specify config file",
                                 metavar="FILE")
        args, remaining_argv = conf_parser.parse_known_args(args_str.split())

        defaults = {
            'router_asn': '64512',
            'bgp_server_port': 179,
            'local_autonomous_system': None,
            'ibgp_auto_mesh': None,
            'api_server_ip': '127.0.0.1',
            'api_server_port': '8082',
            'api_server_use_ssl': False,
            'oper': None,
            'admin_user': None,
            'admin_password': None,
            'admin_tenant_name': None,
            'md5': None,
            'graceful_restart_time': 300,
            'long_lived_graceful_restart_time': 300,
            'end_of_rib_timeout': 300,
            'graceful_restart_bgp_helper_enable': False,
            'graceful_restart_xmpp_helper_enable': False,
            'graceful_restart_enable': False,
            'set_graceful_restart_parameters': False,
            'sub_cluster_name': None,
            'peer_list': None,
        }

        if args.conf_file:
            config = ConfigParser.SafeConfigParser()
            config.read([args.conf_file])
            defaults.update(dict(config.items("DEFAULTS")))

        # Override with CLI options
        # Don't surpress add_help here so it will handle -h
        parser = argparse.ArgumentParser(
            # Inherit options from config_parser
            parents=[conf_parser],
            # print script description with -h/--help
            description=__doc__,
            # Don't mess with format of description
            formatter_class=argparse.RawDescriptionHelpFormatter,
        )
        parser.set_defaults(**defaults)

        parser.add_argument("--host_name",
                            help="hostname name of control-node")
        parser.add_argument("--host_ip", help="IP address of control-node")
        parser.add_argument("--router_asn",
                            help="AS Number the control-node is in",
                            required=True)
        parser.add_argument("--bgp_server_port",
                            help="BGP server port number (Default: 179)")
        parser.add_argument(
            "--local_autonomous_system",
            help=
            "Local autonomous-system number used to peer contrail-control bgp speakers across different geographic locations"
        )
        parser.add_argument("--address_families",
                            help="Address family list",
                            choices=[
                                "route-target", "inet-vpn", "e-vpn", "erm-vpn",
                                "inet6-vpn"
                            ],
                            nargs="*",
                            default=[])
        parser.add_argument("--md5", help="Md5 config for the node")
        parser.add_argument("--ibgp_auto_mesh",
                            help="Create iBGP mesh automatically",
                            dest='ibgp_auto_mesh',
                            action='store_true')
        parser.add_argument("--no_ibgp_auto_mesh",
                            help="Don't create iBGP mesh automatically",
                            dest='ibgp_auto_mesh',
                            action='store_false')
        parser.add_argument("--api_server_port", help="Port of api server")
        parser.add_argument("--api_server_use_ssl",
                            help="Use SSL to connect with API server")
        parser.add_argument("--oper",
                            help="Provision operation to be done(add or del)")
        parser.add_argument("--admin_user", help="Name of keystone admin user")
        parser.add_argument("--admin_password",
                            help="Password of keystone admin user")
        parser.add_argument("--admin_tenant_name",
                            help="Tenamt name for keystone admin user")
        parser.add_argument("--graceful_restart_time",
                            help="Graceful Restart Time in seconds (0..4095)",
                            type=self.gr_time_type,
                            default=300,
                            required=False)
        parser.add_argument(
            "--long_lived_graceful_restart_time",
            help="Long Lived Graceful Restart Time in seconds (0..16777215)",
            type=self.llgr_time_type,
            default=300,
            required=False)
        parser.add_argument("--end_of_rib_timeout",
                            help="EndOfRib timeout value in seconds (0..4095)",
                            type=self.gr_time_type,
                            default=300,
                            required=False)
        parser.add_argument("--graceful_restart_bgp_helper_enable",
                            action='store_true',
                            help="Enable helper mode for BGP graceful restart")
        parser.add_argument(
            "--graceful_restart_xmpp_helper_enable",
            action='store_true',
            help="Enable helper mode for XMPP graceful restart")
        parser.add_argument("--graceful_restart_enable",
                            action='store_true',
                            help="Enable Graceful Restart")
        parser.add_argument("--set_graceful_restart_parameters",
                            action='store_true',
                            help="Set Graceful Restart Parameters")
        parser.add_argument("--sub_cluster_name",
                            help="sub cluster to associate to",
                            required=False)
        parser.add_argument("--peer_list",
                            help="list of control node names to peer",
                            required=False)
        group = parser.add_mutually_exclusive_group(required=True)
        group.add_argument("--api_server_ip",
                           help="IP address of api server",
                           nargs='+',
                           type=str)
        group.add_argument("--use_admin_api",
                           default=False,
                           help="Connect to local api-server on admin port",
                           action="store_true")

        self._args = parser.parse_args(remaining_argv)
class VrouterProvisioner(object):

    def __init__(self, args_str=None):
        self._args = None
        if not args_str:
            args_str = ' '.join(sys.argv[1:])
        self._parse_args(args_str)

        connected = False
        tries = 0
        while not connected:
            try:
                self._vnc_lib = VncApiAdmin(
                    self._args.use_admin_api,
                    self._args.admin_user, self._args.admin_password,
                    self._args.admin_tenant_name,
                    self._args.api_server_ip,
                    self._args.api_server_port, '/',
                    auth_host=self._args.openstack_ip,
                    api_server_use_ssl=self._args.api_server_use_ssl)
                connected = True
            except ResourceExhaustionError: # haproxy throws 503
                if tries < 10:
                    tries += 1
                    time.sleep(3)
                else:
                    raise
        gsc_obj = self._vnc_lib.global_system_config_read(
            fq_name=['default-global-system-config'])
        self._global_system_config_obj = gsc_obj

        rt_inst_obj = self._vnc_lib.routing_instance_read(
            fq_name=['default-domain', 'default-project',
                     'ip-fabric', '__default__'])
        self._fab_rt_inst_obj = rt_inst_obj

        if self._args.oper == 'add':
            self.add_vrouter()
            if not self._args.disable_vhost_vmi:
                self.add_vhost0_vmi()
        elif self._args.oper == 'del':
            self.del_vhost0_vmi()
            self.del_vrouter()
        else:
            print "Unknown operation %s. Only 'add' and 'del' supported"\
                % (self._args.oper)

    # end __init__

    def _parse_args(self, args_str):
        '''
        Eg. python provision_vrouter.py --host_name a3s30.contrail.juniper.net
                                        --host_ip 10.1.1.1
                                        --api_server_ip 127.0.0.1
                                        --api_server_port 8082
                                        --api_server_use_ssl False
                                        --oper <add | del>
                                        [--ip_fabric_subnet 192.168.10.0/24]
                                        [--dpdk-enabled]
        '''

        # Source any specified config/ini file
        # Turn off help, so we print all options in response to -h
        conf_parser = argparse.ArgumentParser(add_help=False)

        conf_parser.add_argument("-c", "--conf_file",
                                 help="Specify config file", metavar="FILE")
        args, remaining_argv = conf_parser.parse_known_args(args_str.split())

        defaults = {
            'api_server_ip': '127.0.0.1',
            'api_server_port': '8082',
            'api_server_use_ssl': False,
            'oper': 'add',
            'control_names': [],
            'router_type': None,
            'dpdk_enabled': False,
            'disable_vhost_vmi': False,
            'enable_vhost_vmi_policy': False,
            'sub_cluster_name': None,
            'ip_fabric_subnet': None
        }
        ksopts = {
            'admin_user': '******',
            'admin_password': '******',
            'admin_tenant_name': 'default-domain'
        }

        if args.conf_file:
            config = ConfigParser.SafeConfigParser()
            config.read([args.conf_file])
            defaults.update(dict(config.items("DEFAULTS")))
            if 'KEYSTONE' in config.sections():
                ksopts.update(dict(config.items("KEYSTONE")))

        # Override with CLI options
        # Don't surpress add_help here so it will handle -h
        parser = argparse.ArgumentParser(
            # Inherit options from config_parser
            parents=[conf_parser],
            # print script description with -h/--help
            description=__doc__,
            # Don't mess with format of description
            formatter_class=argparse.RawDescriptionHelpFormatter,
        )
        defaults.update(ksopts)
        parser.set_defaults(**defaults)

        parser.add_argument(
            "--host_name", help="hostname name of compute-node", required=True)
        parser.add_argument("--host_ip", help="IP address of compute-node", required=True)
        parser.add_argument(
            "--control_names",
            help="List of control-node names compute node connects to")
        parser.add_argument("--api_server_port", help="Port of api server")
        parser.add_argument("--api_server_use_ssl",
                        help="Use SSL to connect with API server")
        parser.add_argument(
            "--oper", default='add',
            help="Provision operation to be done(add or del)")
        parser.add_argument(
            "--admin_user", help="Name of keystone admin user")
        parser.add_argument(
            "--admin_password", help="Password of keystone admin user")
        parser.add_argument(
            "--admin_tenant_name", help="Tenamt name for keystone admin user")
        parser.add_argument(
            "--openstack_ip", help="IP address of openstack node")
        parser.add_argument(
            "--router_type", help="Type of the virtual router (tor-service-node,embedded or none)")
        parser.add_argument(
            "--dpdk_enabled", action="store_true", help="Whether forwarding mode on vrouter is DPDK based")
        parser.add_argument(
            "--disable_vhost_vmi", action="store_true", help="Do not create vhost0 vmi if flag is set")
        parser.add_argument(
            "--enable_vhost_vmi_policy", action="store_true", help="Enable vhost0 vmi policy if flag is set")
        parser.add_argument(
            "--sub_cluster_name", help="Sub cluster this vrouter to be part of")
        parser.add_argument("--ip_fabric_subnet",
                            help = "Add the ip_fabric_subnet")
        group = parser.add_mutually_exclusive_group(required=True)
        group.add_argument(
            "--api_server_ip", help="IP address of api server",
            nargs='+', type=str)
        group.add_argument("--use_admin_api",
                            default=False,
                            help = "Connect to local api-server on admin port",
                            action="store_true")

        self._args = parser.parse_args(remaining_argv)

    # end _parse_args

    def add_vrouter(self):
        gsc_obj = self._global_system_config_obj

        if self._args.ip_fabric_subnet:
            ip_subnet, mask = self._args.ip_fabric_subnet.split('/')
            so = SubnetType(ip_subnet, int(mask))
            sl = gsc_obj.get_ip_fabric_subnets()
            if sl is None:
                gsc_obj.set_ip_fabric_subnets(SubnetListType([so]))
                self._vnc_lib.global_system_config_update(gsc_obj)
            elif so not in sl.subnet:
                sl.subnet.append(so)
                gsc_obj.set_ip_fabric_subnets(sl)
                self._vnc_lib.global_system_config_update(gsc_obj)

        vrouter_obj = VirtualRouter(
            self._args.host_name, gsc_obj,
            virtual_router_ip_address=self._args.host_ip)
        vrouter_exists = True

        try:
            vrouter_obj = self._vnc_lib.virtual_router_read(
                fq_name=vrouter_obj.get_fq_name())
        except NoIdError:
            vrouter_exists = False

        if self._args.sub_cluster_name:
            sub_cluster_obj = SubCluster(self._args.sub_cluster_name)
            try:
                sub_cluster_obj = self._vnc_lib.sub_cluster_read(
                    fq_name=sub_cluster_obj.get_fq_name())
            except NoIdError:
                raise RuntimeError("Sub cluster has to be provisioned first")
            vrouter_obj.add_sub_cluster(sub_cluster_obj)

        # Configure router type
        if self._args.router_type:
            vrouter_obj.set_virtual_router_type(self._args.router_type)
        if self._args.dpdk_enabled:
            vrouter_obj.set_virtual_router_dpdk_enabled(True)
        else:
            vrouter_obj.set_virtual_router_dpdk_enabled(False)
        if vrouter_exists:
            self.vrouter_fq_name = vrouter_obj.get_fq_name()
            self._vnc_lib.virtual_router_update(vrouter_obj)
        else:
            try:
                self.vrouter_fq_name = vrouter_obj.get_fq_name()
                self._vnc_lib.virtual_router_create(vrouter_obj)
            except RefsExistError:
                print "Already created!"

    # end add_vrouter

    def add_vhost0_vmi(self):
        vrouter_exists = True
        try:
            vrouter_obj = self._vnc_lib.virtual_router_read(
                fq_name=self.vrouter_fq_name)
        except NoIdError:
            vrouter_exists = False

        if not vrouter_exists:
            print "No vrouter object found cannot add vhost0 vmi !"
            return

        try:
            vhost0_vmi_fq_name = self.vrouter_fq_name
            vhost0_vmi_fq_name.append('vhost0')
            vhost0_vmi = self._vnc_lib.virtual_machine_interface_read(
                fq_name = vhost0_vmi_fq_name)
            vhost0_vmi_exists = True
        except NoIdError:
            vhost0_vmi_exists = False
            vhost0_vmi =  VirtualMachineInterface(name="vhost0", parent_obj = vrouter_obj)
            ip_fab_vn = self._vnc_lib.virtual_network_read(fq_name = [u'default-domain', u'default-project', u'ip-fabric'])
            vhost0_vmi.set_virtual_network(ip_fab_vn)

        # Enable/Disable policy on the vhost0 vmi
        if self._args.enable_vhost_vmi_policy:
            vhost0_vmi.set_virtual_machine_interface_disable_policy(False)
        else:
            vhost0_vmi.set_virtual_machine_interface_disable_policy(True)

        if vhost0_vmi_exists:
           self._vnc_lib.virtual_machine_interface_update(vhost0_vmi)
        else:
            try:
                self._vnc_lib.virtual_machine_interface_create(vhost0_vmi)
            except RefsExistError:
                print "vhost0 vmi already created!"

    # end add_vhost0_vmi

    def del_vrouter(self):
        gsc_obj = self._global_system_config_obj
        vrouter_obj = VirtualRouter(self._args.host_name, gsc_obj)
        vrouter_exists = True
        try:
            vrouter = self._vnc_lib.virtual_router_read(
                fq_name=vrouter_obj.get_fq_name())
        except NoIdError:
            vrouter_exists = False

        if vrouter_exists:
            self._vnc_lib.virtual_router_delete(
                fq_name=vrouter_obj.get_fq_name())
        else:
            print " vrouter object not found "

    # end del_vrouter

    def del_vhost0_vmi(self):
        gsc_obj = self._global_system_config_obj
        vrouter_obj = VirtualRouter(self._args.host_name, gsc_obj)
        vhost0_vmi_fq_name = vrouter_obj.get_fq_name()
        vhost0_vmi_fq_name.append('vhost0')
        vhost0_vmi_exists = True
        try:
            vhost0_vmi = self._vnc_lib.virtual_machine_interface_read(
                fq_name = vhost0_vmi_fq_name)
        except NoIdError:
            vhost0_vmi_exists = False

        if vhost0_vmi_exists:
            self._vnc_lib.virtual_machine_interface_delete(fq_name=vhost0_vmi_fq_name)
            print " Deleted vhost0 vmi %s " % vhost0_vmi_fq_name
        else:
            print " No vhost0 vmi found "
Beispiel #3
0
class VrouterProvisioner(object):
    def __init__(self, args_str=None):
        self._args = None
        if not args_str:
            args_str = ' '.join(sys.argv[1:])
        self._parse_args(args_str)

        connected = False
        tries = 0
        while not connected:
            try:
                self._vnc_lib = VncApiAdmin(
                    self._args.use_admin_api,
                    self._args.admin_user,
                    self._args.admin_password,
                    self._args.admin_tenant_name,
                    self._args.api_server_ip,
                    self._args.api_server_port,
                    '/',
                    auth_host=self._args.openstack_ip,
                    api_server_use_ssl=self._args.api_server_use_ssl)
                connected = True
            except ResourceExhaustionError:  # haproxy throws 503
                if tries < 10:
                    tries += 1
                    time.sleep(3)
                else:
                    raise
        gsc_obj = self._vnc_lib.global_system_config_read(
            fq_name=['default-global-system-config'])
        self._global_system_config_obj = gsc_obj

        rt_inst_obj = self._vnc_lib.routing_instance_read(fq_name=[
            'default-domain', 'default-project', 'ip-fabric', '__default__'
        ])
        self._fab_rt_inst_obj = rt_inst_obj

        if self._args.oper == 'add':
            self.add_vrouter()
            if not self._args.disable_vhost_vmi:
                self.add_vhost0_vmi()
        elif self._args.oper == 'del':
            self.del_vhost0_vmi()
            self.del_vrouter()
        else:
            print("Unknown operation %s. Only 'add' and 'del' supported" %
                  (self._args.oper))

    # end __init__

    def _parse_args(self, args_str):
        """
        Sample usage.

        python provision_vrouter.py
                --host_name a3s30.contrail.juniper.net
                --host_ip 10.1.1.1
                --api_server_ip 127.0.0.1
                --api_server_port 8082
                --api_server_use_ssl False
                --oper <add | del>
                [--ip_fabric_subnet 192.168.10.0/24]
                [--dpdk-enabled]
                [--sriov-physnets physnet1=eth0 physnet2=eth1]
        """
        # Source any specified config/ini file
        # Turn off help, so we print all options in response to -h
        conf_parser = argparse.ArgumentParser(add_help=False)

        conf_parser.add_argument("-c",
                                 "--conf_file",
                                 help="Specify config file",
                                 metavar="FILE")
        args, remaining_argv = conf_parser.parse_known_args(args_str.split())

        defaults = {
            'api_server_ip': '127.0.0.1',
            'api_server_port': '8082',
            'api_server_use_ssl': False,
            'oper': 'add',
            'control_names': [],
            'router_type': None,
            'dpdk_enabled': False,
            'disable_vhost_vmi': False,
            'enable_vhost_vmi_policy': False,
            'sub_cluster_name': None,
            'ip_fabric_subnet': None
        }
        ksopts = {
            'admin_user': '******',
            'admin_password': '******',
            'admin_tenant_name': 'default-domain'
        }

        if args.conf_file:
            config = configparser.SafeConfigParser()
            config.read([args.conf_file])
            defaults.update(dict(config.items("DEFAULTS")))
            if 'KEYSTONE' in config.sections():
                ksopts.update(dict(config.items("KEYSTONE")))

        # Override with CLI options
        # Don't surpress add_help here so it will handle -h
        parser = argparse.ArgumentParser(
            # Inherit options from config_parser
            parents=[conf_parser],
            # print script description with -h/--help
            description=__doc__,
            # Don't mess with format of description
            formatter_class=argparse.RawDescriptionHelpFormatter,
        )
        defaults.update(ksopts)
        parser.set_defaults(**defaults)

        parser.add_argument("--host_name",
                            help="hostname name of compute-node",
                            required=True)
        parser.add_argument("--host_ip",
                            help="IP address of compute-node",
                            required=True)
        parser.add_argument(
            "--control_names",
            help="List of control-node names compute node connects to")
        parser.add_argument("--api_server_port", help="Port of api server")
        parser.add_argument("--api_server_use_ssl",
                            help="Use SSL to connect with API server")
        parser.add_argument("--oper",
                            default='add',
                            help="Provision operation to be done(add or del)")
        parser.add_argument("--admin_user", help="Name of keystone admin user")
        parser.add_argument("--admin_password",
                            help="Password of keystone admin user")
        parser.add_argument("--admin_tenant_name",
                            help="Tenamt name for keystone admin user")
        parser.add_argument("--openstack_ip",
                            help="IP address of openstack node")
        parser.add_argument(
            "--router_type",
            help="Type of the virtual router (tor-service-node,embedded,none)")
        parser.add_argument(
            "--dpdk_enabled",
            action="store_true",
            help="Whether forwarding mode on vrouter is DPDK based")
        parser.add_argument("--disable_vhost_vmi",
                            action="store_true",
                            help="Do not create vhost0 vmi if flag is set")
        parser.add_argument("--enable_vhost_vmi_policy",
                            action="store_true",
                            help="Enable vhost0 vmi policy if flag is set")
        parser.add_argument("--sub_cluster_name",
                            help="Sub cluster this vrouter to be part of")
        parser.add_argument("--ip_fabric_subnet",
                            help="Add the ip_fabric_subnet")
        parser.add_argument("--sriov_physnets",
                            metavar="KEY=VALUE",
                            nargs='+',
                            action=SriovPhysNetAction,
                            help="physnet to vourter interface mapping")
        group = parser.add_mutually_exclusive_group(required=True)
        group.add_argument("--api_server_ip",
                           help="IP address of api server",
                           nargs='+',
                           type=str)
        group.add_argument("--use_admin_api",
                           default=False,
                           help="Connect to local api-server on admin port",
                           action="store_true")

        self._args = parser.parse_args(remaining_argv)

    # end _parse_args

    def add_vrouter(self):
        gsc_obj = self._global_system_config_obj

        if self._args.ip_fabric_subnet:
            ip_subnet, mask = self._args.ip_fabric_subnet.split('/')
            so = SubnetType(ip_subnet, int(mask))
            sl = gsc_obj.get_ip_fabric_subnets()
            if sl is None:
                gsc_obj.set_ip_fabric_subnets(SubnetListType([so]))
                self._vnc_lib.global_system_config_update(gsc_obj)
            elif so not in sl.subnet:
                sl.subnet.append(so)
                gsc_obj.set_ip_fabric_subnets(sl)
                self._vnc_lib.global_system_config_update(gsc_obj)

        vrouter_obj = VirtualRouter(
            self._args.host_name,
            gsc_obj,
            virtual_router_ip_address=self._args.host_ip)
        vrouter_exists = True

        try:
            vrouter_obj = self._vnc_lib.virtual_router_read(
                fq_name=vrouter_obj.get_fq_name())
        except NoIdError:
            vrouter_exists = False

        if self._args.sub_cluster_name:
            sub_cluster_obj = SubCluster(self._args.sub_cluster_name)
            try:
                sub_cluster_obj = self._vnc_lib.sub_cluster_read(
                    fq_name=sub_cluster_obj.get_fq_name())
            except NoIdError:
                raise RuntimeError("Sub cluster has to be provisioned first")
            vrouter_obj.add_sub_cluster(sub_cluster_obj)

        # Configure router type
        if self._args.router_type:
            vrouter_obj.set_virtual_router_type(self._args.router_type)
        if self._args.dpdk_enabled:
            vrouter_obj.set_virtual_router_dpdk_enabled(True)
        else:
            vrouter_obj.set_virtual_router_dpdk_enabled(False)

        # Configure sirov physical networks
        if self._args.sriov_physnets:
            vrouter_obj.set_virtual_router_sriov_physical_networks(
                self._args.sriov_physnets)
        if vrouter_exists:
            self.vrouter_fq_name = vrouter_obj.get_fq_name()
            self._vnc_lib.virtual_router_update(vrouter_obj)
        else:
            try:
                self.vrouter_fq_name = vrouter_obj.get_fq_name()
                self._vnc_lib.virtual_router_create(vrouter_obj)
            except RefsExistError:
                print("Already created!")

    # end add_vrouter

    def add_vhost0_vmi(self):
        vrouter_exists = True
        try:
            vrouter_obj = self._vnc_lib.virtual_router_read(
                fq_name=self.vrouter_fq_name)
        except NoIdError:
            vrouter_exists = False

        if not vrouter_exists:
            print("No vrouter object found cannot add vhost0 vmi !")
            return

        try:
            vhost0_vmi_fq_name = self.vrouter_fq_name
            vhost0_vmi_fq_name.append('vhost0')
            vhost0_vmi = self._vnc_lib.virtual_machine_interface_read(
                fq_name=vhost0_vmi_fq_name)
            vhost0_vmi_exists = True
        except NoIdError:
            vhost0_vmi_exists = False
            vhost0_vmi = VirtualMachineInterface(name="vhost0",
                                                 parent_obj=vrouter_obj)
            ip_fab_vn = self._vnc_lib.virtual_network_read(
                fq_name=[u'default-domain', u'default-project', u'ip-fabric'])
            vhost0_vmi.set_virtual_network(ip_fab_vn)

        # Enable/Disable policy on the vhost0 vmi
        if self._args.enable_vhost_vmi_policy:
            vhost0_vmi.set_virtual_machine_interface_disable_policy(False)
        else:
            vhost0_vmi.set_virtual_machine_interface_disable_policy(True)

        if vhost0_vmi_exists:
            self._vnc_lib.virtual_machine_interface_update(vhost0_vmi)
        else:
            try:
                self._vnc_lib.virtual_machine_interface_create(vhost0_vmi)
            except RefsExistError:
                print("vhost0 vmi already created!")

    # end add_vhost0_vmi

    def del_vrouter(self):
        gsc_obj = self._global_system_config_obj
        vrouter_obj = VirtualRouter(self._args.host_name, gsc_obj)
        vrouter_exists = True
        try:
            self._vnc_lib.virtual_router_read(
                fq_name=vrouter_obj.get_fq_name())
        except NoIdError:
            vrouter_exists = False

        if vrouter_exists:
            self._vnc_lib.virtual_router_delete(
                fq_name=vrouter_obj.get_fq_name())
        else:
            print(" vrouter object not found ")

    # end del_vrouter

    def del_vhost0_vmi(self):
        gsc_obj = self._global_system_config_obj
        vrouter_obj = VirtualRouter(self._args.host_name, gsc_obj)
        vhost0_vmi_fq_name = vrouter_obj.get_fq_name()
        vhost0_vmi_fq_name.append('vhost0')
        vhost0_vmi_exists = True
        try:
            self._vnc_lib.virtual_machine_interface_read(
                fq_name=vhost0_vmi_fq_name)
        except NoIdError:
            vhost0_vmi_exists = False

        if vhost0_vmi_exists:
            self._vnc_lib.virtual_machine_interface_delete(
                fq_name=vhost0_vmi_fq_name)
            print(" Deleted vhost0 vmi %s " % vhost0_vmi_fq_name)
        else:
            print(" No vhost0 vmi found ")
class ControlProvisioner(object):

    def __init__(self, args_str=None):
        self._args = None
        if not args_str:
            args_str = ' '.join(sys.argv[1:])
        self._parse_args(args_str)
        if self._args.peer_list:
            peer_list = self._args.peer_list.split(',')
        else:
            peer_list = None
        if self._args.router_asn and not self._args.oper:
            self._vnc_lib = VncApiAdmin(
            self._args.use_admin_api,
            self._args.admin_user, self._args.admin_password,
            self._args.admin_tenant_name,
            self._args.api_server_ip,
            self._args.api_server_port, '/',
            api_server_use_ssl=self._args.api_server_use_ssl)

            # Update global system config also with this ASN
            gsc_obj = self._vnc_lib.global_system_config_read(
                  fq_name=['default-global-system-config'])
            gsc_obj.set_autonomous_system(self._args.router_asn)
            if self._args.ibgp_auto_mesh is not None:
                gsc_obj.set_ibgp_auto_mesh(self._args.ibgp_auto_mesh)

            if self._args.set_graceful_restart_parameters == True:
                gr_params = GracefulRestartParametersType()
                gr_params.set_restart_time(
                    int(self._args.graceful_restart_time))
                gr_params.set_long_lived_restart_time(
                    int(self._args.long_lived_graceful_restart_time))
                gr_params.set_end_of_rib_timeout(
                    int(self._args.end_of_rib_timeout))
                gr_params.set_enable(self._args.graceful_restart_enable)
                gr_params.set_bgp_helper_enable(
                    self._args.graceful_restart_bgp_helper_enable)
                gr_params.set_xmpp_helper_enable(
                    self._args.graceful_restart_xmpp_helper_enable)
                gsc_obj.set_graceful_restart_parameters(gr_params)
            self._vnc_lib.global_system_config_update(gsc_obj)
            return

        bp_obj = BgpProvisioner(
            self._args.admin_user, self._args.admin_password,
            self._args.admin_tenant_name,
            self._args.api_server_ip, self._args.api_server_port,
            api_server_use_ssl=self._args.api_server_use_ssl,
            use_admin_api=self._args.use_admin_api,
            sub_cluster_name=self._args.sub_cluster_name,
            peer_list=peer_list)
        if self._args.oper == 'add':
            if self._args.sub_cluster_name:
                bp_obj.add_bgp_router('external-control-node',
                                  self._args.host_name,
                                  self._args.host_ip, self._args.router_asn,
                                  self._args.address_families, self._args.md5,
                                  self._args.local_autonomous_system,
                                  self._args.bgp_server_port)
            else:
                bp_obj.add_bgp_router('control-node', self._args.host_name,
                                  self._args.host_ip, self._args.router_asn,
                                  self._args.address_families, self._args.md5,
                                  self._args.local_autonomous_system,
                                  self._args.bgp_server_port)
        elif self._args.oper == 'del':
            bp_obj.del_bgp_router(self._args.host_name)
        else:
            print "Unknown operation %s. Only 'add' and 'del' supported"\
                % (self._args.oper)

    # end __init__

    def gr_time_type(self, value):
        time = int(value)
        if time < 0 or time > 4095:
            raise argparse.ArgumentTypeError("graceful_restart_time %s must be in range (0..4095)" % value)
        return time

    def llgr_time_type(self, value):
        time = int(value)
        if time < 0 or time > 16777215:
            raise argparse.ArgumentTypeError("long_lived_graceful_restart_time %s must be in range (0..16777215)" % value)
        return time

    def _parse_args(self, args_str):
        '''
        Eg. python provision_control.py --host_name a3s30.contrail.juniper.net
                                        --host_ip 10.1.1.1
                                        --router_asn 64512
                                        --ibgp_auto_mesh|--no_ibgp_auto_mesh
                                        --api_server_ip 127.0.0.1
                                        --api_server_port 8082
                                        --api_server_use_ssl False
                                        --oper <add | del>
                                        --md5 <key value>|None(optional)
                                        --bgp_server_port <port>|None(optional)
                                        --local_autonomous_system <ASN value>|None(optional)
                                        --graceful_restart_time 300
                                        --long_lived_graceful_restart_time 300
                                        --end_of_rib_timeout 300
                                        --set_graceful_restart_parameters False
                                        --graceful_restart_bgp_helper_enable False
                                        --graceful_restart_xmpp_helper_enable False
                                        --graceful_restart_enable False

        '''

        # Source any specified config/ini file
        # Turn off help, so we print all options in response to -h
        conf_parser = argparse.ArgumentParser(add_help=False)

        conf_parser.add_argument("-c", "--conf_file",
                                 help="Specify config file", metavar="FILE")
        args, remaining_argv = conf_parser.parse_known_args(args_str.split())

        defaults = {
            'router_asn': '64512',
            'bgp_server_port': 179,
            'local_autonomous_system': None,
            'ibgp_auto_mesh': None,
            'api_server_ip': '127.0.0.1',
            'api_server_port': '8082',
            'api_server_use_ssl': False,
            'oper': None,
            'admin_user': None,
            'admin_password': None,
            'admin_tenant_name': None,
            'md5' : None,
            'graceful_restart_time': 300,
            'long_lived_graceful_restart_time': 300,
            'end_of_rib_timeout': 300,
            'graceful_restart_bgp_helper_enable': False,
            'graceful_restart_xmpp_helper_enable': False,
            'graceful_restart_enable': False,
            'set_graceful_restart_parameters': False,
            'sub_cluster_name': None,
            'peer_list':None,
        }

        if args.conf_file:
            config = ConfigParser.SafeConfigParser()
            config.read([args.conf_file])
            defaults.update(dict(config.items("DEFAULTS")))

        # Override with CLI options
        # Don't surpress add_help here so it will handle -h
        parser = argparse.ArgumentParser(
            # Inherit options from config_parser
            parents=[conf_parser],
            # print script description with -h/--help
            description=__doc__,
            # Don't mess with format of description
            formatter_class=argparse.RawDescriptionHelpFormatter,
        )
        parser.set_defaults(**defaults)

        parser.add_argument(
            "--host_name", help="hostname name of control-node")
        parser.add_argument("--host_ip", help="IP address of control-node")
        parser.add_argument(
            "--router_asn", help="AS Number the control-node is in", required=True)
        parser.add_argument(
            "--bgp_server_port", help="BGP server port number (Default: 179)")
        parser.add_argument(
            "--local_autonomous_system", help="Local autonomous-system number used to peer contrail-control bgp speakers across different geographic locations")
        parser.add_argument(
            "--address_families", help="Address family list",
            choices=["route-target", "inet-vpn", "e-vpn", "erm-vpn", "inet6-vpn"],
            nargs="*", default=[])
        parser.add_argument(
            "--md5", help="Md5 config for the node")
        parser.add_argument(
            "--ibgp_auto_mesh", help="Create iBGP mesh automatically", dest='ibgp_auto_mesh', action='store_true')
        parser.add_argument(
            "--no_ibgp_auto_mesh", help="Don't create iBGP mesh automatically", dest='ibgp_auto_mesh', action='store_false')
        parser.add_argument("--api_server_port", help="Port of api server")
        parser.add_argument("--api_server_use_ssl",
                        help="Use SSL to connect with API server")
        parser.add_argument(
            "--oper",
            help="Provision operation to be done(add or del)")
        parser.add_argument(
            "--admin_user", help="Name of keystone admin user")
        parser.add_argument(
            "--admin_password", help="Password of keystone admin user")
        parser.add_argument(
            "--admin_tenant_name", help="Tenamt name for keystone admin user")
        parser.add_argument(
            "--graceful_restart_time",
            help="Graceful Restart Time in seconds (0..4095)",
            type=self.gr_time_type, default=300,
            required=False)
        parser.add_argument(
            "--long_lived_graceful_restart_time",
            help="Long Lived Graceful Restart Time in seconds (0..16777215)",
            type=self.llgr_time_type, default=300,
            required=False)
        parser.add_argument(
            "--end_of_rib_timeout",
            help="EndOfRib timeout value in seconds (0..4095)",
            type=self.gr_time_type, default=300,
            required=False)
        parser.add_argument("--graceful_restart_bgp_helper_enable",
                            action='store_true',
                            help="Enable helper mode for BGP graceful restart")
        parser.add_argument("--graceful_restart_xmpp_helper_enable",
                            action='store_true',
                            help="Enable helper mode for XMPP graceful restart")
        parser.add_argument("--graceful_restart_enable",
                            action='store_true',
                            help="Enable Graceful Restart")
        parser.add_argument("--set_graceful_restart_parameters",
                            action='store_true',
                            help="Set Graceful Restart Parameters")
        parser.add_argument(
            "--sub_cluster_name", help="sub cluster to associate to",
            required=False)
        parser.add_argument(
            "--peer_list", help="list of control node names to peer",
            required=False)
        group = parser.add_mutually_exclusive_group(required=True)
        group.add_argument(
            "--api_server_ip", help="IP address of api server",
            nargs='+', type=str)
        group.add_argument("--use_admin_api",
                            default=False,
                            help = "Connect to local api-server on admin port",
                            action="store_true")

        self._args = parser.parse_args(remaining_argv)