From fb3c0bfdc79a8dfeb40b9c1ebf9025ca1c4a19ed Mon Sep 17 00:00:00 2001 From: trvanduy Date: Tue, 5 Jan 2021 15:00:24 -0800 Subject: [PATCH 1/6] updates main.py to add snmp show commands --- show/main.py | 216 ++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 207 insertions(+), 9 deletions(-) diff --git a/show/main.py b/show/main.py index 16f5d8cec7..efecec3a8d 100755 --- a/show/main.py +++ b/show/main.py @@ -1103,17 +1103,215 @@ def interfaces(interfacename, verbose): # 'snmp' subcommand ("show runningconfiguration snmp") -@runningconfiguration.command() -@click.argument('server', required=False) -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def snmp(server, verbose): - """Show SNMP information""" - cmd = "sudo docker exec snmp cat /etc/snmp/snmpd.conf" +@runningconfiguration.group(invoke_without_command=True) +@clicommon.pass_db +@click.pass_context +def snmp(ctx, db): + """Show SNMP running configuration""" + if ctx.invoked_subcommand is None: + show_run_snmp_global(db.cfgdb) - if server is not None: - cmd += " | grep -i agentAddress" - run_command(cmd, display_cmd=verbose) +# ("show runningconfiguration snmp location") +@snmp.command('location') +@click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, help="Display the output in JSON format") +@clicommon.pass_db +def location(config_db, json_output): + """show SNMP running configuration location""" + config_db = ConfigDBConnector() + config_db.connect() + snmp = config_db.get_table('SNMP') + snmp_header = ["Location"] + snmp_body = [] + if json_output: + try: + if snmp['LOCATION']: + click.echo(snmp['LOCATION']) + except KeyError: + click.echo("SNMP Location not set") + else: + try: + if snmp['LOCATION']: + snmp_location = [snmp['LOCATION']['Location']] + snmp_body.append(snmp_location) + except KeyError: + snmp['LOCATION'] = '' + click.echo(tabulate(snmp_body, snmp_header)) + + +# '("show runningconfiguration snmp contact") +@snmp.command('contact') +@click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, help="Display the output in JSON format") +@clicommon.pass_db +def contact(config_db, json_output): + """show SNMP running configuration contact""" + config_db = ConfigDBConnector() + config_db.connect() + snmp = config_db.get_table('SNMP') + snmp_header = ["Contact", "Contact Email"] + snmp_body = [] + if json_output: + try: + if snmp['CONTACT']: + click.echo(snmp['CONTACT']) + except KeyError: + click.echo("SNMP Contact not set") + else: + try: + if snmp['CONTACT']: + snmp_contact = list(snmp['CONTACT'].keys()) + snmp_contact_email = [snmp['CONTACT'][snmp_contact[0]]] + snmp_body.append([snmp_contact[0], snmp_contact_email[0]]) + except KeyError: + snmp['CONTACT'] = '' + click.echo(tabulate(snmp_body, snmp_header)) + + +# '("show runningconfiguration snmp community") +@snmp.command('community') +@click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, help="Display the output in JSON format") +@clicommon.pass_db +def community(config_db, json_output): + """show SNMP running configuration community""" + config_db = ConfigDBConnector() + config_db.connect() + snmp_comm_header = ["Community String", "Community Type"] + snmp_comm_body = [] + snmp_comm_keys = config_db.get_table('SNMP_COMMUNITY') + snmp_comm_strings = snmp_comm_keys.keys() + if json_output: + try: + if snmp_comm_keys: + click.echo(snmp_comm_keys) + except KeyError: + click.echo("SNMP Community not set") + else: + for line in snmp_comm_strings: + comm_string = line + comm_string_type = snmp_comm_keys[line]['TYPE'] + snmp_comm_body.append([comm_string, comm_string_type]) + click.echo(tabulate(snmp_comm_body, snmp_comm_header)) + + +# ("show runningconfiguration snmp server") +@snmp.command('server') +@click.option('--verbose', is_flag=True, help="Enable verbose output") +@clicommon.pass_db +def users(server, verbose): + """show SNMP running configuration server""" + cmd = "sudo docker exec snmp cat /etc/snmp/snmpd.conf | grep -i agentAddress" + run_command(cmd,display_cmd=verbose) + + +# '("show runningconfiguration snmp user") +@snmp.command('user') +@click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, help="Display the output in JSON format") +@clicommon.pass_db +def users(config_db, json_output): + """show SNMP running configuration user""" + config_db = ConfigDBConnector() + config_db.connect() + snmp_users_keys = config_db.get_table('SNMP_USER') + snmp_users = snmp_users_keys.keys() + snmp_user_header = ['User', "Type", "Auth Type", "Auth Password", "Encryption Type", "Encryption Password"] + snmp_user_body = [] + if json_output: + try: + if snmp_users_keys: + click.echo(snmp_users_keys) + except KeyError: + click.echo("SNMP User not set") + else: + for line in snmp_users: + snmp_user = line + try: + snmp_user_auth_type = snmp_users_keys[line]['SNMP_USER_AUTH_TYPE'] + except KeyError: + snmp_user_auth_type = 'Null' + try: + snmp_user_auth_password = snmp_users_keys[line]['SNMP_USER_AUTH_PASSWORD'] + except KeyError: + snmp_user_auth_password = 'Null' + try: + snmp_user_encryption_type = snmp_users_keys[line]['SNMP_USER_ENCRYPTION_TYPE'] + except KeyError: + snmp_user_encryption_type = 'Null' + try: + snmp_user_encryption_password = snmp_users_keys[line]['SNMP_USER_ENCRYPTION_PASSWORD'] + except KeyError: + snmp_user_encryption_password = 'Null' + try: + snmp_user_type = snmp_users_keys[line]['SNMP_USER_TYPE'] + except KeyError: + snmp_user_type = 'Null' + snmp_user_body.append([snmp_user, snmp_user_type, snmp_user_auth_type, snmp_user_auth_password, snmp_user_encryption_type, snmp_user_encryption_password]) + click.echo(tabulate(snmp_user_body, snmp_user_header)) + + +# ("show runningconfiguration snmp") +def show_run_snmp_global(config_db): + config_db = ConfigDBConnector() + config_db.connect() + snmp_global_table = config_db.get_table('SNMP') + snmp_comm_table = config_db.get_table('SNMP_COMMUNITY') + snmp_users_table = config_db.get_table('SNMP_USER') + snmp_location_header = ["Location"] + snmp_location_body = [] + snmp_contact_header = ["SNMP_CONTACT", "SNMP_CONTACT_EMAIL"] + snmp_contact_body = [] + snmp_comm_header = ["Community String", "Community Type"] + snmp_comm_body = [] + snmp_user_header = ['User', "Type", "Auth Type", "Auth Password", "Encryption Type", "Encryption Password"] + snmp_user_body = [] + try: + if snmp_global_table['LOCATION']: + snmp_location = [snmp_global_table['LOCATION']['Location']] + snmp_location_body.append(snmp_location) + except KeyError: + snmp_global_table['LOCATION'] = '' + click.echo(tabulate(snmp_location_body, snmp_location_header)) + click.echo("\n") + try: + if snmp_global_table['CONTACT']: + snmp_contact = list(snmp_global_table['CONTACT'].keys()) + snmp_contact_email = [snmp_global_table['CONTACT'][snmp_contact[0]]] + snmp_contact_body.append([snmp_contact[0], snmp_contact_email[0]]) + except KeyError: + snmp_global_table['CONTACT'] = '' + click.echo(tabulate(snmp_contact_body, snmp_contact_header)) + click.echo("\n") + snmp_comm_strings = snmp_comm_table.keys() + snmp_users = snmp_users_table.keys() + for line in snmp_comm_strings: + comm_string = line + comm_string_type = snmp_comm_table[line]['TYPE'] + snmp_comm_body.append([comm_string, comm_string_type]) + click.echo(tabulate(snmp_comm_body, snmp_comm_header)) + click.echo("\n") + for line in snmp_users: + snmp_user = line + try: + snmp_user_auth_type = snmp_users_table[line]['SNMP_USER_AUTH_TYPE'] + except KeyError: + snmp_user_auth_type = 'Null' + try: + snmp_user_auth_password = snmp_users_table[line]['SNMP_USER_AUTH_PASSWORD'] + except KeyError: + snmp_user_auth_password = 'Null' + try: + snmp_user_encryption_type = snmp_users_table[line]['SNMP_USER_ENCRYPTION_TYPE'] + except KeyError: + snmp_user_encryption_type = 'Null' + try: + snmp_user_encryption_password = snmp_users_table[line]['SNMP_USER_ENCRYPTION_PASSWORD'] + except KeyError: + snmp_user_encryption_password = 'Null' + try: + snmp_user_type = snmp_users_table[line]['SNMP_USER_TYPE'] + except KeyError: + snmp_user_type = 'Null' + snmp_user_body.append([snmp_user, snmp_user_type, snmp_user_auth_type, snmp_user_auth_password, snmp_user_encryption_type, snmp_user_encryption_password]) + click.echo(tabulate(snmp_user_body, snmp_user_header)) # 'ntp' subcommand ("show runningconfiguration ntp") From aca04cb8b43b2510da4fc34a46b6dfb7e49f8dd0 Mon Sep 17 00:00:00 2001 From: tsvanduyn Date: Fri, 16 Apr 2021 22:20:23 +0000 Subject: [PATCH 2/6] Adding snmp show and config commands plus tests --- config/main.py | 532 ++++++++++++++++++++ show/main.py | 180 ++++--- tests/config_snmp_test.py | 814 +++++++++++++++++++++++++++++++ tests/mock_tables/config_db.json | 166 +++++++ tests/show_snmp_test.py | 296 +++++++++++ 5 files changed, 1897 insertions(+), 91 deletions(-) create mode 100644 tests/config_snmp_test.py create mode 100644 tests/show_snmp_test.py diff --git a/config/main.py b/config/main.py index e5a3cf6d0f..bf0c50c621 100644 --- a/config/main.py +++ b/config/main.py @@ -2064,6 +2064,538 @@ def delete_snmptrap_server(ctx, ver): cmd="systemctl restart snmp" os.system (cmd) + + +# +# 'snmp' group ('config snmp ...') +# +@config.group(cls=clicommon.AbbreviationGroup, name='snmp') +@clicommon.pass_db +def snmp(db): + """SNMP configuration tasks""" + + +@snmp.group(cls=clicommon.AbbreviationGroup) +@clicommon.pass_db +def community(db): + pass + + +def is_valid_community_type(commstr_type): + commstr_types = ['RO', 'RW'] + if commstr_type not in commstr_types: + click.echo("Invalid community type. Must be either RO or RW") + return False + return True + + +def is_valid_user_type(user_type): + user_types = ['noauthnopriv', 'authnopriv', 'priv'] + if user_type not in user_types: + click.echo("Invalid user type. Must be one of these one of these three " + "'noauthnopriv' or 'authnopriv' or 'priv'") + return False + return True + + +def is_valid_auth_type(user_auth_type): + user_auth_types = ['MD5', 'SHA', 'HMAC-SHA-2'] + if user_auth_type not in user_auth_types: + return False + return True + + +def is_valid_encrypt_type(encrypt_type): + encrypt_types = ['DES', 'AES'] + if encrypt_type not in encrypt_types: + click.echo("Invalid user encryption type. Must be one of these two 'DES' or 'AES'") + return False + return True + + +def snmp_community_secret_check(snmp_secret): + excluded_special_symbols = ['@', ":"] + if len(snmp_secret) > 32: + click.echo("SNMP community string length should be not be greater than 32") + click.echo("SNMP community string should not have any of these special " + "symbols {}".format(excluded_special_symbols)) + click.echo("FAILED: SNMP community string length should be not be greater than 32") + return False + if any(char in excluded_special_symbols for char in snmp_secret): + click.echo("SNMP community string length should be not be greater than 32") + click.echo("SNMP community string should not have any of these special " + "symbols {}".format(excluded_special_symbols)) + click.echo("FAILED: SNMP community string should not have any of these " + "special symbols {}".format(excluded_special_symbols)) + return False + return True + + +def snmp_username_check(snmp_username): + excluded_special_symbols = ['@', ":"] + if len(snmp_username) > 32: + click.echo("SNMP user {} length should be not be greater than 32 characters".format(snmp_username)) + click.echo("SNMP community string should not have any of these special " + "symbols {}".format(excluded_special_symbols)) + click.echo("FAILED: SNMP user {} length should not be greater than 32 characters".format(snmp_username)) + return False + if any(char in excluded_special_symbols for char in snmp_username): + click.echo("SNMP user {} length should be not be greater than 32 characters".format(snmp_username)) + click.echo("SNMP community string should not have any of these special " + "symbols {}".format(excluded_special_symbols)) + click.echo("FAILED: SNMP user {} should not have any of these special " + "symbols {}".format(snmp_username, excluded_special_symbols)) + return False + return True + + +def snmp_user_secret_check(snmp_secret): + excluded_special_symbols = ['@', ":"] + if len(snmp_secret) < 8: + click.echo("SNMP user password length should be at least 8 characters") + click.echo("SNMP user password length should be not be greater than 64") + click.echo("SNMP user password should not have any of these special " + "symbols {}".format(excluded_special_symbols)) + click.echo("FAILED: SNMP user password length should be at least 8 characters") + return False + if len(snmp_secret) > 64: + click.echo("SNMP user password length should be at least 8 characters") + click.echo("SNMP user password length should be not be greater than 64") + click.echo("SNMP user password should not have any of these special " + "symbols {}".format(excluded_special_symbols)) + click.echo("FAILED: SNMP user password length should be not be greater than 64") + return False + if any(char in excluded_special_symbols for char in snmp_secret): + click.echo("SNMP user password length should be at least 8 characters") + click.echo("SNMP user password length should be not be greater than 64") + click.echo("SNMP user password should not have any of these special " + "symbols {}".format(excluded_special_symbols)) + click.echo("FAILED: SNMP user password should not have any of these special " + "symbols {}".format(excluded_special_symbols)) + return False + return True + + +@community.command('add') +@click.argument('community', metavar='', required=True) +@click.argument('string_type', metavar='', required=True) +@clicommon.pass_db +def add_community(db, community, string_type): + """ Add snmp community string""" + string_type = string_type.upper() + if not is_valid_community_type(string_type): + click.echo("SNMP type must be RO or RW and not {}".format(string_type)) + sys.exit(1) + if not snmp_community_secret_check(community): + click.echo("Bad community") + sys.exit(2) + snmp_communities = db.cfgdb.get_table("SNMP_COMMUNITY") + if community in snmp_communities: + click.echo("SNMP community {} is already configured".format(community)) + sys.exit(3) + else: + db.cfgdb.set_entry('SNMP_COMMUNITY', community, {'TYPE': string_type}) + click.echo("SNMP community {} added to configuration".format(community)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + db.cfgdb.set_entry('SNMP_COMMUNITY', community, None) + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() + + +@community.command('del') +@click.argument('community', metavar='', required=True) +@clicommon.pass_db +def del_community(db, community): + """ Delete snmp community string""" + snmp_communities = db.cfgdb.get_table("SNMP_COMMUNITY") + if community not in snmp_communities: + click.echo("SNMP community {} is not configured".format(community)) + sys.exit(1) + else: + db.cfgdb.set_entry('SNMP_COMMUNITY', community, None) + click.echo("SNMP community {} removed from configuration".format(community)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() + + +@community.command('replace') +@click.argument('current_community', metavar='', required=True) +@click.argument('new_community', metavar='', required=True) +@clicommon.pass_db +def replace_community(db, current_community, new_community): + """ Replace snmp community string""" + snmp_communities = db.cfgdb.get_table("SNMP_COMMUNITY") + if not current_community in snmp_communities: + click.echo("Current SNMP community {} is not configured".format(current_community)) + sys.exit(1) + if not snmp_community_secret_check(new_community): + click.echo("Bad community") + sys.exit(2) + elif new_community in snmp_communities: + click.echo("New SNMP community {} to replace current SNMP community {} already " + "configured".format(new_community, current_community)) + sys.exit(3) + else: + string_type = snmp_communities[current_community]['TYPE'] + db.cfgdb.set_entry('SNMP_COMMUNITY', new_community, {'TYPE': string_type}) + click.echo("SNMP community {} added to configuration".format(new_community)) + db.cfgdb.set_entry('SNMP_COMMUNITY', current_community, None) + click.echo('SNMP community {} removed from configuration'.format(current_community)) + click.echo('SNMP community {} replace community {}'.format(new_community, current_community)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() + + +@snmp.group(cls=clicommon.AbbreviationGroup) +@clicommon.pass_db +def contact(db): + pass + + +def is_valid_email(email): + return bool(re.search(r"^[\w\.\+\-]+\@[\w]+\.[a-z]{2,3}$", email)) + + +@contact.command('add') +@click.argument('contact', metavar='', required=True) +@click.argument('contact_email', metavar='', required=True) +@clicommon.pass_db +def add_contact(db, contact, contact_email): + """ Add snmp contact name and email """ + snmp = db.cfgdb.get_table("SNMP") + try: + if snmp['CONTACT']: + click.echo("Contact already exists. Use sudo config snmp contact modify instead") + sys.exit(1) + if not is_valid_email(contact_email): + click.echo("Contact email {} is not valid".format(contact_email)) + sys.exit(2) + else: + db.cfgdb.set_entry('SNMP', 'CONTACT', {contact: contact_email}) + click.echo("Contact name {} and contact email {} have been added to " + "configuration".format(contact, contact_email)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() + except KeyError: + if "CONTACT" not in snmp.keys(): + db.cfgdb.set_entry('SNMP', 'CONTACT', {contact: contact_email}) + click.echo("Contact name {} and contact email {} have been added to " + "configuration".format(contact, contact_email)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() + + +@contact.command('del') +@click.argument('contact', metavar='', required=True) +@clicommon.pass_db +def del_contact(db, contact): + """ Delete snmp contact name and email """ + snmp = db.cfgdb.get_table("SNMP") + try: + if not contact in (list(snmp['CONTACT'].keys()))[0]: + click.echo("SNMP contact {} is not configured".format(contact)) + sys.exit(1) + else: + db.cfgdb.set_entry('SNMP', 'CONTACT', None) + click.echo("SNMP contact {} removed from configuration".format(contact)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() + except KeyError: + if "CONTACT" not in snmp.keys(): + click.echo("Contact name {} is not configured".format(contact)) + sys.exit(2) + + +@contact.command('modify') +@click.argument('contact', metavar='', required=True) +@click.argument('contact_email', metavar='', required=True) +@clicommon.pass_db +def modify_contact(db, contact, contact_email): + """ Modify snmp contact""" + snmp = db.cfgdb.get_table("SNMP") + try: + current_snmp_contact_name = (list(snmp['CONTACT'].keys()))[0] + if current_snmp_contact_name == contact: + current_snmp_contact_email = snmp['CONTACT'][contact] + else: + current_snmp_contact_email = '' + if contact == current_snmp_contact_name and contact_email == current_snmp_contact_email: + click.echo("SNMP contact {} {} already exists".format(contact, contact_email)) + sys.exit(1) + elif contact == current_snmp_contact_name and contact_email != current_snmp_contact_email: + db.cfgdb.mod_entry('SNMP', 'CONTACT', {contact: contact_email}) + click.echo("SNMP contact {} email updated to {}".format(contact, contact_email)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() + else: + db.cfgdb.set_entry('SNMP', 'CONTACT', None) + db.cfgdb.set_entry('SNMP', 'CONTACT', {contact: contact_email}) + click.echo("SNMP contact {} and contact email {} updated".format(contact, contact_email)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() + except KeyError: + if "CONTACT" not in snmp.keys(): + click.echo("Contact name {} is not configured".format(contact)) + sys.exit(2) + + +@snmp.group(cls=clicommon.AbbreviationGroup) +@clicommon.pass_db +def location(db): + pass + + +@location.command('add') +@click.argument('location', metavar='', required=True, nargs=-1) +@clicommon.pass_db +def add_location(db, location): + """ Add snmp location""" + if isinstance(location, tuple): + location = " ".join(location) + elif isinstance(location, list): + location = " ".join(location) + snmp = db.cfgdb.get_table("SNMP") + try: + if snmp['LOCATION']: + click.echo("Location already exists") + sys.exit(1) + except KeyError: + if "LOCATION" not in snmp.keys(): + db.cfgdb.set_entry('SNMP', 'LOCATION', {'Location': location}) + click.echo("SNMP Location {} has been added to configuration".format(location)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() + + +@location.command('del') +@click.argument('location', metavar='', required=True, nargs=-1) +@clicommon.pass_db +def delete_location(db, location): + """ Delete snmp location""" + if isinstance(location, tuple): + location = " ".join(location) + elif isinstance(location, list): + location = " ".join(location) + snmp = db.cfgdb.get_table("SNMP") + try: + if location == snmp['LOCATION']['Location']: + db.cfgdb.set_entry('SNMP', 'LOCATION', None) + click.echo("SNMP Location {} removed from configuration".format(location)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() + else: + click.echo("SNMP Location {} does not exist. The location is {}".format(location, snmp['LOCATION']['Location'])) + sys.exit(1) + except KeyError: + if "LOCATION" not in snmp.keys(): + click.echo("SNMP Location {} is not configured".format(location)) + sys.exit(2) + + +@location.command('modify') +@click.argument('location', metavar='', required=True, nargs=-1) +@clicommon.pass_db +def modify_location(db, location): + """ Modify snmp location""" + if isinstance(location, tuple): + location = " ".join(location) + elif isinstance(location, list): + location = " ".join(location) + snmp = db.cfgdb.get_table("SNMP") + try: + snmp_location = snmp['LOCATION']['Location'] + if location in snmp_location: + click.echo("SNMP location {} already exists".format(location)) + sys.exit(1) + else: + db.cfgdb.mod_entry('SNMP', 'LOCATION', {'Location': location}) + click.echo("SNMP location {} modified in configuration".format(location)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() + except KeyError: + click.echo("Cannot modify SNMP Location. You must use 'config snmp location add command '") + sys.exit(2) + + +@snmp.group(cls=clicommon.AbbreviationGroup) +@clicommon.pass_db +def user(db): + pass + + +@user.command('add') +@click.argument('user', metavar='', required=True) +@click.argument('user_type', metavar='', required=True) +@click.argument('user_permission_type', metavar='', required=True) +@click.argument('user_auth_type', metavar='', required=False) +@click.argument('user_auth_password', metavar='', required=False) +@click.argument('user_encrypt_type', metavar='', required=False) +@click.argument('user_encrypt_password', metavar='', required=False) +@clicommon.pass_db +def add_user(db, user, user_type, user_permission_type, user_auth_type, user_auth_password, user_encrypt_type, + user_encrypt_password): + """ Add snmp user""" + click.echo(user) + if not snmp_username_check(user): + click.echo("Bad SNMP user") + sys.exit(1) + user_type = user_type.lower() + if not is_valid_user_type(user_type): + click.echo("User type {} is invalid. Must be noauthnopriv, authnopriv, or priv".format(user_type)) + sys.exit(2) + if user_type == "noauthnopriv": + user_type = "noAuthNoPriv" + elif user_type == "authnopriv": + user_type = "AuthNoPriv" + elif user_type == "priv": + user_type = "Priv" + user_permission_type = user_permission_type.upper() + if not is_valid_community_type(user_permission_type): + click.echo("User permission type {} is invalid. Must be RO or RW".format(user_permission_type)) + sys.exit(3) + if user_type == "noAuthNoPriv": + if user_auth_type: + click.echo("User auth type not used with 'noAuthNoPriv'. Please use 'AuthNoPriv' or 'Priv' instead") + sys.exit(4) + if user_type is not 'noAuthNoPriv': + if not user_auth_type: + click.echo("User auth type is missing. Must be MD5, SHA, or HMAC-SHA-2") + sys.exit(5) + if user_auth_type: + user_auth_type = user_auth_type.upper() + if not is_valid_auth_type(user_auth_type): + click.echo("User auth type {} is invalid. Must be MD5, SHA, or HMAC-SHA-2".format(user_auth_type)) + sys.exit(6) + elif not user_auth_password: + click.echo("User auth password is missing") + sys.exit(7) + elif user_auth_password: + if not snmp_user_secret_check(user_auth_password): + click.echo("Bad user auth password") + sys.exit(8) + if user_type == "AuthNoPriv": + if user_encrypt_type: + click.echo("User encrypt type not used with 'AuthNoPriv'. Please use 'Priv' instead") + sys.exit(9) + elif user_type == "Priv": + if not user_encrypt_type: + click.echo("User encrypt type is missing. Must be DES or AES") + sys.exit(10) + if user_encrypt_type: + user_encrypt_type = user_encrypt_type.upper() + if not is_valid_encrypt_type(user_encrypt_type): + click.echo("User encryption type {} is invalid. Must be DES or AES".format(user_encrypt_type)) + sys.exit(11) + elif not user_encrypt_password: + click.echo("User encrypt password is missing") + sys.exit(12) + elif user_encrypt_password: + if not snmp_user_secret_check(user_encrypt_password): + click.echo("Bad user encrypt password") + sys.exit(13) + snmp_users = db.cfgdb.get_table("SNMP_USER") + if user in snmp_users.keys(): + click.echo("SNMP user {} is already configured".format(user)) + sys.exit(14) + else: + if not user_auth_type: + user_auth_type = '' + if not user_auth_password: + user_auth_password = '' + if not user_encrypt_type: + user_encrypt_type = '' + if not user_encrypt_password: + user_encrypt_password = '' + db.cfgdb.set_entry('SNMP_USER', user, {'SNMP_USER_TYPE': user_type, + 'SNMP_USER_PERMISSION': user_permission_type, + 'SNMP_USER_AUTH_TYPE': user_auth_type, + 'SNMP_USER_AUTH_PASSWORD': user_auth_password, + 'SNMP_USER_ENCRYPTION_TYPE': user_encrypt_type, + 'SNMP_USER_ENCRYPTION_PASSWORD': user_encrypt_password}) + click.echo("SNMP user {} added to configuration".format(user)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() + +@user.command('del') +@click.argument('user', metavar='', required=True) +@clicommon.pass_db +def del_user(db, user): + """ Del snmp user""" + snmp_users = db.cfgdb.get_table("SNMP_USER") + if user not in snmp_users: + click.echo("SNMP user {} is not configured".format(user)) + sys.exit(1) + else: + db.cfgdb.set_entry('SNMP_USER', user, None) + click.echo("SNMP user {} removed from configuration".format(user)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() + + # # 'bgp' group ('config bgp ...') # diff --git a/show/main.py b/show/main.py index efecec3a8d..a8c7a791e9 100755 --- a/show/main.py +++ b/show/main.py @@ -377,6 +377,7 @@ def snmptrap (ctx): body.append([ver, traptable[row]['DestIp'], traptable[row]['DestPort'], traptable[row]['vrf'], traptable[row]['Community']]) click.echo(tabulate(body, header)) + # # 'subinterfaces' group ("show subinterfaces ...") # @@ -1102,8 +1103,25 @@ def interfaces(interfacename, verbose): run_command(cmd, display_cmd=verbose) +# 'ntp' subcommand ("show runningconfiguration ntp") +@runningconfiguration.command() +@click.option('--verbose', is_flag=True, help="Enable verbose output") +def ntp(verbose): + """Show NTP running configuration""" + ntp_servers = [] + ntp_dict = {} + with open("/etc/ntp.conf") as ntp_file: + data = ntp_file.readlines() + for line in data: + if line.startswith("server "): + ntp_server = line.split(" ")[1] + ntp_servers.append(ntp_server) + ntp_dict['NTP Servers'] = ntp_servers + print(tabulate(ntp_dict, headers=list(ntp_dict.keys()), tablefmt="simple", stralign='left', missingval="")) + + # 'snmp' subcommand ("show runningconfiguration snmp") -@runningconfiguration.group(invoke_without_command=True) +@runningconfiguration.group("snmp", invoke_without_command=True) @clicommon.pass_db @click.pass_context def snmp(ctx, db): @@ -1112,42 +1130,39 @@ def snmp(ctx, db): show_run_snmp_global(db.cfgdb) -# ("show runningconfiguration snmp location") -@snmp.command('location') -@click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, help="Display the output in JSON format") +# '("show runningconfiguration snmp community") +@snmp.command('community') +@click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, + help="Display the output in JSON format") @clicommon.pass_db -def location(config_db, json_output): - """show SNMP running configuration location""" - config_db = ConfigDBConnector() - config_db.connect() - snmp = config_db.get_table('SNMP') - snmp_header = ["Location"] - snmp_body = [] +def community(db, json_output): + """show SNMP running configuration community""" + snmp_comm_header = ["Community String", "Community Type"] + snmp_comm_body = [] + snmp_comm_keys = db.cfgdb.get_table('SNMP_COMMUNITY') + snmp_comm_strings = snmp_comm_keys.keys() if json_output: try: - if snmp['LOCATION']: - click.echo(snmp['LOCATION']) + if snmp_comm_keys: + click.echo(snmp_comm_keys) except KeyError: - click.echo("SNMP Location not set") + click.echo("SNMP Community not set") else: - try: - if snmp['LOCATION']: - snmp_location = [snmp['LOCATION']['Location']] - snmp_body.append(snmp_location) - except KeyError: - snmp['LOCATION'] = '' - click.echo(tabulate(snmp_body, snmp_header)) + for line in snmp_comm_strings: + comm_string = line + comm_string_type = snmp_comm_keys[line]['TYPE'] + snmp_comm_body.append([comm_string, comm_string_type]) + click.echo(tabulate(natsorted(snmp_comm_body), snmp_comm_header)) # '("show runningconfiguration snmp contact") @snmp.command('contact') -@click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, help="Display the output in JSON format") +@click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, + help="Display the output in JSON format") @clicommon.pass_db -def contact(config_db, json_output): +def contact(db, json_output): """show SNMP running configuration contact""" - config_db = ConfigDBConnector() - config_db.connect() - snmp = config_db.get_table('SNMP') + snmp = db.cfgdb.get_table('SNMP') snmp_header = ["Contact", "Contact Email"] snmp_body = [] if json_output: @@ -1167,53 +1182,43 @@ def contact(config_db, json_output): click.echo(tabulate(snmp_body, snmp_header)) -# '("show runningconfiguration snmp community") -@snmp.command('community') -@click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, help="Display the output in JSON format") +# ("show runningconfiguration snmp location") +@snmp.command('location') +@click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, + help="Display the output in JSON format") @clicommon.pass_db -def community(config_db, json_output): - """show SNMP running configuration community""" - config_db = ConfigDBConnector() - config_db.connect() - snmp_comm_header = ["Community String", "Community Type"] - snmp_comm_body = [] - snmp_comm_keys = config_db.get_table('SNMP_COMMUNITY') - snmp_comm_strings = snmp_comm_keys.keys() +def location(db, json_output): + """show SNMP running configuration location""" + snmp = db.cfgdb.get_table('SNMP') + snmp_header = ["Location"] + snmp_body = [] if json_output: try: - if snmp_comm_keys: - click.echo(snmp_comm_keys) + if snmp['LOCATION']: + click.echo(snmp['LOCATION']) except KeyError: - click.echo("SNMP Community not set") + click.echo("SNMP Location not set") else: - for line in snmp_comm_strings: - comm_string = line - comm_string_type = snmp_comm_keys[line]['TYPE'] - snmp_comm_body.append([comm_string, comm_string_type]) - click.echo(tabulate(snmp_comm_body, snmp_comm_header)) - - -# ("show runningconfiguration snmp server") -@snmp.command('server') -@click.option('--verbose', is_flag=True, help="Enable verbose output") -@clicommon.pass_db -def users(server, verbose): - """show SNMP running configuration server""" - cmd = "sudo docker exec snmp cat /etc/snmp/snmpd.conf | grep -i agentAddress" - run_command(cmd,display_cmd=verbose) + try: + if snmp['LOCATION']: + snmp_location = [snmp['LOCATION']['Location']] + snmp_body.append(snmp_location) + except KeyError: + snmp['LOCATION'] = '' + click.echo(tabulate(snmp_body, snmp_header)) # '("show runningconfiguration snmp user") @snmp.command('user') -@click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, help="Display the output in JSON format") +@click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, + help="Display the output in JSON format") @clicommon.pass_db -def users(config_db, json_output): +def users(db, json_output): """show SNMP running configuration user""" - config_db = ConfigDBConnector() - config_db.connect() - snmp_users_keys = config_db.get_table('SNMP_USER') + snmp_users_keys = db.cfgdb.get_table('SNMP_USER') snmp_users = snmp_users_keys.keys() - snmp_user_header = ['User', "Type", "Auth Type", "Auth Password", "Encryption Type", "Encryption Password"] + snmp_user_header = ['User', "Permission Type", "Type", "Auth Type", "Auth Password", "Encryption Type", + "Encryption Password"] snmp_user_body = [] if json_output: try: @@ -1224,6 +1229,10 @@ def users(config_db, json_output): else: for line in snmp_users: snmp_user = line + try: + snmp_user_permissions_type = snmp_users_keys[line]['SNMP_USER_PERMISSION'] + except KeyError: + snmp_user_permissions_type = 'Null' try: snmp_user_auth_type = snmp_users_keys[line]['SNMP_USER_AUTH_TYPE'] except KeyError: @@ -1244,24 +1253,25 @@ def users(config_db, json_output): snmp_user_type = snmp_users_keys[line]['SNMP_USER_TYPE'] except KeyError: snmp_user_type = 'Null' - snmp_user_body.append([snmp_user, snmp_user_type, snmp_user_auth_type, snmp_user_auth_password, snmp_user_encryption_type, snmp_user_encryption_password]) - click.echo(tabulate(snmp_user_body, snmp_user_header)) + snmp_user_body.append([snmp_user, snmp_user_permissions_type, snmp_user_type, snmp_user_auth_type, + snmp_user_auth_password, snmp_user_encryption_type, snmp_user_encryption_password]) + click.echo(tabulate(natsorted(snmp_user_body), snmp_user_header)) # ("show runningconfiguration snmp") -def show_run_snmp_global(config_db): - config_db = ConfigDBConnector() - config_db.connect() - snmp_global_table = config_db.get_table('SNMP') - snmp_comm_table = config_db.get_table('SNMP_COMMUNITY') - snmp_users_table = config_db.get_table('SNMP_USER') +@clicommon.pass_db +def show_run_snmp_global(db, ctx): + snmp_global_table = db.cfgdb.get_table('SNMP') + snmp_comm_table = db.cfgdb.get_table('SNMP_COMMUNITY') + snmp_users_table = db.cfgdb.get_table('SNMP_USER') snmp_location_header = ["Location"] snmp_location_body = [] snmp_contact_header = ["SNMP_CONTACT", "SNMP_CONTACT_EMAIL"] snmp_contact_body = [] snmp_comm_header = ["Community String", "Community Type"] snmp_comm_body = [] - snmp_user_header = ['User', "Type", "Auth Type", "Auth Password", "Encryption Type", "Encryption Password"] + snmp_user_header = ['User', "Permission Type", "Type", "Auth Type", "Auth Password", "Encryption Type", + "Encryption Password"] snmp_user_body = [] try: if snmp_global_table['LOCATION']: @@ -1281,15 +1291,19 @@ def show_run_snmp_global(config_db): click.echo(tabulate(snmp_contact_body, snmp_contact_header)) click.echo("\n") snmp_comm_strings = snmp_comm_table.keys() - snmp_users = snmp_users_table.keys() + snmp_users = snmp_users_table.keys() for line in snmp_comm_strings: comm_string = line comm_string_type = snmp_comm_table[line]['TYPE'] snmp_comm_body.append([comm_string, comm_string_type]) - click.echo(tabulate(snmp_comm_body, snmp_comm_header)) + click.echo(tabulate(natsorted(snmp_comm_body), snmp_comm_header)) click.echo("\n") for line in snmp_users: snmp_user = line + try: + snmp_user_permissions_type = snmp_users_table[line]['SNMP_USER_PERMISSION'] + except KeyError: + snmp_user_permissions_type = 'Null' try: snmp_user_auth_type = snmp_users_table[line]['SNMP_USER_AUTH_TYPE'] except KeyError: @@ -1310,25 +1324,9 @@ def show_run_snmp_global(config_db): snmp_user_type = snmp_users_table[line]['SNMP_USER_TYPE'] except KeyError: snmp_user_type = 'Null' - snmp_user_body.append([snmp_user, snmp_user_type, snmp_user_auth_type, snmp_user_auth_password, snmp_user_encryption_type, snmp_user_encryption_password]) - click.echo(tabulate(snmp_user_body, snmp_user_header)) - - -# 'ntp' subcommand ("show runningconfiguration ntp") -@runningconfiguration.command() -@click.option('--verbose', is_flag=True, help="Enable verbose output") -def ntp(verbose): - """Show NTP running configuration""" - ntp_servers = [] - ntp_dict = {} - with open("/etc/ntp.conf") as ntp_file: - data = ntp_file.readlines() - for line in data: - if line.startswith("server "): - ntp_server = line.split(" ")[1] - ntp_servers.append(ntp_server) - ntp_dict['NTP Servers'] = ntp_servers - print(tabulate(ntp_dict, headers=list(ntp_dict.keys()), tablefmt="simple", stralign='left', missingval="")) + snmp_user_body.append([snmp_user, snmp_user_permissions_type, snmp_user_type, snmp_user_auth_type, + snmp_user_auth_password, snmp_user_encryption_type, snmp_user_encryption_password]) + click.echo(tabulate(natsorted(snmp_user_body), snmp_user_header)) # 'syslog' subcommand ("show runningconfiguration syslog") diff --git a/tests/config_snmp_test.py b/tests/config_snmp_test.py new file mode 100644 index 0000000000..56b5086d59 --- /dev/null +++ b/tests/config_snmp_test.py @@ -0,0 +1,814 @@ +import sys +import os +import click +from click.testing import CliRunner + +import show.main as show +import clear.main as clear +import config.main as config + +from unittest import mock +from unittest.mock import patch +from utilities_common.db import Db + +tabular_data_show_run_snmp_contact_expected = """\ +Contact Contact Email\n--------- --------------------\ntestuser testuser@contoso.com +""" + +json_data_show_run_snmp_contact_expected = """\ +{'testuser': 'testuser@contoso.com'} +""" + +config_snmp_contact_add_del_new_contact ="""\ +Contact name testuser and contact email testuser@contoso.com have been added to configuration +Restarting SNMP service... +""" + +config_snmp_location_add_new_location ="""\ +SNMP Location public has been added to configuration +Restarting SNMP service... +""" + + +expected_snmp_community_add_new_community_ro_output = {"TYPE": "RO"} +expected_snmp_community_add_new_community_rw_output = {"TYPE": "RW"} +expected_snmp_community_replace_existing_community_with_new_community_output = {'TYPE': 'RW'} + +expected_snmp_user_priv_ro_md5_des_config_db_output = {'SNMP_USER_AUTH_PASSWORD': 'user_auth_pass', + 'SNMP_USER_AUTH_TYPE': 'MD5', + 'SNMP_USER_ENCRYPTION_PASSWORD': 'user_encrypt_pass', + 'SNMP_USER_ENCRYPTION_TYPE': 'DES', + 'SNMP_USER_PERMISSION': 'RO', + 'SNMP_USER_TYPE': 'Priv'} +expected_snmp_user_priv_ro_md5_aes_config_db_output = {'SNMP_USER_AUTH_PASSWORD': 'user_auth_pass', + 'SNMP_USER_AUTH_TYPE': 'MD5', + 'SNMP_USER_ENCRYPTION_PASSWORD': 'user_encrypt_pass', + 'SNMP_USER_ENCRYPTION_TYPE': 'AES', + 'SNMP_USER_PERMISSION': 'RO', + 'SNMP_USER_TYPE': 'Priv'} +expected_snmp_user_priv_ro_sha_des_config_db_output = {'SNMP_USER_AUTH_PASSWORD': 'user_auth_pass', + 'SNMP_USER_AUTH_TYPE': 'SHA', + 'SNMP_USER_ENCRYPTION_PASSWORD': 'user_encrypt_pass', + 'SNMP_USER_ENCRYPTION_TYPE': 'DES', + 'SNMP_USER_PERMISSION': 'RO', + 'SNMP_USER_TYPE': 'Priv'} +expected_snmp_user_priv_ro_sha_aes_config_db_output = {'SNMP_USER_AUTH_PASSWORD': 'user_auth_pass', + 'SNMP_USER_AUTH_TYPE': 'SHA', + 'SNMP_USER_ENCRYPTION_PASSWORD': 'user_encrypt_pass', + 'SNMP_USER_ENCRYPTION_TYPE': 'AES', + 'SNMP_USER_PERMISSION': 'RO', + 'SNMP_USER_TYPE': 'Priv'} +expected_snmp_user_priv_ro_hmac_sha_2_des_config_db_output = {'SNMP_USER_AUTH_PASSWORD': 'user_auth_pass', + 'SNMP_USER_AUTH_TYPE': 'HMAC-SHA-2', + 'SNMP_USER_ENCRYPTION_PASSWORD': 'user_encrypt_pass', + 'SNMP_USER_ENCRYPTION_TYPE': 'DES', + 'SNMP_USER_PERMISSION': 'RO', + 'SNMP_USER_TYPE': 'Priv'} +expected_snmp_user_priv_ro_hmac_sha_2_aes_config_db_output = {'SNMP_USER_AUTH_PASSWORD': 'user_auth_pass', + 'SNMP_USER_AUTH_TYPE': 'HMAC-SHA-2', + 'SNMP_USER_ENCRYPTION_PASSWORD': 'user_encrypt_pass', + 'SNMP_USER_ENCRYPTION_TYPE': 'AES', + 'SNMP_USER_PERMISSION': 'RO', + 'SNMP_USER_TYPE': 'Priv'} +expected_snmp_user_priv_rw_md5_des_config_db_output = {'SNMP_USER_AUTH_PASSWORD': 'user_auth_pass', + 'SNMP_USER_AUTH_TYPE': 'MD5', + 'SNMP_USER_ENCRYPTION_PASSWORD': 'user_encrypt_pass', + 'SNMP_USER_ENCRYPTION_TYPE': 'DES', + 'SNMP_USER_PERMISSION': 'RW', + 'SNMP_USER_TYPE': 'Priv'} +expected_snmp_user_priv_rw_md5_aes_config_db_output = {'SNMP_USER_AUTH_PASSWORD': 'user_auth_pass', + 'SNMP_USER_AUTH_TYPE': 'MD5', + 'SNMP_USER_ENCRYPTION_PASSWORD': 'user_encrypt_pass', + 'SNMP_USER_ENCRYPTION_TYPE': 'AES', + 'SNMP_USER_PERMISSION': 'RW', + 'SNMP_USER_TYPE': 'Priv'} +expected_snmp_user_priv_rw_sha_des_config_db_output = {'SNMP_USER_AUTH_PASSWORD': 'user_auth_pass', + 'SNMP_USER_AUTH_TYPE': 'SHA', + 'SNMP_USER_ENCRYPTION_PASSWORD': 'user_encrypt_pass', + 'SNMP_USER_ENCRYPTION_TYPE': 'DES', + 'SNMP_USER_PERMISSION': 'RW', + 'SNMP_USER_TYPE': 'Priv'} +expected_snmp_user_priv_rw_sha_aes_config_db_output = {'SNMP_USER_AUTH_PASSWORD': 'user_auth_pass', + 'SNMP_USER_AUTH_TYPE': 'SHA', + 'SNMP_USER_ENCRYPTION_PASSWORD': 'user_encrypt_pass', + 'SNMP_USER_ENCRYPTION_TYPE': 'AES', + 'SNMP_USER_PERMISSION': 'RW', + 'SNMP_USER_TYPE': 'Priv'} +expected_snmp_user_priv_rw_hmac_sha_2_des_config_db_output = {'SNMP_USER_AUTH_PASSWORD': 'user_auth_pass', + 'SNMP_USER_AUTH_TYPE': 'HMAC-SHA-2', + 'SNMP_USER_ENCRYPTION_PASSWORD': 'user_encrypt_pass', + 'SNMP_USER_ENCRYPTION_TYPE': 'DES', + 'SNMP_USER_PERMISSION': 'RW', + 'SNMP_USER_TYPE': 'Priv'} +expected_snmp_user_priv_rw_hmac_sha_2_aes_config_db_output = {'SNMP_USER_AUTH_PASSWORD': 'user_auth_pass', + 'SNMP_USER_AUTH_TYPE': 'HMAC-SHA-2', + 'SNMP_USER_ENCRYPTION_PASSWORD': 'user_encrypt_pass', + 'SNMP_USER_ENCRYPTION_TYPE': 'AES', + 'SNMP_USER_PERMISSION': 'RW', + 'SNMP_USER_TYPE': 'Priv'} + +class TestSNMPConfigCommands(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["UTILITIES_UNIT_TESTING"] = "1" + + # Add snmp community tests + def test_config_snmp_community_add_new_community_ro(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["add"], + ["Everest", "ro"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP community Everest added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_COMMUNITY", "Everest") == expected_snmp_community_add_new_community_ro_output + + def test_config_snmp_community_add_new_community_rw(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["add"], + ["Shasta", "rw"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP community Shasta added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_COMMUNITY", "Shasta") == expected_snmp_community_add_new_community_rw_output + + def test_config_snmp_community_add_new_community_with_invalid_type(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["add"], ["Everest", "RT"]) + print(result.exit_code) + assert result.exit_code == 1 + assert 'SNMP type must be RO or RW and not RT' in result.output + + def test_config_snmp_community_add_invalid_community_over_32_characters(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["add"], + ["over_32_character_community_string", "ro"]) + print(result.exit_code) + assert result.exit_code == 2 + assert 'FAILED: SNMP community string length should be not be greater than 32' in result.output + + def test_config_snmp_community_add_invalid_community_with_excluded_special_characters(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["add"], + ["Test@snmp", "ro"]) + print(result.exit_code) + assert result.exit_code == 2 + assert 'FAILED: SNMP community string should not have any of these special symbols' in result.output + + def test_config_snmp_community_add_existing_community(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["add"], ["Rainer", "rw"]) + print(result.exit_code) + assert result.exit_code == 3 + assert 'SNMP community Rainer is already configured' in result.output + + # Del snmp community tests + def test_config_snmp_community_del_existing_community(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["del"], + ["Rainer"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP community Rainer removed from configuration' in result.output + assert db.cfgdb.get_entry("SNMP_COMMUNITY", "Everest") == {} + + def test_config_snmp_community_del_non_existing_community(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["del"], ["Everest"]) + print(result.exit_code) + assert result.exit_code == 1 + assert 'SNMP community Everest is not configured' in result.output + + # Replace snmp community tests + def test_config_snmp_community_replace_existing_community_with_new_community(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["replace"], + ["Rainer", "Everest"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP community Everest added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_COMMUNITY", "Everest") == \ + expected_snmp_community_replace_existing_community_with_new_community_output + + def test_config_snmp_community_replace_existing_community_does_not_exist(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["replace"], + ["Denali", "Everest"]) + print(result.exit_code) + assert result.exit_code == 1 + assert 'Current SNMP community Denali is not configured' in result.output + + def test_config_snmp_community_replace_new_community_already_exists(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["replace"], + ["Rainer", "msft"]) + print(result.exit_code) + assert result.exit_code == 3 + assert 'New SNMP community msft to replace current SNMP community Rainer already configured' in result.output + + def test_config_snmp_community_replace_with_invalid_new_community_bad_symbol(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["replace"], + ["Rainer", "msft@"]) + print(result.exit_code) + assert result.exit_code == 2 + assert 'FAILED: SNMP community string should not have any of these special symbols' in result.output + + def test_config_snmp_community_replace_with_invalid_new_community_over_32_chars(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["replace"], + ["Rainer", "over_32_characters_community_string"]) + print(result.exit_code) + assert result.exit_code == 2 + assert 'FAILED: SNMP community string length should be not be greater than 32' in result.output + + + # Del snmp contact when CONTACT not setup in REDIS + def test_config_snmp_contact_del_without_contact_redis(self): + db = Db() + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["del"], ["blah"], obj=db) + print(result.exit_code) + assert result.exit_code == 2 + assert 'Contact name blah is not configured' in result.output + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {} + + def test_config_snmp_contact_modify_without_contact_redis(self): + db = Db() + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["modify"], + ["blah", "blah@contoso.com"], obj=db) + print(result.exit_code) + assert result.exit_code == 2 + assert 'Contact name blah is not configured' in result.output + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {} + + def test_config_snmp_contact_add_del_new_contact(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["add"], + ["testuser", "testuser@contoso.com"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_contact_add_del_new_contact + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {"testuser": "testuser@contoso.com"} + + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["del"], + ["testuser"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert 'SNMP contact testuser removed from configuration' in result.output + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {} + + # Add snmp contact tests + def test_config_snmp_contact_add_with_existing_contact(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["add"], + ["testuser", "testuser@contoso.com"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_contact_add_del_new_contact + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {"testuser": "testuser@contoso.com"} + + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["add"], + ["blah", "blah@contoso.com"], obj=db) + print(result.exit_code) + assert result.exit_code == 1 + assert 'Contact already exists. Use sudo config snmp contact modify instead' in result.output + + # Delete snmp contact tests + def test_config_snmp_contact_del_without_existing_contact(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["add"], + ["testuser", "testuser@contoso.com"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_contact_add_del_new_contact + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {"testuser": "testuser@contoso.com"} + + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["del"], ["blah"], obj=db) + print(result.exit_code) + assert result.exit_code == 1 + assert 'SNMP contact blah is not configured' in result.output + + def test_config_snmp_contact_del_with_existing_contact(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["add"], + ["testuser", "testuser@contoso.com"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_contact_add_del_new_contact + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {"testuser": "testuser@contoso.com"} + + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["del"], + ["testuser"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP contact testuser removed from configuration' in result.output + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {} + + # Modify snmp contact tests + def test_config_snmp_contact_modify_email_with_existing_contact(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["add"], + ["testuser", "testuser@contoso.com"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_contact_add_del_new_contact + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {"testuser": "testuser@contoso.com"} + + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["modify"], + ["testuser", "testuser@test.com"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP contact testuser email updated to testuser@test.com' in result.output + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {"testuser": "testuser@test.com"} + + def test_config_snmp_contact_modify_contact_and_email_with_existing_entry(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["add"], + ["testuser", "testuser@contoso.com"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_contact_add_del_new_contact + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {"testuser": "testuser@contoso.com"} + + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["modify"], + ["testuser", "testuser@contoso.com"], obj=db) + print(result.exit_code) + assert result.exit_code == 1 + assert 'SNMP contact testuser testuser@contoso.com already exists' in result.output + + # Add snmp location tests + def test_config_snmp_location_add_exiting_location_with_same_location_already_existing(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["add"], + ["public"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_location_add_new_location + assert db.cfgdb.get_entry("SNMP", "LOCATION") == {"Location": "public"} + + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["add"], + ["public"], obj=db) + print(result.exit_code) + assert result.exit_code == 1 + assert 'Location already exists' in result.output + + def test_config_snmp_location_add_new_location_with_location_already_existing(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["add"], + ["public"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_location_add_new_location + assert db.cfgdb.get_entry("SNMP", "LOCATION") == {"Location": "public"} + + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["add"], + ["Mile High"], obj=db) + print(result.exit_code) + assert result.exit_code == 1 + assert 'Location already exists' in result.output + + # Del snmp location tests + def test_config_snmp_location_del_with_existing_location(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["add"], + ["public"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_location_add_new_location + assert db.cfgdb.get_entry("SNMP", "LOCATION") == {"Location": "public"} + + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["del"], + ["public"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP Location public removed from configuration' in result.output + assert db.cfgdb.get_entry("SNMP", "LOCATION") == {} + + def test_config_snmp_location_del_new_location_with_location_already_existing(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["add"], + ["public"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_location_add_new_location + assert db.cfgdb.get_entry("SNMP", "LOCATION") == {"Location": "public"} + + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["del"], + ["Mile High"], obj=db) + print(result.exit_code) + assert result.exit_code == 1 + assert 'SNMP Location Mile High does not exist. The location is public' in result.output + + # Modify snmp location tests + def test_config_snmp_location_modify_with_same_location(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["add"], + ["public"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_location_add_new_location + assert db.cfgdb.get_entry("SNMP", "LOCATION") == {"Location": "public"} + + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["modify"], + ["public"], obj=db) + print(result.exit_code) + assert result.exit_code == 1 + assert 'SNMP location public already exists' in result.output + + def test_config_snmp_location_modify_without_redis(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["modify"], + ["Rainer"],obj=db) + print(result.exit_code) + assert result.exit_code == 2 + assert "Cannot modify SNMP Location. You must use 'config snmp location add " \ + "command '" in result.output + assert db.cfgdb.get_entry("SNMP", "LOCATION") == {} + + def test_config_snmp_location_modify_without_existing_location(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["add"], + ["public"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_location_add_new_location + assert db.cfgdb.get_entry("SNMP", "LOCATION") == {"Location": "public"} + + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["modify"], + ["Rainer"],obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert "SNMP location Rainer modified in configuration" in result.output + assert db.cfgdb.get_entry("SNMP", "LOCATION") == {"Location": "Rainer"} + + # Add snmp user tests + def test_config_snmp_user_add_invalid_user_name_over_32_characters(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["over_32_characters_community_user", "noAUthNoPRiv", "ro"]) + print(result.exit_code) + assert result.exit_code == 1 + assert 'FAILED: SNMP user over_32_characters_community_user length should not be greater than 32 characters' \ + in result.output + + def test_config_snmp_user_add_excluded_special_characters_in_username(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["Test@user", "noAUthNoPRiv", "ro"]) + print(result.exit_code) + assert result.exit_code == 1 + assert 'FAILED: SNMP user Test@user should not have any of these special symbols' in result.output + + def test_config_snmp_user_add_existing_user(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_1", "noAUthNoPRiv", "ro"]) + print(result.exit_code) + assert result.exit_code == 14 + assert 'SNMP user test_nopriv_RO_1 is already configured' in result.output + + def test_config_snmp_user_add_invalid_user_type(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "nopriv", "ro"]) + print(result.exit_code) + assert result.exit_code == 2 + assert 'User type nopriv is invalid. Must be noauthnopriv, authnopriv, or priv' in result.output + + def test_config_snmp_user_add_invalid_permission_type(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "noauthnopriv", "ab"]) + print(result.exit_code) + assert result.exit_code == 3 + assert 'User permission type AB is invalid. Must be RO or RW' in result.output + + def test_config_snmp_user_add_user_type_noauthnopriv_with_unnecessary_auth_type(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "noauthnopriv", "ro", "sha"]) + print(result.exit_code) + assert result.exit_code == 4 + assert "User auth type not used with 'noAuthNoPriv'. Please use 'AuthNoPriv' or 'Priv' instead" \ + in result.output + + def test_config_snmp_user_add_user_type_authnopriv_missing_auth_type(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "authnopriv", "ro"]) + print(result.exit_code) + assert result.exit_code == 5 + assert "User auth type is missing. Must be MD5, SHA, or HMAC-SHA-2" in result.output + + def test_config_snmp_user_add_user_type_authnopriv_missing_auth_password(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "authnopriv", "ro", "sha"]) + print(result.exit_code) + assert result.exit_code == 7 + assert "User auth password is missing" in result.output + + def test_config_snmp_user_add_user_type_authnopriv_with_unnecessary_encrypt_type(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "authnopriv", "ro", "sha", "testauthpass", "DES"]) + print(result.exit_code) + assert result.exit_code == 9 + assert "User encrypt type not used with 'AuthNoPriv'. Please use 'Priv' instead" in result.output + + def test_config_snmp_user_add_user_type_priv_missing_auth_type(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "priv", "ro"]) + print(result.exit_code) + assert result.exit_code == 5 + assert "User auth type is missing. Must be MD5, SHA, or HMAC-SHA-2" in result.output + + def test_config_snmp_user_add_user_type_priv_missing_auth_password(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "priv", "ro", "md5"]) + print(result.exit_code) + assert result.exit_code == 7 + assert "User auth password is missing" in result.output + + def test_config_snmp_user_add_user_type_priv_missing_encrypt_type(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "priv", "ro", "md5", "testauthpass"]) + print(result.exit_code) + assert result.exit_code == 10 + assert "User encrypt type is missing. Must be DES or AES" in result.output + + def test_config_snmp_user_add_user_type_priv_invalid_encrypt_password_over_64_characters(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "priv", "ro", "md5", "testauthpass", "DES", + "superlongencryptionpasswordtotestbeingoverthesixtyfourcharacterlimit"]) + print(result.exit_code) + assert result.exit_code == 13 + assert "FAILED: SNMP user password length should be not be greater than 64" in result.output + + def test_config_snmp_user_add_user_type_priv_invalid_encrypt_password_excluded_special_characters(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "priv", "ro", "md5", "testauthpass", "DES", "testencrypt@pass"]) + print(result.exit_code) + assert result.exit_code == 13 + assert "FAILED: SNMP user password should not have any of these special symbols" in result.output + + def test_config_snmp_user_add_user_type_priv_invalid_encrypt_password_not_long_enough(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "priv", "ro", "md5", "testauthpass", "DES", "test1"]) + print(result.exit_code) + assert result.exit_code == 13 + assert "FAILED: SNMP user password length should be at least 8 characters" in result.output + + def test_config_snmp_user_add_invalid_auth_type(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "authnopriv", "ro", "DM5", "user_auth_pass"]) + print(result.exit_code) + assert result.exit_code == 6 + assert 'User auth type DM5 is invalid. Must be MD5, SHA, or HMAC-SHA-2' in result.output + + def test_config_snmp_user_add_missing_auth_password(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "authnopriv", "ro", "SHA", ""]) + print(result.exit_code) + assert result.exit_code == 7 + assert 'User auth password is missing' in result.output + + def test_config_snmp_user_add_invalid_encrypt_type(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "priv", "ro", "SHA", "user_auth_pass", "EAS", "user_encrypt_pass"]) + print(result.exit_code) + assert result.exit_code == 11 + assert 'User encryption type EAS is invalid. Must be DES or AES' in result.output + + def test_config_snmp_user_add_missing_encrypt_password(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_3", "priv", "ro", "SHA", "user_auth_pass", "AES"]) + print(result.exit_code) + assert result.exit_code == 12 + assert 'User encrypt password is missing' in result.output + + def test_config_snmp_user_add_user_already_existing(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_nopriv_RO_1", "noauthnopriv", "ro"]) + print(result.exit_code) + assert result.exit_code == 14 + assert 'SNMP user test_nopriv_RO_1 is already configured' in result.output + + def test_config_snmp_user_add_valid_user_priv_ro_md5_des(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_priv_RO_7", "priv", "ro", "MD5", "user_auth_pass", "DES", "user_encrypt_pass"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RO_7 added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_USER", "test_priv_RO_7") == expected_snmp_user_priv_ro_md5_des_config_db_output + + def test_config_snmp_user_add_valid_user_priv_ro_md5_aes(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_priv_RO_8", "priv", "ro", "MD5", "user_auth_pass", "AES", "user_encrypt_pass"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RO_8 added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_USER", "test_priv_RO_8") == expected_snmp_user_priv_ro_md5_aes_config_db_output + + def test_config_snmp_user_add_valid_user_priv_ro_sha_des(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_priv_RO_9", "priv", "ro", "SHA", "user_auth_pass", "DES", "user_encrypt_pass"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RO_9 added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_USER", "test_priv_RO_9") == expected_snmp_user_priv_ro_sha_des_config_db_output + + def test_config_snmp_user_add_valid_user_priv_ro_sha_aes(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_priv_RO_10", "priv", "ro", "SHA", "user_auth_pass", "AES", "user_encrypt_pass"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RO_10 added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_USER", "test_priv_RO_10") == expected_snmp_user_priv_ro_sha_aes_config_db_output + + def test_config_snmp_user_add_valid_user_priv_ro_hmac_sha_2_des(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_priv_RO_11", "priv", "ro", "HMAC-SHA-2", "user_auth_pass", "DES", "user_encrypt_pass"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RO_11 added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_USER", "test_priv_RO_11") == \ + expected_snmp_user_priv_ro_hmac_sha_2_des_config_db_output + + def test_config_snmp_user_add_valid_user_priv_ro_hmac_sha_2_aes(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_priv_RO_12", "priv", "ro", "HMAC-SHA-2", "user_auth_pass", "AES", "user_encrypt_pass"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RO_12 added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_USER", "test_priv_RO_12") == \ + expected_snmp_user_priv_ro_hmac_sha_2_aes_config_db_output + + def test_config_snmp_user_add_valid_user_priv_rw_md5_des(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_priv_RW_7", "priv", "rw", "MD5", "user_auth_pass", "DES", "user_encrypt_pass"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RW_7 added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_USER", "test_priv_RW_7") == expected_snmp_user_priv_rw_md5_des_config_db_output + + def test_config_snmp_user_add_valid_user_priv_rw_md5_aes(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_priv_RW_8", "priv", "rw", "MD5", "user_auth_pass", "AES", "user_encrypt_pass"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RW_8 added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_USER", "test_priv_RW_8") == expected_snmp_user_priv_rw_md5_aes_config_db_output + + def test_config_snmp_user_add_valid_user_priv_rw_sha_des(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_priv_RW_9", "priv", "rw", "SHA", "user_auth_pass", "DES", "user_encrypt_pass"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RW_9 added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_USER", "test_priv_RW_9") == expected_snmp_user_priv_rw_sha_des_config_db_output + + def test_config_snmp_user_add_valid_user_priv_rw_sha_aes(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_priv_RW_10", "priv", "rw", "SHA", "user_auth_pass", "AES", "user_encrypt_pass"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RW_10 added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_USER", "test_priv_RW_10") == expected_snmp_user_priv_rw_sha_aes_config_db_output + + def test_config_snmp_user_add_valid_user_priv_rw_hmac_sha_2_des(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_priv_RW_11", "priv", "rw", "HMAC-SHA-2", "user_auth_pass", "DES", "user_encrypt_pass"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RW_11 added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_USER", "test_priv_RW_11") == \ + expected_snmp_user_priv_rw_hmac_sha_2_des_config_db_output + + def test_config_snmp_user_add_valid_user_priv_rw_hmac_sha_2_aes(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], + ["test_priv_RW_12", "priv", "rw", "HMAC-SHA-2", "user_auth_pass", "AES", "user_encrypt_pass"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RW_12 added to configuration' in result.output + assert db.cfgdb.get_entry("SNMP_USER", "test_priv_RW_12") == \ + expected_snmp_user_priv_rw_hmac_sha_2_aes_config_db_output + + # Del snmp user tests + def test_config_snmp_user_del_valid_user(self): + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_nopriv_RO_1"]) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_nopriv_RO_1 removed from configuration' in result.output + + def test_config_snmp_user_del_invalid_user(self): + runner = CliRunner() + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_nopriv_RO_2"]) + print(result.exit_code) + assert result.exit_code == 1 + assert 'SNMP user test_nopriv_RO_2 is not configured' in result.output + + @classmethod + def teardown_class(cls): + print("TEARDOWN") + os.environ["UTILITIES_UNIT_TESTING"] = "0" diff --git a/tests/mock_tables/config_db.json b/tests/mock_tables/config_db.json index f8ceebffbf..6c554f8f98 100644 --- a/tests/mock_tables/config_db.json +++ b/tests/mock_tables/config_db.json @@ -695,6 +695,172 @@ "peer_switch": "sonic-switch", "type": "ToRRouter" }, + "SNMP_COMMUNITY|msft": { + "TYPE": "RO" + }, + "SNMP_COMMUNITY|Rainer": { + "TYPE": "RW" + }, + "SNMP_USER|test_authpriv_RO_2": { + "SNMP_USER_TYPE": "AuthNoPriv", + "SNMP_USER_PERMISSION": "RO", + "SNMP_USER_AUTH_TYPE": "SHA", + "SNMP_USER_AUTH_PASSWORD": "test_authpriv_RO_2_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "", + "SNMP_USER_ENCRYPTION_PASSWORD": "" + }, + "SNMP_USER|test_authpriv_RO_3": { + "SNMP_USER_TYPE": "AuthNoPriv", + "SNMP_USER_PERMISSION": "RO", + "SNMP_USER_AUTH_TYPE": "HMAC-SHA-2", + "SNMP_USER_AUTH_PASSWORD": "test_authpriv_RO_3_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "", + "SNMP_USER_ENCRYPTION_PASSWORD": "" + }, + "SNMP_USER|test_priv_RW_4": { + "SNMP_USER_TYPE": "Priv", + "SNMP_USER_PERMISSION": "RW", + "SNMP_USER_AUTH_TYPE": "SHA", + "SNMP_USER_AUTH_PASSWORD": "test_priv_RW_4_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "AES", + "SNMP_USER_ENCRYPTION_PASSWORD": "test_priv_RW_4_encrpytpass" + }, + "SNMP_USER|test_priv_RW_3": { + "SNMP_USER_TYPE": "Priv", + "SNMP_USER_PERMISSION": "RW", + "SNMP_USER_AUTH_TYPE": "SHA", + "SNMP_USER_AUTH_PASSWORD": "test_priv_RW_3_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "DES", + "SNMP_USER_ENCRYPTION_PASSWORD": "test_priv_RW_3_encrpytpass" + }, + "SNMP_USER|test_priv_RO_2": { + "SNMP_USER_TYPE": "Priv", + "SNMP_USER_PERMISSION": "RO", + "SNMP_USER_AUTH_TYPE": "MD5", + "SNMP_USER_AUTH_PASSWORD": "test_priv_RO_2_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "AES", + "SNMP_USER_ENCRYPTION_PASSWORD": "test_priv_RO_2_encrpytpass" + }, + "SNMP_USER|test_nopriv_RO_1": { + "SNMP_USER_TYPE": "noAuthNoPriv", + "SNMP_USER_PERMISSION": "RO", + "SNMP_USER_AUTH_TYPE": "", + "SNMP_USER_AUTH_PASSWORD": "", + "SNMP_USER_ENCRYPTION_TYPE": "", + "SNMP_USER_ENCRYPTION_PASSWORD": "" + }, + "SNMP_USER|test_priv_RW_1": { + "SNMP_USER_TYPE": "Priv", + "SNMP_USER_PERMISSION": "RW", + "SNMP_USER_AUTH_TYPE": "MD5", + "SNMP_USER_AUTH_PASSWORD": "test_priv_RO_1_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "DES", + "SNMP_USER_ENCRYPTION_PASSWORD": "test_priv_RW_1_encrpytpass" + }, + "SNMP_USER|test_authpriv_RW_1": { + "SNMP_USER_TYPE": "AuthNoPriv", + "SNMP_USER_PERMISSION": "RW", + "SNMP_USER_AUTH_TYPE": "MD5", + "SNMP_USER_AUTH_PASSWORD": "test_authpriv_RW_1_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "", + "SNMP_USER_ENCRYPTION_PASSWORD": "" + }, + "SNMP_USER|test_priv_RO_6": { + "SNMP_USER_TYPE": "Priv", + "SNMP_USER_PERMISSION": "RO", + "SNMP_USER_AUTH_TYPE": "HMAC-SHA-2", + "SNMP_USER_AUTH_PASSWORD": "test_priv_RO_6_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "AES", + "SNMP_USER_ENCRYPTION_PASSWORD": "test_priv_RO_6_encrpytpass" + }, + "SNMP_USER|test_priv_RO_1": { + "SNMP_USER_TYPE": "Priv", + "SNMP_USER_PERMISSION": "RO", + "SNMP_USER_AUTH_TYPE": "MD5", + "SNMP_USER_AUTH_PASSWORD": "test_priv_RO_1_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "DES", + "SNMP_USER_ENCRYPTION_PASSWORD": "test_priv_RO_1_encrpytpass" + }, + "SNMP_USER|test_priv_RO_5": { + "SNMP_USER_TYPE": "Priv", + "SNMP_USER_PERMISSION": "RO", + "SNMP_USER_AUTH_TYPE": "HMAC-SHA-2", + "SNMP_USER_AUTH_PASSWORD": "test_priv_RO_5_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "DES", + "SNMP_USER_ENCRYPTION_PASSWORD": "test_priv_RO_5_encrpytpass" + }, + "SNMP_USER|test_nopriv_RW_1": { + "SNMP_USER_TYPE": "noAuthNoPriv", + "SNMP_USER_PERMISSION": "RW", + "SNMP_USER_AUTH_TYPE": "", + "SNMP_USER_AUTH_PASSWORD": "", + "SNMP_USER_ENCRYPTION_TYPE": "", + "SNMP_USER_ENCRYPTION_PASSWORD": "" + }, + "SNMP_USER|test_priv_RO_3": { + "SNMP_USER_TYPE": "Priv", + "SNMP_USER_PERMISSION": "RO", + "SNMP_USER_AUTH_TYPE": "SHA", + "SNMP_USER_AUTH_PASSWORD": "test_priv_RO_3_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "DES", + "SNMP_USER_ENCRYPTION_PASSWORD": "test_priv_RO_3_encrpytpass" + }, + "SNMP_USER|test_priv_RW_2": { + "SNMP_USER_TYPE": "Priv", + "SNMP_USER_PERMISSION": "RW", + "SNMP_USER_AUTH_TYPE": "MD5", + "SNMP_USER_AUTH_PASSWORD": "test_priv_RO_2_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "AES", + "SNMP_USER_ENCRYPTION_PASSWORD": "test_priv_RW_2_encrpytpass" + }, + "SNMP_USER|test_authpriv_RW_3": { + "SNMP_USER_TYPE": "AuthNoPriv", + "SNMP_USER_PERMISSION": "RW", + "SNMP_USER_AUTH_TYPE": "HMAC-SHA-2", + "SNMP_USER_AUTH_PASSWORD": "test_authpriv_RW_3_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "", + "SNMP_USER_ENCRYPTION_PASSWORD": "" + }, + "SNMP_USER|test_priv_RW_5": { + "SNMP_USER_TYPE": "Priv", + "SNMP_USER_PERMISSION": "RW", + "SNMP_USER_AUTH_TYPE": "HMAC-SHA-2", + "SNMP_USER_AUTH_PASSWORD": "test_priv_RW_5_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "DES", + "SNMP_USER_ENCRYPTION_PASSWORD": "test_priv_RW_5_encrpytpass" + }, + "SNMP_USER|test_priv_RW_6": { + "SNMP_USER_TYPE": "Priv", + "SNMP_USER_PERMISSION": "RW", + "SNMP_USER_AUTH_TYPE": "HMAC-SHA-2", + "SNMP_USER_AUTH_PASSWORD": "test_priv_RW_6_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "AES", + "SNMP_USER_ENCRYPTION_PASSWORD": "test_priv_RW_6_encrpytpass" + }, + "SNMP_USER|test_authpriv_RW_2": { + "SNMP_USER_TYPE": "AuthNoPriv", + "SNMP_USER_PERMISSION": "RW", + "SNMP_USER_AUTH_TYPE": "SHA", + "SNMP_USER_AUTH_PASSWORD": "test_authpriv_RW_2_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "", + "SNMP_USER_ENCRYPTION_PASSWORD": "" + }, + "SNMP_USER|test_priv_RO_4": { + "SNMP_USER_TYPE": "Priv", + "SNMP_USER_PERMISSION": "RO", + "SNMP_USER_AUTH_TYPE": "SHA", + "SNMP_USER_AUTH_PASSWORD": "test_priv_RO_4_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "AES", + "SNMP_USER_ENCRYPTION_PASSWORD": "test_priv_RO_4_encrpytpass" + }, + "SNMP_USER|test_authpriv_RO_1": { + "SNMP_USER_TYPE": "AuthNoPriv", + "SNMP_USER_PERMISSION": "RO", + "SNMP_USER_AUTH_TYPE": "MD5", + "SNMP_USER_AUTH_PASSWORD": "test_authpriv_RO_1_authpass", + "SNMP_USER_ENCRYPTION_TYPE": "", + "SNMP_USER_ENCRYPTION_PASSWORD": "" + }, "DEVICE_NEIGHBOR|Ethernet0": { "name": "Servers", "port": "eth0" diff --git a/tests/show_snmp_test.py b/tests/show_snmp_test.py new file mode 100644 index 0000000000..7ff771043a --- /dev/null +++ b/tests/show_snmp_test.py @@ -0,0 +1,296 @@ +import sys +import os +import click +from click.testing import CliRunner +import pytest +import swsssdk + +test_path = os.path.dirname(os.path.abspath(__file__)) +modules_path = os.path.dirname(test_path) +scripts_path = os.path.join(modules_path, "scripts") +sys.path.insert(0, test_path) +sys.path.insert(0, modules_path) + +import show.main as show +import clear.main as clear +import config.main as config + +import mock_tables.dbconnector + +from unittest import mock +from unittest.mock import patch +from utilities_common.db import Db + +config_snmp_location_add_new_location ="""\ +SNMP Location public has been added to configuration +Restarting SNMP service... +""" + +config_snmp_contact_add_del_new_contact ="""\ +Contact name testuser and contact email testuser@contoso.com have been added to configuration +Restarting SNMP service... +""" + +tabular_data_show_run_snmp_contact_expected = """\ +Contact Contact Email\n--------- --------------------\ntestuser testuser@contoso.com +""" + +json_data_show_run_snmp_contact_expected = """\ +{'testuser': 'testuser@contoso.com'} +""" + +tabular_data_show_run_snmp_community_expected = """\ +Community String Community Type +------------------ ---------------- +Rainer RW +msft RO +""" + +json_data_show_run_snmp_community_expected = """\ +{'msft': {'TYPE': 'RO'}, 'Rainer': {'TYPE': 'RW'}} +""" + +tabular_data_show_run_snmp_location_expected = """\ +Location +---------- +public +""" + +json_data_show_run_snmp_location_expected = """\ +{'Location': 'public'} +""" + + +tabular_data_show_run_snmp_user_expected = """\ +User Permission Type Type Auth Type Auth Password Encryption Type Encryption Password +------------------ ----------------- ------------ ----------- --------------------------- ----------------- -------------------------- +test_authpriv_RO_1 RO AuthNoPriv MD5 test_authpriv_RO_1_authpass +test_authpriv_RO_2 RO AuthNoPriv SHA test_authpriv_RO_2_authpass +test_authpriv_RO_3 RO AuthNoPriv HMAC-SHA-2 test_authpriv_RO_3_authpass +test_authpriv_RW_1 RW AuthNoPriv MD5 test_authpriv_RW_1_authpass +test_authpriv_RW_2 RW AuthNoPriv SHA test_authpriv_RW_2_authpass +test_authpriv_RW_3 RW AuthNoPriv HMAC-SHA-2 test_authpriv_RW_3_authpass +test_nopriv_RO_1 RO noAuthNoPriv +test_nopriv_RW_1 RW noAuthNoPriv +test_priv_RO_1 RO Priv MD5 test_priv_RO_1_authpass DES test_priv_RO_1_encrpytpass +test_priv_RO_2 RO Priv MD5 test_priv_RO_2_authpass AES test_priv_RO_2_encrpytpass +test_priv_RO_3 RO Priv SHA test_priv_RO_3_authpass DES test_priv_RO_3_encrpytpass +test_priv_RO_4 RO Priv SHA test_priv_RO_4_authpass AES test_priv_RO_4_encrpytpass +test_priv_RO_5 RO Priv HMAC-SHA-2 test_priv_RO_5_authpass DES test_priv_RO_5_encrpytpass +test_priv_RO_6 RO Priv HMAC-SHA-2 test_priv_RO_6_authpass AES test_priv_RO_6_encrpytpass +test_priv_RW_1 RW Priv MD5 test_priv_RO_1_authpass DES test_priv_RW_1_encrpytpass +test_priv_RW_2 RW Priv MD5 test_priv_RO_2_authpass AES test_priv_RW_2_encrpytpass +test_priv_RW_3 RW Priv SHA test_priv_RW_3_authpass DES test_priv_RW_3_encrpytpass +test_priv_RW_4 RW Priv SHA test_priv_RW_4_authpass AES test_priv_RW_4_encrpytpass +test_priv_RW_5 RW Priv HMAC-SHA-2 test_priv_RW_5_authpass DES test_priv_RW_5_encrpytpass +test_priv_RW_6 RW Priv HMAC-SHA-2 test_priv_RW_6_authpass AES test_priv_RW_6_encrpytpass +""" + + + + +json_data_show_run_snmp_user_expected = """{'test_authpriv_RO_2': {'SNMP_USER_TYPE': 'AuthNoPriv', 'SNMP_USER_PERMISSION': 'RO', 'SNMP_USER_AUTH_TYPE': 'SHA', 'SNMP_USER_AUTH_PASSWORD': 'test_authpriv_RO_2_authpass', 'SNMP_USER_ENCRYPTION_TYPE': '', 'SNMP_USER_ENCRYPTION_PASSWORD': ''}, 'test_authpriv_RO_3': {'SNMP_USER_TYPE': 'AuthNoPriv', 'SNMP_USER_PERMISSION': 'RO', 'SNMP_USER_AUTH_TYPE': 'HMAC-SHA-2', 'SNMP_USER_AUTH_PASSWORD': 'test_authpriv_RO_3_authpass', 'SNMP_USER_ENCRYPTION_TYPE': '', 'SNMP_USER_ENCRYPTION_PASSWORD': ''}, 'test_priv_RW_4': {'SNMP_USER_TYPE': 'Priv', 'SNMP_USER_PERMISSION': 'RW', 'SNMP_USER_AUTH_TYPE': 'SHA', 'SNMP_USER_AUTH_PASSWORD': 'test_priv_RW_4_authpass', 'SNMP_USER_ENCRYPTION_TYPE': 'AES', 'SNMP_USER_ENCRYPTION_PASSWORD': 'test_priv_RW_4_encrpytpass'}, 'test_priv_RW_3': {'SNMP_USER_TYPE': 'Priv', 'SNMP_USER_PERMISSION': 'RW', 'SNMP_USER_AUTH_TYPE': 'SHA', 'SNMP_USER_AUTH_PASSWORD': 'test_priv_RW_3_authpass', 'SNMP_USER_ENCRYPTION_TYPE': 'DES', 'SNMP_USER_ENCRYPTION_PASSWORD': 'test_priv_RW_3_encrpytpass'}, 'test_priv_RO_2': {'SNMP_USER_TYPE': 'Priv', 'SNMP_USER_PERMISSION': 'RO', 'SNMP_USER_AUTH_TYPE': 'MD5', 'SNMP_USER_AUTH_PASSWORD': 'test_priv_RO_2_authpass', 'SNMP_USER_ENCRYPTION_TYPE': 'AES', 'SNMP_USER_ENCRYPTION_PASSWORD': 'test_priv_RO_2_encrpytpass'}, 'test_nopriv_RO_1': {'SNMP_USER_TYPE': 'noAuthNoPriv', 'SNMP_USER_PERMISSION': 'RO', 'SNMP_USER_AUTH_TYPE': '', 'SNMP_USER_AUTH_PASSWORD': '', 'SNMP_USER_ENCRYPTION_TYPE': '', 'SNMP_USER_ENCRYPTION_PASSWORD': ''}, 'test_priv_RW_1': {'SNMP_USER_TYPE': 'Priv', 'SNMP_USER_PERMISSION': 'RW', 'SNMP_USER_AUTH_TYPE': 'MD5', 'SNMP_USER_AUTH_PASSWORD': 'test_priv_RO_1_authpass', 'SNMP_USER_ENCRYPTION_TYPE': 'DES', 'SNMP_USER_ENCRYPTION_PASSWORD': 'test_priv_RW_1_encrpytpass'}, 'test_authpriv_RW_1': {'SNMP_USER_TYPE': 'AuthNoPriv', 'SNMP_USER_PERMISSION': 'RW', 'SNMP_USER_AUTH_TYPE': 'MD5', 'SNMP_USER_AUTH_PASSWORD': 'test_authpriv_RW_1_authpass', 'SNMP_USER_ENCRYPTION_TYPE': '', 'SNMP_USER_ENCRYPTION_PASSWORD': ''}, 'test_priv_RO_6': {'SNMP_USER_TYPE': 'Priv', 'SNMP_USER_PERMISSION': 'RO', 'SNMP_USER_AUTH_TYPE': 'HMAC-SHA-2', 'SNMP_USER_AUTH_PASSWORD': 'test_priv_RO_6_authpass', 'SNMP_USER_ENCRYPTION_TYPE': 'AES', 'SNMP_USER_ENCRYPTION_PASSWORD': 'test_priv_RO_6_encrpytpass'}, 'test_priv_RO_1': {'SNMP_USER_TYPE': 'Priv', 'SNMP_USER_PERMISSION': 'RO', 'SNMP_USER_AUTH_TYPE': 'MD5', 'SNMP_USER_AUTH_PASSWORD': 'test_priv_RO_1_authpass', 'SNMP_USER_ENCRYPTION_TYPE': 'DES', 'SNMP_USER_ENCRYPTION_PASSWORD': 'test_priv_RO_1_encrpytpass'}, 'test_priv_RO_5': {'SNMP_USER_TYPE': 'Priv', 'SNMP_USER_PERMISSION': 'RO', 'SNMP_USER_AUTH_TYPE': 'HMAC-SHA-2', 'SNMP_USER_AUTH_PASSWORD': 'test_priv_RO_5_authpass', 'SNMP_USER_ENCRYPTION_TYPE': 'DES', 'SNMP_USER_ENCRYPTION_PASSWORD': 'test_priv_RO_5_encrpytpass'}, 'test_nopriv_RW_1': {'SNMP_USER_TYPE': 'noAuthNoPriv', 'SNMP_USER_PERMISSION': 'RW', 'SNMP_USER_AUTH_TYPE': '', 'SNMP_USER_AUTH_PASSWORD': '', 'SNMP_USER_ENCRYPTION_TYPE': '', 'SNMP_USER_ENCRYPTION_PASSWORD': ''}, 'test_priv_RO_3': {'SNMP_USER_TYPE': 'Priv', 'SNMP_USER_PERMISSION': 'RO', 'SNMP_USER_AUTH_TYPE': 'SHA', 'SNMP_USER_AUTH_PASSWORD': 'test_priv_RO_3_authpass', 'SNMP_USER_ENCRYPTION_TYPE': 'DES', 'SNMP_USER_ENCRYPTION_PASSWORD': 'test_priv_RO_3_encrpytpass'}, 'test_priv_RW_2': {'SNMP_USER_TYPE': 'Priv', 'SNMP_USER_PERMISSION': 'RW', 'SNMP_USER_AUTH_TYPE': 'MD5', 'SNMP_USER_AUTH_PASSWORD': 'test_priv_RO_2_authpass', 'SNMP_USER_ENCRYPTION_TYPE': 'AES', 'SNMP_USER_ENCRYPTION_PASSWORD': 'test_priv_RW_2_encrpytpass'}, 'test_authpriv_RW_3': {'SNMP_USER_TYPE': 'AuthNoPriv', 'SNMP_USER_PERMISSION': 'RW', 'SNMP_USER_AUTH_TYPE': 'HMAC-SHA-2', 'SNMP_USER_AUTH_PASSWORD': 'test_authpriv_RW_3_authpass', 'SNMP_USER_ENCRYPTION_TYPE': '', 'SNMP_USER_ENCRYPTION_PASSWORD': ''}, 'test_priv_RW_5': {'SNMP_USER_TYPE': 'Priv', 'SNMP_USER_PERMISSION': 'RW', 'SNMP_USER_AUTH_TYPE': 'HMAC-SHA-2', 'SNMP_USER_AUTH_PASSWORD': 'test_priv_RW_5_authpass', 'SNMP_USER_ENCRYPTION_TYPE': 'DES', 'SNMP_USER_ENCRYPTION_PASSWORD': 'test_priv_RW_5_encrpytpass'}, 'test_priv_RW_6': {'SNMP_USER_TYPE': 'Priv', 'SNMP_USER_PERMISSION': 'RW', 'SNMP_USER_AUTH_TYPE': 'HMAC-SHA-2', 'SNMP_USER_AUTH_PASSWORD': 'test_priv_RW_6_authpass', 'SNMP_USER_ENCRYPTION_TYPE': 'AES', 'SNMP_USER_ENCRYPTION_PASSWORD': 'test_priv_RW_6_encrpytpass'}, 'test_authpriv_RW_2': {'SNMP_USER_TYPE': 'AuthNoPriv', 'SNMP_USER_PERMISSION': 'RW', 'SNMP_USER_AUTH_TYPE': 'SHA', 'SNMP_USER_AUTH_PASSWORD': 'test_authpriv_RW_2_authpass', 'SNMP_USER_ENCRYPTION_TYPE': '', 'SNMP_USER_ENCRYPTION_PASSWORD': ''}, 'test_priv_RO_4': {'SNMP_USER_TYPE': 'Priv', 'SNMP_USER_PERMISSION': 'RO', 'SNMP_USER_AUTH_TYPE': 'SHA', 'SNMP_USER_AUTH_PASSWORD': 'test_priv_RO_4_authpass', 'SNMP_USER_ENCRYPTION_TYPE': 'AES', 'SNMP_USER_ENCRYPTION_PASSWORD': 'test_priv_RO_4_encrpytpass'}, 'test_authpriv_RO_1': {'SNMP_USER_TYPE': 'AuthNoPriv', 'SNMP_USER_PERMISSION': 'RO', 'SNMP_USER_AUTH_TYPE': 'MD5', 'SNMP_USER_AUTH_PASSWORD': 'test_authpriv_RO_1_authpass', 'SNMP_USER_ENCRYPTION_TYPE': '', 'SNMP_USER_ENCRYPTION_PASSWORD': ''}} +""" + +tabular_data_show_run_snmp_expected = """\ +Location +---------- +public + + +SNMP_CONTACT SNMP_CONTACT_EMAIL +-------------- -------------------- +testuser testuser@contoso.com + + +Community String Community Type +------------------ ---------------- +Rainer RW +msft RO + + +User Permission Type Type Auth Type Auth Password Encryption Type Encryption Password +------------------ ----------------- ------------ ----------- --------------------------- ----------------- -------------------------- +test_authpriv_RO_1 RO AuthNoPriv MD5 test_authpriv_RO_1_authpass +test_authpriv_RO_2 RO AuthNoPriv SHA test_authpriv_RO_2_authpass +test_authpriv_RO_3 RO AuthNoPriv HMAC-SHA-2 test_authpriv_RO_3_authpass +test_authpriv_RW_1 RW AuthNoPriv MD5 test_authpriv_RW_1_authpass +test_authpriv_RW_2 RW AuthNoPriv SHA test_authpriv_RW_2_authpass +test_authpriv_RW_3 RW AuthNoPriv HMAC-SHA-2 test_authpriv_RW_3_authpass +test_nopriv_RO_1 RO noAuthNoPriv +test_nopriv_RW_1 RW noAuthNoPriv +test_priv_RO_1 RO Priv MD5 test_priv_RO_1_authpass DES test_priv_RO_1_encrpytpass +test_priv_RO_2 RO Priv MD5 test_priv_RO_2_authpass AES test_priv_RO_2_encrpytpass +test_priv_RO_3 RO Priv SHA test_priv_RO_3_authpass DES test_priv_RO_3_encrpytpass +test_priv_RO_4 RO Priv SHA test_priv_RO_4_authpass AES test_priv_RO_4_encrpytpass +test_priv_RO_5 RO Priv HMAC-SHA-2 test_priv_RO_5_authpass DES test_priv_RO_5_encrpytpass +test_priv_RO_6 RO Priv HMAC-SHA-2 test_priv_RO_6_authpass AES test_priv_RO_6_encrpytpass +test_priv_RW_1 RW Priv MD5 test_priv_RO_1_authpass DES test_priv_RW_1_encrpytpass +test_priv_RW_2 RW Priv MD5 test_priv_RO_2_authpass AES test_priv_RW_2_encrpytpass +test_priv_RW_3 RW Priv SHA test_priv_RW_3_authpass DES test_priv_RW_3_encrpytpass +test_priv_RW_4 RW Priv SHA test_priv_RW_4_authpass AES test_priv_RW_4_encrpytpass +test_priv_RW_5 RW Priv HMAC-SHA-2 test_priv_RW_5_authpass DES test_priv_RW_5_encrpytpass +test_priv_RW_6 RW Priv HMAC-SHA-2 test_priv_RW_6_authpass AES test_priv_RW_6_encrpytpass +""" + + +class TestSNMPShowCommands(object): + @classmethod + def setup_class(cls): + print("SETUP") + os.environ["PATH"] += os.pathsep + scripts_path + os.environ["UTILITIES_UNIT_TESTING"] = "1" + + # mock the redis for unit test purposes # + try: + if os.environ["UTILITIES_UNIT_TESTING"] == "1": + modules_path = os.path.join(os.path.dirname(__file__), "..") + test_path = os.path.join(modules_path, "sonic-utilities-tests") + sys.path.insert(0, modules_path) + sys.path.insert(0, test_path) + import mock_tables.dbconnector + except KeyError: + pass + + def test_show_run_snmp_location_tabular(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["add"], + ["public"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_location_add_new_location + assert db.cfgdb.get_entry("SNMP", "LOCATION") == {"Location": "public"} + + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["location"], + [], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == tabular_data_show_run_snmp_location_expected + + def test_show_run_snmp_location_json(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["add"], + ["public"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_location_add_new_location + assert db.cfgdb.get_entry("SNMP", "LOCATION") == {"Location": "public"} + + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["location"], + ["--json"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == json_data_show_run_snmp_location_expected + + def test_show_run_snmp_contact_tabular(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["add"], + ["testuser", "testuser@contoso.com"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_contact_add_del_new_contact + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {"testuser": "testuser@contoso.com"} + + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["contact"], + [], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == tabular_data_show_run_snmp_contact_expected + + def test_show_run_snmp_contact_json(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["add"], + ["testuser", "testuser@contoso.com"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_contact_add_del_new_contact + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {"testuser": "testuser@contoso.com"} + + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["contact"], + ["--json"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == json_data_show_run_snmp_contact_expected + + def test_show_run_snmp_community_tabular(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["community"], []) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == tabular_data_show_run_snmp_community_expected + + def test_show_run_snmp_community_json(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["community"], + ["--json"]) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == json_data_show_run_snmp_community_expected + + def test_show_run_snmp_user_tabular(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["user"], []) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == tabular_data_show_run_snmp_user_expected + + def test_show_run_snmp_user_json(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["user"], ["--json"]) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == json_data_show_run_snmp_user_expected + + def test_show_run_snmp_tabular(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["add"], + ["testuser", "testuser@contoso.com"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_contact_add_del_new_contact + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {"testuser": "testuser@contoso.com"} + + result = runner.invoke(config.config.commands["snmp"].commands["location"].commands["add"], + ["public"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_location_add_new_location + assert db.cfgdb.get_entry("SNMP", "LOCATION") == {"Location": "public"} + + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"], [], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == tabular_data_show_run_snmp_expected + + + @classmethod + def teardown_class(cls): + print("TEARDOWN") + os.environ["PATH"] = os.pathsep.join(os.environ["PATH"].split(os.pathsep)[:-1]) + os.environ["UTILITIES_UNIT_TESTING"] = "0" + From afa839d55b0302f5ba28db112de3bc12a4867946 Mon Sep 17 00:00:00 2001 From: tsvanduyn Date: Tue, 27 Apr 2021 23:28:22 +0000 Subject: [PATCH 3/6] updated show commands and show tests --- show/main.py | 117 +++++++++------------------ tests/show_snmp_test.py | 171 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 207 insertions(+), 81 deletions(-) diff --git a/show/main.py b/show/main.py index a8c7a791e9..829195bf5b 100755 --- a/show/main.py +++ b/show/main.py @@ -1120,6 +1120,7 @@ def ntp(verbose): print(tabulate(ntp_dict, headers=list(ntp_dict.keys()), tablefmt="simple", stralign='left', missingval="")) + # 'snmp' subcommand ("show runningconfiguration snmp") @runningconfiguration.group("snmp", invoke_without_command=True) @clicommon.pass_db @@ -1127,10 +1128,10 @@ def ntp(verbose): def snmp(ctx, db): """Show SNMP running configuration""" if ctx.invoked_subcommand is None: - show_run_snmp_global(db.cfgdb) + show_run_snmp(db.cfgdb) -# '("show runningconfiguration snmp community") +# ("show runningconfiguration snmp community") @snmp.command('community') @click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, help="Display the output in JSON format") @@ -1142,11 +1143,7 @@ def community(db, json_output): snmp_comm_keys = db.cfgdb.get_table('SNMP_COMMUNITY') snmp_comm_strings = snmp_comm_keys.keys() if json_output: - try: - if snmp_comm_keys: - click.echo(snmp_comm_keys) - except KeyError: - click.echo("SNMP Community not set") + click.echo(snmp_comm_keys) else: for line in snmp_comm_strings: comm_string = line @@ -1155,7 +1152,7 @@ def community(db, json_output): click.echo(tabulate(natsorted(snmp_comm_body), snmp_comm_header)) -# '("show runningconfiguration snmp contact") +# ("show runningconfiguration snmp contact") @snmp.command('contact') @click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, help="Display the output in JSON format") @@ -1170,7 +1167,8 @@ def contact(db, json_output): if snmp['CONTACT']: click.echo(snmp['CONTACT']) except KeyError: - click.echo("SNMP Contact not set") + snmp['CONTACT'] = {} + click.echo(snmp['CONTACT']) else: try: if snmp['CONTACT']: @@ -1197,7 +1195,8 @@ def location(db, json_output): if snmp['LOCATION']: click.echo(snmp['LOCATION']) except KeyError: - click.echo("SNMP Location not set") + snmp['LOCATION'] = {} + click.echo(snmp['LOCATION']) else: try: if snmp['LOCATION']: @@ -1208,51 +1207,27 @@ def location(db, json_output): click.echo(tabulate(snmp_body, snmp_header)) -# '("show runningconfiguration snmp user") +# ("show runningconfiguration snmp user") @snmp.command('user') @click.option('--json', 'json_output', required=False, is_flag=True, type=click.BOOL, help="Display the output in JSON format") @clicommon.pass_db def users(db, json_output): """show SNMP running configuration user""" - snmp_users_keys = db.cfgdb.get_table('SNMP_USER') - snmp_users = snmp_users_keys.keys() + snmp_users = db.cfgdb.get_table('SNMP_USER') snmp_user_header = ['User', "Permission Type", "Type", "Auth Type", "Auth Password", "Encryption Type", "Encryption Password"] snmp_user_body = [] if json_output: - try: - if snmp_users_keys: - click.echo(snmp_users_keys) - except KeyError: - click.echo("SNMP User not set") + click.echo(snmp_users) else: - for line in snmp_users: - snmp_user = line - try: - snmp_user_permissions_type = snmp_users_keys[line]['SNMP_USER_PERMISSION'] - except KeyError: - snmp_user_permissions_type = 'Null' - try: - snmp_user_auth_type = snmp_users_keys[line]['SNMP_USER_AUTH_TYPE'] - except KeyError: - snmp_user_auth_type = 'Null' - try: - snmp_user_auth_password = snmp_users_keys[line]['SNMP_USER_AUTH_PASSWORD'] - except KeyError: - snmp_user_auth_password = 'Null' - try: - snmp_user_encryption_type = snmp_users_keys[line]['SNMP_USER_ENCRYPTION_TYPE'] - except KeyError: - snmp_user_encryption_type = 'Null' - try: - snmp_user_encryption_password = snmp_users_keys[line]['SNMP_USER_ENCRYPTION_PASSWORD'] - except KeyError: - snmp_user_encryption_password = 'Null' - try: - snmp_user_type = snmp_users_keys[line]['SNMP_USER_TYPE'] - except KeyError: - snmp_user_type = 'Null' + for snmp_user, snmp_user_value in snmp_users.items(): + snmp_user_permissions_type = snmp_users[snmp_user].get('SNMP_USER_PERMISSION', 'Null') + snmp_user_auth_type = snmp_users[snmp_user].get('SNMP_USER_AUTH_TYPE', 'Null') + snmp_user_auth_password = snmp_users[snmp_user].get('SNMP_USER_AUTH_PASSWORD', 'Null') + snmp_user_encryption_type = snmp_users[snmp_user].get('SNMP_USER_ENCRYPTION_TYPE', 'Null') + snmp_user_encryption_password = snmp_users[snmp_user].get('SNMP_USER_ENCRYPTION_PASSWORD', 'Null') + snmp_user_type = snmp_users[snmp_user].get('SNMP_USER_TYPE', 'Null') snmp_user_body.append([snmp_user, snmp_user_permissions_type, snmp_user_type, snmp_user_auth_type, snmp_user_auth_password, snmp_user_encryption_type, snmp_user_encryption_password]) click.echo(tabulate(natsorted(snmp_user_body), snmp_user_header)) @@ -1260,10 +1235,10 @@ def users(db, json_output): # ("show runningconfiguration snmp") @clicommon.pass_db -def show_run_snmp_global(db, ctx): - snmp_global_table = db.cfgdb.get_table('SNMP') +def show_run_snmp(db, ctx): + snmp_contact_location_table = db.cfgdb.get_table('SNMP') snmp_comm_table = db.cfgdb.get_table('SNMP_COMMUNITY') - snmp_users_table = db.cfgdb.get_table('SNMP_USER') + snmp_users = db.cfgdb.get_table('SNMP_USER') snmp_location_header = ["Location"] snmp_location_body = [] snmp_contact_header = ["SNMP_CONTACT", "SNMP_CONTACT_EMAIL"] @@ -1274,56 +1249,36 @@ def show_run_snmp_global(db, ctx): "Encryption Password"] snmp_user_body = [] try: - if snmp_global_table['LOCATION']: - snmp_location = [snmp_global_table['LOCATION']['Location']] + if snmp_contact_location_table['LOCATION']: + snmp_location = [snmp_contact_location_table['LOCATION']['Location']] snmp_location_body.append(snmp_location) except KeyError: - snmp_global_table['LOCATION'] = '' + snmp_contact_location_table['LOCATION'] = '' click.echo(tabulate(snmp_location_body, snmp_location_header)) click.echo("\n") try: - if snmp_global_table['CONTACT']: - snmp_contact = list(snmp_global_table['CONTACT'].keys()) - snmp_contact_email = [snmp_global_table['CONTACT'][snmp_contact[0]]] + if snmp_contact_location_table['CONTACT']: + snmp_contact = list(snmp_contact_location_table['CONTACT'].keys()) + snmp_contact_email = [snmp_contact_location_table['CONTACT'][snmp_contact[0]]] snmp_contact_body.append([snmp_contact[0], snmp_contact_email[0]]) except KeyError: - snmp_global_table['CONTACT'] = '' + snmp_contact_location_table['CONTACT'] = '' click.echo(tabulate(snmp_contact_body, snmp_contact_header)) click.echo("\n") snmp_comm_strings = snmp_comm_table.keys() - snmp_users = snmp_users_table.keys() for line in snmp_comm_strings: comm_string = line comm_string_type = snmp_comm_table[line]['TYPE'] snmp_comm_body.append([comm_string, comm_string_type]) click.echo(tabulate(natsorted(snmp_comm_body), snmp_comm_header)) click.echo("\n") - for line in snmp_users: - snmp_user = line - try: - snmp_user_permissions_type = snmp_users_table[line]['SNMP_USER_PERMISSION'] - except KeyError: - snmp_user_permissions_type = 'Null' - try: - snmp_user_auth_type = snmp_users_table[line]['SNMP_USER_AUTH_TYPE'] - except KeyError: - snmp_user_auth_type = 'Null' - try: - snmp_user_auth_password = snmp_users_table[line]['SNMP_USER_AUTH_PASSWORD'] - except KeyError: - snmp_user_auth_password = 'Null' - try: - snmp_user_encryption_type = snmp_users_table[line]['SNMP_USER_ENCRYPTION_TYPE'] - except KeyError: - snmp_user_encryption_type = 'Null' - try: - snmp_user_encryption_password = snmp_users_table[line]['SNMP_USER_ENCRYPTION_PASSWORD'] - except KeyError: - snmp_user_encryption_password = 'Null' - try: - snmp_user_type = snmp_users_table[line]['SNMP_USER_TYPE'] - except KeyError: - snmp_user_type = 'Null' + for snmp_user, snmp_user_value in snmp_users.items(): + snmp_user_permissions_type = snmp_users[snmp_user].get('SNMP_USER_PERMISSION', 'Null') + snmp_user_auth_type = snmp_users[snmp_user].get('SNMP_USER_AUTH_TYPE', 'Null') + snmp_user_auth_password = snmp_users[snmp_user].get('SNMP_USER_AUTH_PASSWORD', 'Null') + snmp_user_encryption_type = snmp_users[snmp_user].get('SNMP_USER_ENCRYPTION_TYPE', 'Null') + snmp_user_encryption_password = snmp_users[snmp_user].get('SNMP_USER_ENCRYPTION_PASSWORD', 'Null') + snmp_user_type = snmp_users[snmp_user].get('SNMP_USER_TYPE', 'Null') snmp_user_body.append([snmp_user, snmp_user_permissions_type, snmp_user_type, snmp_user_auth_type, snmp_user_auth_password, snmp_user_encryption_type, snmp_user_encryption_password]) click.echo(tabulate(natsorted(snmp_user_body), snmp_user_header)) diff --git a/tests/show_snmp_test.py b/tests/show_snmp_test.py index 7ff771043a..753e20c418 100644 --- a/tests/show_snmp_test.py +++ b/tests/show_snmp_test.py @@ -4,6 +4,7 @@ from click.testing import CliRunner import pytest import swsssdk +import traceback test_path = os.path.dirname(os.path.abspath(__file__)) modules_path = os.path.dirname(test_path) @@ -190,6 +191,25 @@ def test_show_run_snmp_location_json(self): assert result.exit_code == 0 assert result.output == json_data_show_run_snmp_location_expected + def test_show_run_snmp_location_json_bad_key(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["location"], ["--json"]) + print(result.exit_code) + print(result.output) + traceback.print_tb(result.exc_info[2]) + assert result.exit_code == 0 + assert "{}" in result.output + + + def test_show_run_snmp_location_bad_key(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["location"], []) + print(result.exit_code) + print(result.output) + traceback.print_tb(result.exc_info[2]) + assert result.exit_code == 0 + assert "" in result.output + def test_show_run_snmp_contact_tabular(self): db = Db() runner = CliRunner() @@ -228,6 +248,25 @@ def test_show_run_snmp_contact_json(self): assert result.exit_code == 0 assert result.output == json_data_show_run_snmp_contact_expected + def test_show_run_snmp_contact_json_bad_key(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["contact"], ["--json"]) + print(result.exit_code) + print(result.output) + traceback.print_tb(result.exc_info[2]) + assert result.exit_code == 0 + assert '{}' in result.output + + def test_show_run_snmp_contact_tabular_bad_key(self): + runner = CliRunner() + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["contact"]) + print(result.exit_code) + print(result.output) + traceback.print_tb(result.exc_info[2]) + assert result.exit_code == 0 + assert '' in result.output + + def test_show_run_snmp_community_tabular(self): runner = CliRunner() result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["community"], []) @@ -261,6 +300,138 @@ def test_show_run_snmp_user_json(self): assert result.exit_code == 0 assert result.output == json_data_show_run_snmp_user_expected + def test_show_run_snmp_user_json_bad_key(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_authpriv_RO_1"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_authpriv_RO_1 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_authpriv_RO_2"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_authpriv_RO_2 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_authpriv_RO_3"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_authpriv_RO_3 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_authpriv_RW_1"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_authpriv_RW_1 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_authpriv_RW_2"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_authpriv_RW_2 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_authpriv_RW_3"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_authpriv_RW_3 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_nopriv_RO_1"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_nopriv_RO_1 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_nopriv_RW_1"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_nopriv_RW_1 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_priv_RO_1"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RO_1 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_priv_RO_2"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RO_2 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_priv_RO_3"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RO_3 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_priv_RO_4"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RO_4 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_priv_RO_5"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RO_5 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_priv_RO_6"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RO_6 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_priv_RW_1"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RW_1 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_priv_RW_2"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RW_2 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_priv_RW_3"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RW_3 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_priv_RW_4"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RW_4 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_priv_RW_5"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RW_5 removed from configuration' in result.output + + result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["del"], + ["test_priv_RW_6"], obj=db) + print(result.exit_code) + assert result.exit_code == 0 + assert 'SNMP user test_priv_RW_6 removed from configuration' in result.output + + result = runner.invoke(show.cli.commands["runningconfiguration"].commands["snmp"].commands["user"], ["--json"], obj=db) + print(result.exit_code) + print(result.output) + traceback.print_tb(result.exc_info[2]) + assert result.exit_code == 0 + assert "{}" in result.output + + def test_show_run_snmp_tabular(self): db = Db() runner = CliRunner() From 200725544c73d6dd60352fe0b59aef030aa2e38b Mon Sep 17 00:00:00 2001 From: tsvanduyn Date: Fri, 30 Apr 2021 00:23:31 +0000 Subject: [PATCH 4/6] updated snmp config commands and tests --- config/main.py | 116 ++++++++++++++++++++------------------ tests/config_snmp_test.py | 70 +++++++++++++++++++---- 2 files changed, 122 insertions(+), 64 deletions(-) diff --git a/config/main.py b/config/main.py index bf0c50c621..bad820b944 100644 --- a/config/main.py +++ b/config/main.py @@ -2090,17 +2090,20 @@ def is_valid_community_type(commstr_type): def is_valid_user_type(user_type): + convert_user_type = {'noauthnopriv': 'noAuthNoPriv', 'authnopriv': 'AuthNoPriv', 'priv': 'Priv'} user_types = ['noauthnopriv', 'authnopriv', 'priv'] if user_type not in user_types: - click.echo("Invalid user type. Must be one of these one of these three " + message = ("Invalid user type. Must be one of these one of these three " "'noauthnopriv' or 'authnopriv' or 'priv'") - return False - return True + click.echo(message) + return False, message + return True, convert_user_type[user_type] def is_valid_auth_type(user_auth_type): user_auth_types = ['MD5', 'SHA', 'HMAC-SHA-2'] if user_auth_type not in user_auth_types: + click.echo("Invalid user authentication type. Must be one of these 'MD5', 'SHA', or 'HMAC-SHA-2'") return False return True @@ -2184,26 +2187,22 @@ def add_community(db, community, string_type): """ Add snmp community string""" string_type = string_type.upper() if not is_valid_community_type(string_type): - click.echo("SNMP type must be RO or RW and not {}".format(string_type)) sys.exit(1) if not snmp_community_secret_check(community): - click.echo("Bad community") sys.exit(2) snmp_communities = db.cfgdb.get_table("SNMP_COMMUNITY") if community in snmp_communities: click.echo("SNMP community {} is already configured".format(community)) sys.exit(3) - else: - db.cfgdb.set_entry('SNMP_COMMUNITY', community, {'TYPE': string_type}) - click.echo("SNMP community {} added to configuration".format(community)) - try: - click.echo("Restarting SNMP service...") - clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) - clicommon.run_command("systemctl restart snmp.service", display_cmd=False) - except SystemExit as e: - db.cfgdb.set_entry('SNMP_COMMUNITY', community, None) - click.echo("Restart service snmp failed with error {}".format(e)) - raise click.Abort() + db.cfgdb.set_entry('SNMP_COMMUNITY', community, {'TYPE': string_type}) + click.echo("SNMP community {} added to configuration".format(community)) + try: + click.echo("Restarting SNMP service...") + clicommon.run_command("systemctl reset-failed snmp.service", display_cmd=False) + clicommon.run_command("systemctl restart snmp.service", display_cmd=False) + except SystemExit as e: + click.echo("Restart service snmp failed with error {}".format(e)) + raise click.Abort() @community.command('del') @@ -2238,7 +2237,6 @@ def replace_community(db, current_community, new_community): click.echo("Current SNMP community {} is not configured".format(current_community)) sys.exit(1) if not snmp_community_secret_check(new_community): - click.echo("Bad community") sys.exit(2) elif new_community in snmp_communities: click.echo("New SNMP community {} to replace current SNMP community {} already " @@ -2249,7 +2247,6 @@ def replace_community(db, current_community, new_community): db.cfgdb.set_entry('SNMP_COMMUNITY', new_community, {'TYPE': string_type}) click.echo("SNMP community {} added to configuration".format(new_community)) db.cfgdb.set_entry('SNMP_COMMUNITY', current_community, None) - click.echo('SNMP community {} removed from configuration'.format(current_community)) click.echo('SNMP community {} replace community {}'.format(new_community, current_community)) try: click.echo("Restarting SNMP service...") @@ -2281,9 +2278,6 @@ def add_contact(db, contact, contact_email): if snmp['CONTACT']: click.echo("Contact already exists. Use sudo config snmp contact modify instead") sys.exit(1) - if not is_valid_email(contact_email): - click.echo("Contact email {} is not valid".format(contact_email)) - sys.exit(2) else: db.cfgdb.set_entry('SNMP', 'CONTACT', {contact: contact_email}) click.echo("Contact name {} and contact email {} have been added to " @@ -2297,6 +2291,9 @@ def add_contact(db, contact, contact_email): raise click.Abort() except KeyError: if "CONTACT" not in snmp.keys(): + if not is_valid_email(contact_email): + click.echo("Contact email {} is not valid".format(contact_email)) + sys.exit(2) db.cfgdb.set_entry('SNMP', 'CONTACT', {contact: contact_email}) click.echo("Contact name {} and contact email {} have been added to " "configuration".format(contact, contact_email)) @@ -2352,6 +2349,9 @@ def modify_contact(db, contact, contact_email): click.echo("SNMP contact {} {} already exists".format(contact, contact_email)) sys.exit(1) elif contact == current_snmp_contact_name and contact_email != current_snmp_contact_email: + if not is_valid_email(contact_email): + click.echo("Contact email {} is not valid".format(contact_email)) + sys.exit(2) db.cfgdb.mod_entry('SNMP', 'CONTACT', {contact: contact_email}) click.echo("SNMP contact {} email updated to {}".format(contact, contact_email)) try: @@ -2362,6 +2362,9 @@ def modify_contact(db, contact, contact_email): click.echo("Restart service snmp failed with error {}".format(e)) raise click.Abort() else: + if not is_valid_email(contact_email): + click.echo("Contact email {} is not valid".format(contact_email)) + sys.exit(2) db.cfgdb.set_entry('SNMP', 'CONTACT', None) db.cfgdb.set_entry('SNMP', 'CONTACT', {contact: contact_email}) click.echo("SNMP contact {} and contact email {} updated".format(contact, contact_email)) @@ -2375,7 +2378,7 @@ def modify_contact(db, contact, contact_email): except KeyError: if "CONTACT" not in snmp.keys(): click.echo("Contact name {} is not configured".format(contact)) - sys.exit(2) + sys.exit(3) @snmp.group(cls=clicommon.AbbreviationGroup) @@ -2471,6 +2474,24 @@ def modify_location(db, location): sys.exit(2) +from enum import IntEnum +class SnmpUserError(IntEnum): + NameCheckFailure = 1 + TypeNoAuthNoPrivOrAuthNoPrivOrPrivCheckFailure = 2 + RoRwCheckFailure = 3 + NoAuthNoPrivHasAuthType = 4 + AuthTypeMd5OrShaOrHmacsha2IsMissing = 5 + AuthTypeMd5OrShaOrHmacsha2Failure = 6 + AuthPasswordMissing = 7 + AuthPasswordFailsComplexityRequirements = 8 + EncryptPasswordNotAllowedWithAuthNoPriv = 9 + EncryptTypeDesOrAesIsMissing = 10 + EncryptTypeFailsComplexityRequirements = 11 + EncryptPasswordMissingFailure = 12 + EncryptPasswordFailsComplexityRequirements = 13 + UserAlreadyConfigured = 14 + + @snmp.group(cls=clicommon.AbbreviationGroup) @clicommon.pass_db def user(db): @@ -2486,71 +2507,58 @@ def user(db): @click.argument('user_encrypt_type', metavar='', required=False) @click.argument('user_encrypt_password', metavar='', required=False) @clicommon.pass_db -def add_user(db, user, user_type, user_permission_type, user_auth_type, user_auth_password, user_encrypt_type, +def add_user(db, user, user_type, user_permission_type, user_auth_type, user_auth_password, user_encrypt_type, user_encrypt_password): """ Add snmp user""" - click.echo(user) if not snmp_username_check(user): - click.echo("Bad SNMP user") - sys.exit(1) + sys.exit(SnmpUserError.NameCheckFailure) user_type = user_type.lower() - if not is_valid_user_type(user_type): - click.echo("User type {} is invalid. Must be noauthnopriv, authnopriv, or priv".format(user_type)) - sys.exit(2) - if user_type == "noauthnopriv": - user_type = "noAuthNoPriv" - elif user_type == "authnopriv": - user_type = "AuthNoPriv" - elif user_type == "priv": - user_type = "Priv" + if not is_valid_user_type(user_type)[0]: + sys.exit(SnmpUserError.TypeNoAuthNoPrivOrAuthNoPrivOrPrivCheckFailure) + user_type = is_valid_user_type(user_type)[1] user_permission_type = user_permission_type.upper() if not is_valid_community_type(user_permission_type): - click.echo("User permission type {} is invalid. Must be RO or RW".format(user_permission_type)) - sys.exit(3) + sys.exit(SnmpUserError.RoRwCheckFailure) if user_type == "noAuthNoPriv": if user_auth_type: click.echo("User auth type not used with 'noAuthNoPriv'. Please use 'AuthNoPriv' or 'Priv' instead") - sys.exit(4) - if user_type is not 'noAuthNoPriv': + sys.exit(SnmpUserError.NoAuthNoPrivHasAuthType) + else: if not user_auth_type: click.echo("User auth type is missing. Must be MD5, SHA, or HMAC-SHA-2") - sys.exit(5) + sys.exit(SnmpUserError.AuthTypeMd5OrShaOrHmacsha2IsMissing) if user_auth_type: user_auth_type = user_auth_type.upper() if not is_valid_auth_type(user_auth_type): - click.echo("User auth type {} is invalid. Must be MD5, SHA, or HMAC-SHA-2".format(user_auth_type)) - sys.exit(6) + sys.exit(SnmpUserError.AuthTypeMd5OrShaOrHmacsha2Failure) elif not user_auth_password: click.echo("User auth password is missing") - sys.exit(7) + sys.exit(SnmpUserError.AuthPasswordMissing) elif user_auth_password: if not snmp_user_secret_check(user_auth_password): - click.echo("Bad user auth password") - sys.exit(8) + sys.exit(SnmpUserError.AuthPasswordFailsComplexityRequirements) if user_type == "AuthNoPriv": if user_encrypt_type: click.echo("User encrypt type not used with 'AuthNoPriv'. Please use 'Priv' instead") - sys.exit(9) + sys.exit(SnmpUserError.EncryptPasswordNotAllowedWithAuthNoPriv) elif user_type == "Priv": if not user_encrypt_type: click.echo("User encrypt type is missing. Must be DES or AES") - sys.exit(10) + sys.exit(SnmpUserError.EncryptTypeDesOrAesIsMissing) if user_encrypt_type: user_encrypt_type = user_encrypt_type.upper() if not is_valid_encrypt_type(user_encrypt_type): - click.echo("User encryption type {} is invalid. Must be DES or AES".format(user_encrypt_type)) - sys.exit(11) + sys.exit(SnmpUserError.EncryptTypeFailsComplexityRequirements) elif not user_encrypt_password: click.echo("User encrypt password is missing") - sys.exit(12) + sys.exit(SnmpUserError.EncryptPasswordMissingFailure) elif user_encrypt_password: if not snmp_user_secret_check(user_encrypt_password): - click.echo("Bad user encrypt password") - sys.exit(13) + sys.exit(SnmpUserError.EncryptPasswordFailsComplexityRequirements) snmp_users = db.cfgdb.get_table("SNMP_USER") if user in snmp_users.keys(): click.echo("SNMP user {} is already configured".format(user)) - sys.exit(14) + sys.exit(SnmpUserError.UserAlreadyConfigured) else: if not user_auth_type: user_auth_type = '' @@ -2575,6 +2583,7 @@ def add_user(db, user, user_type, user_permission_type, user_auth_type, user_aut click.echo("Restart service snmp failed with error {}".format(e)) raise click.Abort() + @user.command('del') @click.argument('user', metavar='', required=True) @clicommon.pass_db @@ -2595,7 +2604,6 @@ def del_user(db, user): click.echo("Restart service snmp failed with error {}".format(e)) raise click.Abort() - # # 'bgp' group ('config bgp ...') # diff --git a/tests/config_snmp_test.py b/tests/config_snmp_test.py index 56b5086d59..10da903bff 100644 --- a/tests/config_snmp_test.py +++ b/tests/config_snmp_test.py @@ -141,7 +141,7 @@ def test_config_snmp_community_add_new_community_with_invalid_type(self): result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["add"], ["Everest", "RT"]) print(result.exit_code) assert result.exit_code == 1 - assert 'SNMP type must be RO or RW and not RT' in result.output + assert 'Invalid community type. Must be either RO or RW' in result.output def test_config_snmp_community_add_invalid_community_over_32_characters(self): runner = CliRunner() @@ -198,7 +198,7 @@ def test_config_snmp_community_replace_existing_community_with_new_community(sel assert db.cfgdb.get_entry("SNMP_COMMUNITY", "Everest") == \ expected_snmp_community_replace_existing_community_with_new_community_output - def test_config_snmp_community_replace_existing_community_does_not_exist(self): + def test_config_snmp_community_replace_existing_community_non_existing_community(self): runner = CliRunner() result = runner.invoke(config.config.commands["snmp"].commands["community"].commands["replace"], ["Denali", "Everest"]) @@ -247,7 +247,7 @@ def test_config_snmp_contact_modify_without_contact_redis(self): result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["modify"], ["blah", "blah@contoso.com"], obj=db) print(result.exit_code) - assert result.exit_code == 2 + assert result.exit_code == 3 assert 'Contact name blah is not configured' in result.output assert db.cfgdb.get_entry("SNMP", "CONTACT") == {} @@ -290,8 +290,19 @@ def test_config_snmp_contact_add_with_existing_contact(self): assert result.exit_code == 1 assert 'Contact already exists. Use sudo config snmp contact modify instead' in result.output + def test_config_snmp_contact_add_invalid_email(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["add"], + ["testuser", "testusercontoso.com"], obj=db) + print(result.exit_code) + assert result.exit_code == 2 + assert "Contact email testusercontoso.com is not valid" in result.output + + # Delete snmp contact tests - def test_config_snmp_contact_del_without_existing_contact(self): + def test_config_snmp_contact_del_new_contact_when_contact_exists(self): db = Db() runner = CliRunner() with mock.patch('utilities_common.cli.run_command') as mock_run_command: @@ -365,6 +376,43 @@ def test_config_snmp_contact_modify_contact_and_email_with_existing_entry(self): assert result.exit_code == 1 assert 'SNMP contact testuser testuser@contoso.com already exists' in result.output + def test_config_snmp_contact_modify_existing_contact_with_invalid_email(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["add"], + ["testuser", "testuser@contoso.com"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_contact_add_del_new_contact + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {"testuser": "testuser@contoso.com"} + + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["modify"], + ["testuser", "testuser@contosocom"], obj=db) + print(result.exit_code) + assert result.exit_code == 2 + assert 'Contact email testuser@contosocom is not valid' in result.output + + + def test_config_snmp_contact_modify_new_contact_with_invalid_email(self): + db = Db() + runner = CliRunner() + with mock.patch('utilities_common.cli.run_command') as mock_run_command: + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["add"], + ["testuser", "testuser@contoso.com"], obj=db) + print(result.exit_code) + print(result.output) + assert result.exit_code == 0 + assert result.output == config_snmp_contact_add_del_new_contact + assert db.cfgdb.get_entry("SNMP", "CONTACT") == {"testuser": "testuser@contoso.com"} + + result = runner.invoke(config.config.commands["snmp"].commands["contact"].commands["modify"], + ["blah", "blah@contoso@com"], obj=db) + print(result.exit_code) + assert result.exit_code == 2 + assert 'Contact email blah@contoso@com is not valid' in result.output + # Add snmp location tests def test_config_snmp_location_add_exiting_location_with_same_location_already_existing(self): db = Db() @@ -521,8 +569,10 @@ def test_config_snmp_user_add_invalid_user_type(self): result = runner.invoke(config.config.commands["snmp"].commands["user"].commands["add"], ["test_nopriv_RO_3", "nopriv", "ro"]) print(result.exit_code) + print(result) + print(result.output) assert result.exit_code == 2 - assert 'User type nopriv is invalid. Must be noauthnopriv, authnopriv, or priv' in result.output + assert "Invalid user type. Must be one of these one of these three 'noauthnopriv' or 'authnopriv' or 'priv'" in result.output def test_config_snmp_user_add_invalid_permission_type(self): runner = CliRunner() @@ -530,7 +580,7 @@ def test_config_snmp_user_add_invalid_permission_type(self): ["test_nopriv_RO_3", "noauthnopriv", "ab"]) print(result.exit_code) assert result.exit_code == 3 - assert 'User permission type AB is invalid. Must be RO or RW' in result.output + assert "Invalid community type. Must be either RO or RW" in result.output def test_config_snmp_user_add_user_type_noauthnopriv_with_unnecessary_auth_type(self): runner = CliRunner() @@ -538,8 +588,7 @@ def test_config_snmp_user_add_user_type_noauthnopriv_with_unnecessary_auth_type( ["test_nopriv_RO_3", "noauthnopriv", "ro", "sha"]) print(result.exit_code) assert result.exit_code == 4 - assert "User auth type not used with 'noAuthNoPriv'. Please use 'AuthNoPriv' or 'Priv' instead" \ - in result.output + assert "User auth type not used with 'noAuthNoPriv'. Please use 'AuthNoPriv' or 'Priv' instead" in result.output def test_config_snmp_user_add_user_type_authnopriv_missing_auth_type(self): runner = CliRunner() @@ -620,7 +669,7 @@ def test_config_snmp_user_add_invalid_auth_type(self): ["test_nopriv_RO_3", "authnopriv", "ro", "DM5", "user_auth_pass"]) print(result.exit_code) assert result.exit_code == 6 - assert 'User auth type DM5 is invalid. Must be MD5, SHA, or HMAC-SHA-2' in result.output + assert "Invalid user authentication type. Must be one of these 'MD5', 'SHA', or 'HMAC-SHA-2'" in result.output def test_config_snmp_user_add_missing_auth_password(self): runner = CliRunner() @@ -636,7 +685,7 @@ def test_config_snmp_user_add_invalid_encrypt_type(self): ["test_nopriv_RO_3", "priv", "ro", "SHA", "user_auth_pass", "EAS", "user_encrypt_pass"]) print(result.exit_code) assert result.exit_code == 11 - assert 'User encryption type EAS is invalid. Must be DES or AES' in result.output + assert "Invalid user encryption type. Must be one of these two 'DES' or 'AES'" in result.output def test_config_snmp_user_add_missing_encrypt_password(self): runner = CliRunner() @@ -812,3 +861,4 @@ def test_config_snmp_user_del_invalid_user(self): def teardown_class(cls): print("TEARDOWN") os.environ["UTILITIES_UNIT_TESTING"] = "0" + From b603da0c4cf1fe4336d267bc3f54d690588b18d6 Mon Sep 17 00:00:00 2001 From: tsvanduyn Date: Mon, 3 May 2021 23:30:59 +0000 Subject: [PATCH 5/6] updated for requested changes --- config/main.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/config/main.py b/config/main.py index bad820b944..d5c82caa1e 100644 --- a/config/main.py +++ b/config/main.py @@ -2091,8 +2091,7 @@ def is_valid_community_type(commstr_type): def is_valid_user_type(user_type): convert_user_type = {'noauthnopriv': 'noAuthNoPriv', 'authnopriv': 'AuthNoPriv', 'priv': 'Priv'} - user_types = ['noauthnopriv', 'authnopriv', 'priv'] - if user_type not in user_types: + if user_type not in convert_user_type.keys(): message = ("Invalid user type. Must be one of these one of these three " "'noauthnopriv' or 'authnopriv' or 'priv'") click.echo(message) @@ -2513,9 +2512,10 @@ def add_user(db, user, user_type, user_permission_type, user_auth_type, user_aut if not snmp_username_check(user): sys.exit(SnmpUserError.NameCheckFailure) user_type = user_type.lower() - if not is_valid_user_type(user_type)[0]: + user_type_info = is_valid_user_type(user_type) + if not user_type_info[0]: sys.exit(SnmpUserError.TypeNoAuthNoPrivOrAuthNoPrivOrPrivCheckFailure) - user_type = is_valid_user_type(user_type)[1] + user_type = user_type_info[1] user_permission_type = user_permission_type.upper() if not is_valid_community_type(user_permission_type): sys.exit(SnmpUserError.RoRwCheckFailure) From 7ec26a1f51896c69d8f266ba706734153feacbec Mon Sep 17 00:00:00 2001 From: tsvanduyn Date: Tue, 4 May 2021 18:53:45 +0000 Subject: [PATCH 6/6] updated to add addition tests --- config/main.py | 2 +- tests/config_snmp_test.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/config/main.py b/config/main.py index d5c82caa1e..0d620c622e 100644 --- a/config/main.py +++ b/config/main.py @@ -2091,7 +2091,7 @@ def is_valid_community_type(commstr_type): def is_valid_user_type(user_type): convert_user_type = {'noauthnopriv': 'noAuthNoPriv', 'authnopriv': 'AuthNoPriv', 'priv': 'Priv'} - if user_type not in convert_user_type.keys(): + if user_type not in convert_user_type: message = ("Invalid user type. Must be one of these one of these three " "'noauthnopriv' or 'authnopriv' or 'priv'") click.echo(message) diff --git a/tests/config_snmp_test.py b/tests/config_snmp_test.py index 10da903bff..1be2704e47 100644 --- a/tests/config_snmp_test.py +++ b/tests/config_snmp_test.py @@ -7,6 +7,8 @@ import clear.main as clear import config.main as config +import pytest + from unittest import mock from unittest.mock import patch from utilities_common.db import Db @@ -857,6 +859,12 @@ def test_config_snmp_user_del_invalid_user(self): assert result.exit_code == 1 assert 'SNMP user test_nopriv_RO_2 is not configured' in result.output + @pytest.mark.parametrize("invalid_email", ['test@contoso', 'test.contoso.com', 'testcontoso@com', + '123_%contoso.com', 'mytest@contoso.comm']) + def test_is_valid_email(self, invalid_email): + output = config.is_valid_email(invalid_email) + assert output == False + @classmethod def teardown_class(cls): print("TEARDOWN")