-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
59 changed files
with
1,072 additions
and
260 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,5 +2,7 @@ | |
build/ | ||
dist/ | ||
*.egg-info/ | ||
app/*.pyc | ||
tests/*.pyc | ||
tests/__pycache__/ | ||
.idea |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import os | ||
import tempfile | ||
|
||
from .vars import g_debug | ||
from .log import log_crit, log_err | ||
from .util import run_command | ||
|
||
|
||
class ConfigMgr(object): | ||
""" The class represents frr configuration """ | ||
def __init__(self): | ||
self.current_config = None | ||
|
||
def reset(self): | ||
""" Reset stored config """ | ||
self.current_config = None | ||
|
||
def update(self): | ||
""" Read current config from FRR """ | ||
self.current_config = None | ||
ret_code, out, err = run_command(["vtysh", "-c", "show running-config"]) | ||
if ret_code != 0: | ||
log_crit("can't update running config: rc=%d out='%s' err='%s'" % (ret_code, out, err)) | ||
return | ||
self.current_config = self.to_canonical(out) | ||
|
||
def push(self, cmd): | ||
""" | ||
Push new changes to FRR | ||
:param cmd: configuration change for FRR. Type: String | ||
:return: True if change was applied successfully, False otherwise | ||
""" | ||
return self.write(cmd) | ||
|
||
def write(self, cmd): | ||
""" | ||
Write configuration change to FRR. | ||
:param cmd: new configuration to write into FRR. Type: String | ||
:return: True if change was applied successfully, False otherwise | ||
""" | ||
fd, tmp_filename = tempfile.mkstemp(dir='/tmp') | ||
os.close(fd) | ||
with open(tmp_filename, 'w') as fp: | ||
fp.write("%s\n" % cmd) | ||
command = ["vtysh", "-f", tmp_filename] | ||
ret_code, out, err = run_command(command) | ||
if not g_debug: | ||
os.remove(tmp_filename) | ||
if ret_code != 0: | ||
err_tuple = str(cmd), ret_code, out, err | ||
log_err("ConfigMgr::push(): can't push configuration '%s', rc='%d', stdout='%s', stderr='%s'" % err_tuple) | ||
if ret_code == 0: | ||
self.current_config = None # invalidate config | ||
return ret_code == 0 | ||
|
||
@staticmethod | ||
def to_canonical(raw_config): | ||
""" | ||
Convert FRR config into canonical format | ||
:param raw_config: config in frr format | ||
:return: frr config in canonical format | ||
""" | ||
parsed_config = [] | ||
lines_with_comments = raw_config.split("\n") | ||
lines = [line for line in lines_with_comments | ||
if not line.strip().startswith('!') and line.strip() != ''] | ||
if len(lines) == 0: | ||
return [] | ||
cur_path = [lines[0]] | ||
cur_offset = ConfigMgr.count_spaces(lines[0]) | ||
for line in lines: | ||
n_spaces = ConfigMgr.count_spaces(line) | ||
s_line = line.strip() | ||
# assert(n_spaces == cur_offset or (n_spaces + 1) == cur_offset or (n_spaces - 1) == cur_offset) | ||
if n_spaces == cur_offset: | ||
cur_path[-1] = s_line | ||
elif n_spaces > cur_offset: | ||
cur_path.append(s_line) | ||
elif n_spaces < cur_offset: | ||
cur_path = cur_path[:-2] | ||
cur_path.append(s_line) | ||
parsed_config.append(cur_path[:]) | ||
cur_offset = n_spaces | ||
return parsed_config | ||
|
||
@staticmethod | ||
def count_spaces(line): | ||
""" Count leading spaces in the line """ | ||
return len(line) - len(line.lstrip()) | ||
|
||
@staticmethod | ||
def from_canonical(canonical_config): | ||
""" | ||
Convert config from canonical format into FRR raw format | ||
:param canonical_config: config in a canonical format | ||
:return: config in the FRR raw format | ||
""" | ||
out = "" | ||
for lines in canonical_config: | ||
spaces = len(lines) - 1 | ||
out += " " * spaces + lines[-1] + "\n" | ||
|
||
return out |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
import syslog | ||
|
||
from .vars import g_debug | ||
|
||
def log_debug(msg): | ||
""" Send a message msg to the syslog as DEBUG """ | ||
if g_debug: | ||
syslog.syslog(syslog.LOG_DEBUG, msg) | ||
|
||
|
||
def log_notice(msg): | ||
""" Send a message msg to the syslog as NOTICE """ | ||
syslog.syslog(syslog.LOG_NOTICE, msg) | ||
|
||
|
||
def log_info(msg): | ||
""" Send a message msg to the syslog as INFO """ | ||
syslog.syslog(syslog.LOG_INFO, msg) | ||
|
||
|
||
def log_warn(msg): | ||
""" Send a message msg to the syslog as WARNING """ | ||
syslog.syslog(syslog.LOG_WARNING, msg) | ||
|
||
|
||
def log_err(msg): | ||
""" Send a message msg to the syslog as ERR """ | ||
syslog.syslog(syslog.LOG_ERR, msg) | ||
|
||
|
||
def log_crit(msg): | ||
""" Send a message msg to the syslog as CRIT """ | ||
syslog.syslog(syslog.LOG_CRIT, msg) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import subprocess | ||
|
||
from .log import log_debug, log_err | ||
|
||
|
||
def run_command(command, shell=False, hide_errors=False): | ||
""" | ||
Run a linux command. The command is defined as a list. See subprocess.Popen documentation on format | ||
:param command: command to execute. Type: List of strings | ||
:param shell: execute the command through shell when True. Type: Boolean | ||
:param hide_errors: don't report errors to syslog when True. Type: Boolean | ||
:return: Tuple: integer exit code from the command, stdout as a string, stderr as a string | ||
""" | ||
log_debug("execute command '%s'." % str(command)) | ||
p = subprocess.Popen(command, shell=shell, stdout=subprocess.PIPE, stderr=subprocess.PIPE) | ||
stdout, stderr = p.communicate() | ||
if p.returncode != 0: | ||
if not hide_errors: | ||
print_tuple = p.returncode, str(command), stdout, stderr | ||
log_err("command execution returned %d. Command: '%s', stdout: '%s', stderr: '%s'" % print_tuple) | ||
|
||
return p.returncode, stdout, stderr |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
g_debug = False |
Oops, something went wrong.