Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[GCU] Implementing DryRun by printing patch-sorter steps/imitating config_db #1973

Merged
merged 6 commits into from
Dec 17, 2021
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions config/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -1164,6 +1164,10 @@ def load(filename, yes):
log.log_info("'load' executing...")
clicommon.run_command(command, display_cmd=True)

def print_dry_run_message(dry_run):
if dry_run:
click.secho("** DRY RUN EXECUTION **.", fg="yellow", underline=True)

@config.command('apply-patch')
@click.argument('patch-file-path', type=str, required=True)
@click.option('-f', '--format', type=click.Choice([e.name for e in ConfigFormat]),
Expand All @@ -1182,6 +1186,8 @@ def apply_patch(ctx, patch_file_path, format, dry_run, ignore_non_yang_tables, i

<patch-file-path>: Path to the patch file on the file-system."""
try:
print_dry_run_message(dry_run)

with open(patch_file_path, 'r') as fh:
text = fh.read()
patch_as_json = json.loads(text)
Expand Down Expand Up @@ -1214,6 +1220,8 @@ def replace(ctx, target_file_path, format, dry_run, ignore_non_yang_tables, igno

<target-file-path>: Path to the target file on the file-system."""
try:
print_dry_run_message(dry_run)

with open(target_file_path, 'r') as fh:
target_config_as_text = fh.read()
target_config = json.loads(target_config_as_text)
Expand Down Expand Up @@ -1241,6 +1249,8 @@ def rollback(ctx, checkpoint_name, dry_run, ignore_non_yang_tables, ignore_path,

<checkpoint-name>: The checkpoint name, use `config list-checkpoints` command to see available checkpoints."""
try:
print_dry_run_message(dry_run)

GenericUpdater().rollback(checkpoint_name, verbose, dry_run, ignore_non_yang_tables, ignore_path)

click.secho("Config rolled back successfully.", fg="cyan", underline=True)
Expand Down
14 changes: 12 additions & 2 deletions generic_config_updater/change_applier.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import tempfile
from collections import defaultdict
from swsscommon.swsscommon import ConfigDBConnector
from .gu_common import genericUpdaterLogging
from .gu_common import genericUpdaterLogging, DryRunConfigWrapper

SCRIPT_DIR = os.path.dirname(os.path.realpath(__file__))
UPDATER_CONF_FILE = f"{SCRIPT_DIR}/generic_config_updater.conf.json"
Expand Down Expand Up @@ -59,7 +59,12 @@ class ChangeApplier:

updater_conf = None

def __init__(self):
def __init__(self, config_wrapper):
self.config_wrapper = config_wrapper
if type(self.config_wrapper) is DryRunConfigWrapper:
# No need to init the rest of the parameters
return
ghooo marked this conversation as resolved.
Show resolved Hide resolved

self.config_db = get_config_db()
if (not ChangeApplier.updater_conf) and os.path.exists(UPDATER_CONF_FILE):
with open(UPDATER_CONF_FILE, "r") as s:
Expand Down Expand Up @@ -121,6 +126,11 @@ def _report_mismatch(self, run_data, upd_data):


def apply(self, change):
# TODO: DryRun to also include service validation.
if type(self.config_wrapper) is DryRunConfigWrapper:
self.config_wrapper.apply_change_to_config_db(change)
return

run_data = self._get_running_config()
upd_data = prune_empty_table(change.apply(copy.deepcopy(run_data)))
upd_keys = defaultdict(dict)
Expand Down
2 changes: 1 addition & 1 deletion generic_config_updater/generic_updater.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ def __init__(self,
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 StrictPatchSorter(self.config_wrapper, self.patch_wrapper)
self.changeapplier = changeapplier if changeapplier is not None else ChangeApplier()
self.changeapplier = changeapplier if changeapplier is not None else ChangeApplier(self.config_wrapper)

def apply(self, patch):
self.logger.log_notice("Patch application starting.")
Expand Down
14 changes: 12 additions & 2 deletions generic_config_updater/gu_common.py
Original file line number Diff line number Diff line change
Expand Up @@ -152,9 +152,19 @@ def remove_empty_tables(self, config):
return config_with_non_empty_tables

class DryRunConfigWrapper(ConfigWrapper):
# TODO: implement DryRunConfigWrapper
# This class will simulate all read/write operations to ConfigDB on a virtual storage unit.
pass
def __init__(self, yang_dir = YANG_DIR):
self.yang_dir = YANG_DIR
ghooo marked this conversation as resolved.
Show resolved Hide resolved
super().__init__(yang_dir)
self.logger = genericUpdaterLogging.get_logger(title="** DryRun", print_all_to_console=True)
self.imitated_config_db = super().get_config_db_as_json()

def apply_change_to_config_db(self, change):
self.logger.log_notice(f"Would apply {change}")
self.imitated_config_db = change.apply(self.imitated_config_db)

def get_config_db_as_json(self):
return self.imitated_config_db

class PatchWrapper:
def __init__(self, config_wrapper=None):
Expand Down