def __init__(self, stdin=sys.stdin, foreground=True): self.bridge = None # default bridge self.ipt = IPtables() if foreground: output('EasyOVS %s, type help for information\n' % VERSION) self.prompt = color_str(PROMPT_KW, 'g') self.stdin = stdin self.in_poller = poll() self.in_poller.register(stdin) Cmd.__init__(self) output("***\n Welcome to EasyOVS," "type help to see available commands.\n***\n") info('*** Starting CLI:\n') debug("==Loading credentials==\n") debug("auth_url = %s\n" % os.getenv('OS_AUTH_URL') or cfg.CONF.OS.auth_url) debug("username = %s\n" % os.getenv('OS_USERNAME') or cfg.CONF.OS.username) passwd = os.getenv('OS_PASSWORD') or cfg.CONF.OS.password passwd = passwd[:len(passwd) / 4] + "****" + passwd[-len(passwd) / 4:] debug("password = %s\n" % passwd) debug("tenant_name = %s\n" % os.getenv('OS_TENANT_NAME') or cfg.CONF.OS.tenant_name) while True: try: #if self.isatty(): #quietRun( 'stty sane' ) self.cmdloop() break except KeyboardInterrupt: info('\nInterrupt\n')
def _check_compute_node_snat_ns(self, ns_router): """ Check the local router namespace on compute node :param ns_router: :return: list of the fip ns """ if not ns_router: return self.nss.show(ns_router) intfs = NameSpace(ns_router).get_intfs() rfp_ports = [] # list of {'intf':eth0, 'ip':[]} for i in intfs: # check each intf in this ns p = intfs[i]['intf'] if p.startswith('rfp-'): # rfp port in q connect to fpr in fip rfp_ports.append(p) output(b('### Checking rfp port %s\n' % p)) if len(intfs[i]['ip']) < 2: warn(r('Missing ips for port %s\n' % p)) continue else: output( g('Found associated floating ips : %s\n' % ', '.join(intfs[i]['ip'][1:]))) ns_fip = self.nss.get_intf_by_name('fpr-' + intfs[i]['intf'][4:]) if not ns_fip: warn(r('Cannot find fip ns for %s\n' % q)) return self._check_compute_node_fip_ns(intfs[i], ns_fip) self._check_compute_node_nat_table(ns_router, ns_fip) if not rfp_ports: warn(r('Cannot find rfp port in ns %s\n' % ns_router)) elif len(rfp_ports) > 1: warn(r('More than 1 rfp ports in ns %s\n' % ns_router))
def do_help(self, line): """ Describe available CLI commands. """ Cmd.do_help(self, line) if line is "": output(self.helpStr)
def run(self, cmd, forced=False): ''' Run given commands from -m 'xxxx'. Treat this similar with CLI. :param args: :param forced: :return: ''' cmd_split = cmd.split() if cmd_split[0] in CMDS_ONE: # list func = cmd_split[0] getattr(self, 'do_' + func)() elif cmd_split[0] in CMDS_BR: if len(cmd_split) > 2: # e.g., delflow br0 9,10 func, args = cmd_split[0], ' '.join(cmd_split[1:]) debug("run do_%s(%s, %s)\n" % (func, args.replace(',', ' '), forced)) getattr(self, 'do_' + func)(args.replace(',', ' '), forced) else: # e.g., delbr br0 func, args = cmd_split[0], cmd_split[1] getattr(self, 'do_' + func)(args) elif cmd_split[0] in CMDS_OTHER: # e.g., ipt vm 10.0.0.1, 10.0.0.2 func, args = cmd_split[0], ' '.join(cmd_split[1:]) getattr(self, 'do_' + func)(args) else: output('Wrong command format is given\n')
def _network_check_processes(self): """ Check related configuration files :return: True if no warning """ output(b('>>> Checking processes...\n')) warns = False cmd = "ps aux|grep neutron|grep python" result, err = \ Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True).communicate() if err: return [] for p in [ 'neutron-server', 'neutron-dhcp-agent', 'neutron-metadata-agent', 'neutron-openvswitch-agent', 'neutron-l3-agent', #'neutron-ns-metadata-proxy', ]: if p not in result: warn(r('%s service is not running\n' % p)) warns = True if not warns: output(g('<<< Checking processes passed\n')) return True else: warn(r('<<< Checking processes has warnings\n')) return False
def _network_check_router_ns(self, ns_router): """ Check the local router namespace on compute node :param ns_router: :return: list of the fip ns """ output(b('### Checking router ns = %s\n' % ns_router)) if not ns_router: return False intfs = NameSpace(ns_router).get_intfs() r_ports = [] # list of {'intf':eth0, 'ip':[]} for i in intfs: # check each intf in this ns p = intfs[i]['intf'] if p == 'lo': # ignore the lo port continue elif not p.startswith('qr-'): # no router port? warn(r('Invalid port %s in %s\n' % (p, ns_router))) return False else: output(b('### Checking port %s\n' % p)) r_ports.append(p) if not intfs[i]['ip']: warn(r('No ip with port %s in %s\n' % (p, ns_router))) return False else: for ip_m in intfs[i]['ip']: ip, mask = ip_m.split('/') if ipStrToNum(ip) != networkMask(ip_m) + 1: warn(r('IP %s is not gw on port %s\n' % (ip_m, ns_router))) return False if not r_ports: warn(r('Cannot find router port in ns %s\n' % ns_router)) return False return True
def wrapper(self, *arg): if not self.exists(): output('The bridge does not exist.\n \ Please check available bridges using list\n') return None else: return func(self, *arg)
def do_help(self, line): """ Describe available CLI commands. """ Cmd.do_help(self, line) if line is '': output(self.helpStr)
def __init__(self, stdin=sys.stdin, foreground=True): self.bridge = None # default bridge self.ipt = None self.nss = None self.dvr = None if foreground: self.prompt = color_str(PROMPT_KW, 'g') self.stdin = stdin self.in_poller = poll() self.in_poller.register(stdin) Cmd.__init__(self) output("***\n Welcome to EasyOVS %s, " "type help to see available cmds.\n***\n" % VERSION) info('*** Starting CLI:\n') debug("==Loading credentials==\n") debug("auth_url = %s\n" % os.getenv('OS_AUTH_URL') or cfg.CONF.OS.auth_url) debug("username = %s\n" % os.getenv('OS_USERNAME') or cfg.CONF.OS.username) passwd = os.getenv('OS_PASSWORD') or cfg.CONF.OS.password passwd = passwd[:len(passwd)/4] + "****" + passwd[-len(passwd)/4:] debug("password = %s\n" % passwd) debug("tenant_name = %s\n" % os.getenv('OS_TENANT_NAME') or cfg.CONF.OS.tenant_name) while True: try: #if self.isatty(): #quietRun( 'stty sane' ) self.cmdloop() break except KeyboardInterrupt: info('\nInterrupt\n')
def _check_compute_node_snat_ns(self, ns_router): """ Check the local router namespace on compute node :param ns_router: :return: list of the fip ns """ if not ns_router: return self.nss.show(ns_router) intfs = NameSpace(ns_router).get_intfs() rfp_ports = [] # list of {'intf':eth0, 'ip':[]} for i in intfs: # check each intf in this ns p = intfs[i]['intf'] if p.startswith('rfp-'): # rfp port in q connect to fpr in fip rfp_ports.append(p) output(b('### Checking rfp port %s\n' % p)) if len(intfs[i]['ip']) < 2: warn(r('Missing ips for port %s\n' % p)) continue else: output(g('Found associated floating ips : %s\n' % ', '.join(intfs[i]['ip'][1:]))) ns_fip = self.nss.get_intf_by_name('fpr-'+intfs[i]['intf'][4:]) if not ns_fip: warn(r('Cannot find fip ns for %s\n' % q)) return self._check_compute_node_fip_ns(intfs[i], ns_fip) self._check_compute_node_nat_table(ns_router, ns_fip) if not rfp_ports: warn(r('Cannot find rfp port in ns %s\n' % ns_router)) elif len(rfp_ports) > 1: warn(r('More than 1 rfp ports in ns %s\n' % ns_router))
def do_get(self, _arg): """ Get current default bridge. """ if self.bridge: output("Current default bridge is %s\n" % self.bridge) else: output("Default bridge is not set yet.\nPlease try <bridge> set.\n")
def wrapper(self, *arg): if not self.exists(): output( 'The bridge does not exist.\n \ Please check available bridges using list\n') return None else: return func(self, *arg)
def fmt_output(self): if self.packet > 0: result = color_str('g',self._format_str_ % (self.id, self.table, self.packet, self.priority, compress_mac_str(self.match), self.actions)) else: result = self._format_str_ % (self.id, self.table, self.packet, self.priority, compress_mac_str(self.match), self.actions) output(result)
def do_get(self, _arg): """ Get current default bridge. """ if self.bridge: output('Current default bridge is %s\n' % self.bridge) else: output('Default bridge is not set yet.\nPlease try <bridge> set.\n')
def _compute_check_nat_rules(self, qr_intfs, rfp_intfs, nat, ns_fip): """ Check three chains rules match with each other :param nat: the nat table :param ns_fip: :return: True or False """ c_name = 'neutron-l3-agent-PREROUTING' rule = {'in': 'qr-+', 'source': '*', 'out': '*', 'destination': '169.254.169.254', 'target': 'REDIRECT', 'prot': 'tcp', 'flags': 'tcp dpt:80 redir ports 9697'} if not self._check_chain_has_rule(nat, c_name, rule): return False ips_qr = [item for sublist in map(lambda x: x['ip'], qr_intfs) for item in sublist] ips_rfp = [item for sublist in map(lambda x: x['ip'], rfp_intfs) for item in sublist] for intf in rfp_intfs: c_name = 'neutron-l3-agent-PREROUTING' for ip_m in intf['ip'][1:]: # check each floating ip dip = ip_m.split('/')[0] # real floating ip for destination if not ipInNetworks(dip, ips_rfp): warn(r('dip %s not in rfp ports %s\n' % (dip, ips_rfp))) return False rule = nat.get_rule(c_name, {'destination': dip}) sip = rule.get_flags().split(':')[1] if not ipInNetworks(sip, ips_qr): warn(r('sip %s not in qr port %s\n' % (sip, ips_qr))) return False rule_expect = {'in': '*', 'source': '*', 'out': '*', 'destination': dip, 'target': 'DNAT', 'prot': '*', 'flags': 'to:'+sip} if not rule.is_match(rule_expect): warn(r('rule not matched in %s\n' % (c_name))) return False if not self._check_chain_has_rule(nat, 'neutron-l3-agent-OUTPUT', rule_expect): return False else: output(g('DNAT for incoming: %s --> %s passed\n' % (dip, sip))) rule_expect = {'in': '*', 'source': sip, 'out': '*', 'destination': '*', 'target': 'SNAT', 'prot': '*', 'flags': 'to:'+dip} if not self._check_chain_has_rule( nat, 'neutron-l3-agent-float-snat', rule_expect): return False else: output(g('SNAT for outgoing: %s --> %s passed\n' % (sip, dip))) return True
def show(self): ''' Print all rules in this chain :return: ''' output( color_str("chain=%s, policy=%s\n" % (self.name, self.policy), 'b')) for r in self.rules: r.show()
def show(self): ''' Print all rules in this chain :return: ''' output(color_str("chain=%s, policy=%s\n" % (self.name, self.policy), 'b')) for r in self.rules: r.show()
def show(self, chain=None): ''' Get rules from this table :param chain: :return: ''' output(color_str("===table=%s===\n" % self.name, 'r')) for cn in self.chains: if not chain or cn.upper() == chain.upper(): self.chains[cn].show()
def show_routes(self): """ """ run_cmd = '%s exec %s route -en' % (self.ns_cmd, self.id) result, err = Popen(run_cmd, stdout=PIPE, stderr=PIPE, shell=True).communicate() if err: error("Failed to run %s, err=%s\n" % (run_cmd, err)) else: output(result)
def check(self, _node=None): node = _node or self.node if node in 'compute': output(b('# Checking DVR on compute node\n')) self._check_compute_node() elif node in 'network': output(b('# Checking DVR on network node\n')) self._check_network_node() else: error('Unknown node type=%s, compute or network?\n' % node)
def br_delbr(bridge_name): """ Delete a bridge. """ br = ovs_lib.BaseOVS() br.delete_bridge(bridge_name) if not br_exists(bridge_name): output("bridge %s was deleted\n" % bridge_name) else: error("Error when deleting bridge %s\n" % bridge_name)
def br_delbr(name): """ Delete a bridge. """ cmd = "ovs-vsctl --if-exists del-br %s" % name result, err = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True).communicate() if err: error("Error when deleting bridge %s\n" % name) else: output("bridge %s was deleted\n" % name)
def br_addbr(name): """ Create a new bridge. """ cmd = "ovs-vsctl --may-exist add-br %s" % name result, err = Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True).communicate() if err: error("Error when adding new bridge %s\n" % name) else: output("bridge %s was created\n" % name)
def br_addbr(bridge_name): """ Create a new bridge. """ br = ovs_lib.BaseOVS() br.add_bridge(bridge_name) if br_exists(bridge_name): output("bridge %s was created\n" % bridge_name) else: error("Error when adding new bridge %s\n" % bridge_name)
def do_show(self, arg): """ Show port details of a bridge, with neutron information. """ if arg: br_show(arg) elif self.bridge: br_show(self.bridge) else: output("Please give a valid bridge.\n") return
def find(self, pattern): """ Find a namespace which have the pattern :param pattern: pattern to search :return: N/A """ ns = self._search_ns(pattern) if not ns: output('There is no ns matched.\n') else: self.show(ns)
def br_addbr(name): """ Create a new bridge. """ cmd = "ovs-vsctl --may-exist add-br %s" % name result, err = \ Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True).communicate() if err: error("Error when adding new bridge %s\n" % name) else: output("bridge %s was created\n" % name)
def br_delbr(name): """ Delete a bridge. """ cmd = "ovs-vsctl --if-exists del-br %s" % name result, err = \ Popen(cmd, stdout=PIPE, stderr=PIPE, shell=True).communicate() if err: error("Error when deleting bridge %s\n" % name) else: output("bridge %s was deleted\n" % name)
def fmt_output(self): if self.packet > 0: result = color_str( 'g', self._format_str_ % (self.id, self.table, self.packet, self.priority, compress_mac_str(self.match), self.actions)) else: result = self._format_str_ % ( self.id, self.table, self.packet, self.priority, compress_mac_str(self.match), self.actions) output(result)
def _query_port_rules(self, br_port): """ Return the dict of the related security rules on a given port. { 'NAME':[iptables rules], } will load rules first """ results = {} if br_port.startswith('qvo'): # vm port debug('qvo should be vm port\n') #self._load(table='filter') chain_tag = br_port[3:13] i_rules = self._get_rules(chain='neutron-openvswi-i' + chain_tag) out = self._get_rules(chain='neutron-openvswi-o' + chain_tag) filter = self._get_rules(chain='neutron-openvswi-s' + chain_tag) if i_rules: results['IN'] = i_rules if out: results['OUT'] = out if filter: results['SRC_FILTER'] = filter else: # maybe at Network Node debug('Should be network function port\n') ns = self.nss.get_intf_by_name(br_port) if not ns: warn("port %s not in namespaces\n" % br_port) else: output('ns=%s\n' % ns) self._load(table='nat', ns=ns) if br_port.startswith('tap'): # dhcp return None elif br_port.startswith('qr-') or br_port.startswith('qg-'): pre = self._get_rules(table='nat', chain='neutron-l3-agent-PREROUTING') out = self._get_rules(table='nat', chain='neutron-l3-agent-OUTPUT') float_snat = self._get_rules(table='nat', chain='neutron-l3-agent-float-snat') snat = self._get_rules(table='nat', chain='neutron-l3-agent-snat') if pre: results['PRE'] = pre if out: results['OUT'] = out if float_snat: results['FLOAT'] = float_snat if snat: results['SNAT'] = snat return results
def do_delbr(self, arg, forced=False): """ delbr br1, br2 Delete a bridge """ brs = arg.replace(',', ' ').split() if len(brs) < 1: output('Not enough parameters are given, use like ') output('delbr br1,br2\n') return for br in brs: br_delbr(br)
def fmt_show_rules(rule_list): """ Possible columns: num pkts bytes target prot opt in out source destination other """ for r in rule_list: if r['target'] is not 'DROP': if r['source'] == '0.0.0.0/0': r['source'] = 'all' if r['destination'] == '0.0.0.0/0': r['destination'] = 'all' output(_format_str_iptables_rule_ % (r['pkts'], r['source'], r['destination'], r['prot'], r['other']))
def do_addbr(self, arg, forced=False): """ addbr br1, br2 create a new bridge with name """ brs = arg.replace(',', ' ').split() if len(brs) < 1: output('Not enough parameters are given, use like ') output('addbr br1,br2\n') return for br in brs: br_addbr(br)
def do_dump(self, arg): """ [bridge] dump Dump the flows from a bridge. """ if arg: br_dump(arg) elif self.bridge: br_dump(self.bridge) else: output("Please give a valid bridge.\n") return
def do_addbr(self, arg): """ addbr [bridge] create a new bridge with name """ args = arg.split() if len(args) < 1: output('Not enough parameters are given, use like ') output('addbr br1,br2\n') return brs = ' '.join(args[1:]).replace(',', ' ').split() for br in brs: br_addbr(br)
def add_flow(self, flow): """ Return True or False to add a flow. """ if not flow: return False addflow_cmd = 'ovs-ofctl add-flow %s "%s"' % (self.bridge, flow) error = Popen(addflow_cmd, stdout=PIPE, stderr=PIPE, shell=True).communicate()[1] if error: output(error) return False else: return True
def do_delbr(self, arg): """ delbr [bridge] Delete a bridge """ args = arg.split() if len(args) < 1: output('Not enough parameters are given, use like ') output('del br1,br2\n') return brs = ' '.join(args[1:]).replace(',', ' ').split() for br in brs: br_delbr(br)
def show(self, chain=None): ''' Get rules from this table :param chain: :return: ''' if self.ns: output(b("===ns=%s, table=%s===\n" % (self.ns, self.name))) else: output(b("===table=%s===\n" % self.name)) for cn in self.chains: if not chain or cn.upper() == chain.upper(): self.chains[cn].show()
def _query_port_rules(self, br_port): """ Return the dict of the related security rules on a given port. { 'NAME':[iptables rules], } will load rules first """ results = {} if br_port.startswith('qvo'): # vm port debug('qvo should be vm port\n') #self._load(table='filter') chain_tag = br_port[3:13] i_rules = self._get_rules(chain='neutron-openvswi-i' + chain_tag) out = self._get_rules(chain='neutron-openvswi-o' + chain_tag) filter = self._get_rules(chain='neutron-openvswi-s' + chain_tag) if i_rules: results['IN'] = i_rules if out: results['OUT'] = out if filter: results['SRC_FILTER'] = filter else: # maybe at Network Node debug('Should be network function port\n') ns = self.nss.get_intf_by_name(br_port) if not ns: warn("port %s not in namespaces\n" % br_port) else: output('ns=%s\n' % ns) self._load(table='nat', ns=ns) if br_port.startswith('tap'): # dhcp return None elif br_port.startswith('qr-') or br_port.startswith('qg-'): pre = self._get_rules(table='nat', chain='neutron-l3-agent-PREROUTING') out = self._get_rules(table='nat', chain='neutron-l3-agent-OUTPUT') float_snat = self._get_rules( table='nat', chain='neutron-l3-agent-float-snat') snat = self._get_rules(table='nat', chain='neutron-l3-agent-snat') if pre: results['PRE'] = pre if out: results['OUT'] = out if float_snat: results['FLOAT'] = float_snat if snat: results['SNAT'] = snat return results
def _check_chain_has_rule(self, table, c_name, rule): """ :param rule: :return: True or False """ output(b('Checking chain rules: %s...' % c_name)) c = table.get_chain(c_name) if not c.has_rule(rule): warn(r("Defined rule not in %s\n" % c_name)) return False else: output(g('Passed\n')) return True
def _check_chain_has_rule(self, table, c_name, rule): """ :param rule: :return: True or False """ output(b('Checking chain rules: %s...' % c_name)) c = table.get_chain(c_name) if not c.has_rule(rule): warn(r("Defined rule %s not in %s\n" % (rule, c_name))) return False else: output(g('Passed\n')) return True
def dump_flows(self): """ Dump out the flows of this bridge :return: """ self.load_flows() debug('br_dump: len flows=%u\n' % len(self.flows)) table = 0 if self.flows: Flow.banner_output() for f in self.flows: if f.table != table: output('\n') table = f.table f.fmt_output()
def add_flow(self, flow): """ Return True or False to add a flow. """ if not flow: return False addflow_cmd = 'ovs-ofctl add-flow %s "%s"' % (self.bridge, flow) err = Popen(addflow_cmd, stdout=PIPE, stderr=PIPE, shell=True).communicate()[1] if err: output(err) error("Error when adding new flow <%s> to bridge %s\n" % (flow, self.bridge)) return False else: return True
def _check_chain_rule_num(self, table, c_name, num): """ Check if the chain has given number of rules. :param table: :param c_name: :param num: :return: """ output(b('Checking chain rule number: %s...' % c_name)) c = table.get_chain(c_name) if len(c.get_rules()) != num: warn(r("Wrong rule number in chain %s\n" % c_name)) return False else: output(g('Passed\n')) return True
def _check_compute_node(self): """ Check the qrouter-*** fip-*** spaces in the compute node. :return: """ checked_ns = [] for port in self.br_int.get_ports(): if port.startswith('qr-'): # qrouter port output(b('## Checking router port = %s\n' % port)) nsrouter = self.nss.get_intf_by_name(port) if nsrouter in checked_ns: output(g('Checking passed already\n')) continue else: checked_ns.append(nsrouter) # the names of the ns checked self._check_compute_node_snat_ns(nsrouter) pass pass
def br_list(): """ List available bridges. """ bridges = get_bridges() if not bridges: output('None bridge exists.\n') return br_info = '' for br in sorted(bridges.keys()): br_info += "%s\n" % br if bridges[br]['Port']: br_info += " Port:\t\t%s\n" % (' '.join(sorted(bridges[br]['Port'].keys()))) if bridges[br]['Controller']: br_info += " Controller:\t%s\n" % (' '.join(bridges[br]['Controller'])) if bridges[br]['fail_mode']: br_info += " Fail_Mode:\t%s\n" % (bridges[br]['fail_mode']) output(br_info)
def __init__(self, bridge=None, stdin=sys.stdin): self.prompt = color_str('g', PROMPT_KW) self.bridge = bridge self.stdin = stdin self.in_poller = poll() self.in_poller.register(stdin) Cmd.__init__(self) output( "***\n Welcome to EasyOVS, type help to see available commands.\n***\n" ) info('*** Starting CLI:\n') while True: try: #if self.isatty(): #quietRun( 'stty sane' ) self.cmdloop() break except KeyboardInterrupt: info('\nInterrupt\n')
def do_delflow(self, arg): """ [bridge] delflow flow_id Del a flow from a bridge. """ args = arg.split() if len(args) >= 2: flow_ids = ' '.join(args[1:]).replace(',', ' ').split() if not br_delflow(args[0], flow_ids): output('Del flow#%s from %s failed.\n' % (' '.join(flow_ids), args[0])) else: output('Del flow#%s from %s done.\n' % (','.join(flow_ids), args[0])) elif len(args) == 1 and self.bridge: if not br_delflow(self.bridge, arg): output('Del flow#%s from %s failed.\n' % (arg, self.bridge)) else: output('Del flow#%s from %s done.\n' % (arg, self.bridge)) else: output("Please use [bridge] delflow flow_id.\n")