Skip to content

Commit

Permalink
[generic_config_updater] Logging (#1864)
Browse files Browse the repository at this point in the history
#### What I did
Add some logs to generic_updater

#### How I did it

#### How to verify it

#### Previous command output (if the output of a command-line utility has changed)

#### New command output (if the output of a command-line utility has changed)
Empty patch
```
admin@vlab-01:~$ sudo config apply-patch empty.json-patch 
Patch Applier: Patch application starting.
Patch Applier: Patch: []
Patch Applier: Validating patch is not making changes to tables without YANG models.
Patch Applier: Getting current config db.
Patch Applier: Simulating the target full config after applying the patch.
Patch Applier: Validating target config according to YANG models.
... [logs from sonic-yang-mgmt framework]
Patch Applier: Sorting patch updates.
Patch Applier: The patch was sorted into 0 changes.
Patch Applier: Applying changes in order.
Patch Applier: Verifying patch updates are reflected on ConfigDB.
Patch Applier: Patch application completed.
Patch applied successfully.
admin@vlab-01:~$ 
```

Single change patch
```
admin@vlab-01:~$ sudo config apply-patch dhcp_add.json-patch 
Patch Applier: Patch application starting.
Patch Applier: Patch: [{"op": "add", "path": "/VLAN/Vlan1000/dhcp_servers/4", "value": "192.0.0.5"}]
Patch Applier: Validating patch is not making changes to tables without YANG models.
Patch Applier: Getting current config db.
Patch Applier: Simulating the target full config after applying the patch.
Patch Applier: Validating target config according to YANG models.
... [logs from sonic-yang-mgmt framework]
Patch Applier: The patch was sorted into 1 change:
Patch Applier:   * [{"op": "add", "path": "/VLAN/Vlan1000/dhcp_servers/4", "value": "192.0.0.5"}]
Patch Applier: Applying changes in order.
Failed to apply patch
Usage: config apply-patch [OPTIONS] PATCH_FILE_PATH
Try "config apply-patch -h" for help.

Error: ChangeApplier.apply(change) is not implemented yet
admin@vlab-01:~$ 
```

Multi change patch:
```
admin@vlab-01:~$ sudo config apply-patch update_lanes.json-patch 
Patch Applier: Patch application starting.
Patch Applier: Patch: [{"op": "replace", "path": "/PORT/Ethernet100/lanes", "value": "121,122,123"}]
Patch Applier: Validating patch is not making changes to tables without YANG models.
Patch Applier: Getting current config db.
Patch Applier: Simulating the target full config after applying the patch.
Patch Applier: Validating target config according to YANG models.
... [logs from sonic-yang-mgmt framework]
Patch Applier: Sorting patch updates.
... [logs from sonic-yang-mgmt framework]
Patch Applier: The patch was sorted into 2 changes:
Patch Applier:   * [{"op": "remove", "path": "/PORT/Ethernet100"}]
Patch Applier:   * [{"op": "add", "path": "/PORT/Ethernet100", "value": {"alias": "fortyGigE0/100", "description": "fortyGigE0/100", "index": "25", "lanes": "121,122,123", "mtu": "9100", "pfc_asym": "off", "speed": "40000", "tpid": "0x8100"}}]
Patch Applier: Applying changes in order.
Failed to apply patch
Usage: config apply-patch [OPTIONS] PATCH_FILE_PATH
Try "config apply-patch -h" for help.

Error: ChangeApplier.apply(change) is not implemented yet
admin@vlab-01:~$ 
```
  • Loading branch information
ghooo authored Oct 14, 2021
1 parent 25bb184 commit 4d732c6
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 6 deletions.
28 changes: 22 additions & 6 deletions generic_config_updater/generic_updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import os
from enum import Enum
from .gu_common import GenericConfigUpdaterError, ConfigWrapper, \
DryRunConfigWrapper, PatchWrapper
DryRunConfigWrapper, PatchWrapper, genericUpdaterLogging
from .patch_sorter import PatchSorter

CHECKPOINTS_DIR = "/etc/sonic/checkpoints"
Expand Down Expand Up @@ -32,38 +32,58 @@ def __init__(self,
changeapplier=None,
config_wrapper=None,
patch_wrapper=None):
self.logger = genericUpdaterLogging.get_logger(title="Patch Applier")
self.config_wrapper = config_wrapper if config_wrapper is not None else ConfigWrapper()
self.patch_wrapper = patch_wrapper if patch_wrapper is not None else PatchWrapper()
self.patchsorter = patchsorter if patchsorter is not None else PatchSorter(self.config_wrapper, self.patch_wrapper)
self.changeapplier = changeapplier if changeapplier is not None else ChangeApplier()

def apply(self, patch):
print_to_console=True
self.logger.log_notice("Patch application starting.", print_to_console)
self.logger.log_notice(f"Patch: {patch}", print_to_console)

# validate patch is only updating tables with yang models
self.logger.log_notice("Validating patch is not making changes to tables without YANG models.", print_to_console)
if not(self.patch_wrapper.validate_config_db_patch_has_yang_models(patch)):
raise ValueError(f"Given patch is not valid because it has changes to tables without YANG models")

# Get old config
self.logger.log_notice("Getting current config db.", print_to_console)
old_config = self.config_wrapper.get_config_db_as_json()

# Generate target config
self.logger.log_notice("Simulating the target full config after applying the patch.", print_to_console)
target_config = self.patch_wrapper.simulate_patch(patch, old_config)

# Validate target config
self.logger.log_notice("Validating target config according to YANG models.", print_to_console)
if not(self.config_wrapper.validate_config_db_config(target_config)):
raise ValueError(f"Given patch is not valid because it will result in an invalid config")

# Generate list of changes to apply
self.logger.log_notice("Sorting patch updates.", print_to_console)
changes = self.patchsorter.sort(patch)
changes_len = len(changes)
self.logger.log_notice(f"The patch was sorted into {changes_len} " \
f"change{'s' if changes_len != 1 else ''}{':' if changes_len > 0 else '.'}",
print_to_console)
for change in changes:
self.logger.log_notice(f" * {change}", print_to_console)

# Apply changes in order
self.logger.log_notice("Applying changes in order.", print_to_console)
for change in changes:
self.changeapplier.apply(change)

# Validate config updated successfully
self.logger.log_notice("Verifying patch updates are reflected on ConfigDB.", print_to_console)
new_config = self.config_wrapper.get_config_db_as_json()
if not(self.patch_wrapper.verify_same_json(target_config, new_config)):
raise GenericConfigUpdaterError(f"After applying patch to config, there are still some parts not updated")

self.logger.log_notice("Patch application completed.", print_to_console)

class ConfigReplacer:
def __init__(self, patch_applier=None, config_wrapper=None, patch_wrapper=None):
self.patch_applier = patch_applier if patch_applier is not None else PatchApplier()
Expand Down Expand Up @@ -293,11 +313,7 @@ def create_config_rollbacker(self, verbose, dry_run=False):
return config_rollbacker

def init_verbose_logging(self, verbose):
# TODO: implement verbose logging
# Usually logs have levels such as: error, warning, info, debug.
# By default all log levels should show up to the user, except debug.
# By allowing verbose logging, debug msgs will also be shown to the user.
pass
genericUpdaterLogging.set_verbose(verbose)

def get_config_wrapper(self, dry_run):
if dry_run:
Expand Down
25 changes: 25 additions & 0 deletions generic_config_updater/gu_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,11 @@
import yang as ly
import copy
import re
from sonic_py_common import logger
from enum import Enum

YANG_DIR = "/usr/local/yang-models"
SYSLOG_IDENTIFIER = "GenericConfigUpdater"

class GenericConfigUpdaterError(Exception):
pass
Expand Down Expand Up @@ -691,3 +693,26 @@ def _get_model(self, model, name):
return submodel

return None

class TitledLogger(logger.Logger):
def __init__(self, syslog_identifier, title, verbose):
super().__init__(syslog_identifier)
self._title = title
if verbose:
self.set_min_log_priority_debug()

def log(self, priority, msg, also_print_to_console=False):
combined_msg = f"{self._title}: {msg}"
super().log(priority, combined_msg, also_print_to_console)

class GenericUpdaterLogging:
def __init__(self):
self.set_verbose(False)

def set_verbose(self, verbose):
self._verbose = verbose

def get_logger(self, title):
return TitledLogger(SYSLOG_IDENTIFIER, title, self._verbose)

genericUpdaterLogging = GenericUpdaterLogging()

0 comments on commit 4d732c6

Please sign in to comment.