Skip to content

Commit 71fb3a4

Browse files
authored
dcnm_maintenance_mode: Ready for review (#296)
* ApiEndpoints(): endpoints for common controller operations * ControllerFeatures(): Retrieve feature information from the controller * FabricTypes(): add fabric_type to feature mapping FabricTypes(): add a mapping from fabric_type to the feature name required to be enabled on the controller to support fabric_type. FabricTypes().feature_name - property to retrieve the feature_name required to be enabled on the controller given FabricTypes().fabric_type. For example: instance = FabricTypes() instance.fabric_type = "VXLAN_EVPN" feature = instance.feature_name # returns "vxlan" * Verify controller feature is enabled for fabric_type dcnm_fabric.py: Modify Merged() and Replaced() classes to leverage ControllerFeatures() and FabricTypes() to verify that appropriate feature is enabled on the controller prior to initiating operations on a given fabric. * Remove debug message * FabricDelete().register_result(): fabric_name needs to be upper-case * dcnm_fabric IT: Add dcnm_fabric_merged_basic_ipfm * dcnm_fabric IT: Add dcnm_tests.yaml with approprate vars Includes all vars required for the test cases listed. * dcnm_fabric IT: Add notes regarding controller config * Update unit tests to reflect addition of IPFM fabric type * Standardize API endpoint definition and access Standardize how API endpoints are defined and accessed. 1. Create a hierarchical directory structure as follows (we can decide if we want to follow the controller API exactly or not, below parallels exactly): module_utils/common/api module_utils/common/api/v1 module_utils/common/api/v1/configtemplate module_utils/common/api/v1/elastic_service module_utils/common/api/v1/event module_utils/common/api/v1/fm module_utils/common/api/v1/imagemanagement module_utils/common/api/v1/lan_discovery module_utils/common/api/v1/lan_fabric module_utils/common/api/v1/pmn etc... module_utils/common/api/v2 etc... API endpoint definition will then follow the controller's hierarchy per above. Starting with two endpoint classes for v1/fm with this commit. * dcnm_fabric IT: Add dcnm_fabric_merged_save_deploy_ipfm Also, add leaf_1 and leaf_2 vars. leaf_1 is needed for IPFM IT leaf _1 and leaf_2 are needed for VXLAN_EVPN and LAN_CLASSIC IT. * dcnm_fabric IT: Add dcnm_fabric_replaced_save_deploy_ipfm Also, update comments in other IT regarding nxos credentials. * ControllerFeatures(): run thru black and isort * Run api endpoint classes thru black, isort, pylint * ControllerFeatures(): Add unit tests, 100% coverage * dcnm_fabric: Update docs with IPFM fabric parameters * dcnm_fabric: fix PEP8 and doc errors * Add EXTRA_CONF_LEAF param in EXAMPLES section Just to make the example a bit more interesting... * dcnm_endpoints: Initial lan-fabric endpoints Additions: plugins/module_utils/api/v1/lan_fabric.py plugins/module_utils/api/v1/rest/control/fabrics.py Modifications plugins/module_utils/api/common_api.py - Add ConversionUtils() instance * Subclasses can define mandatory properties, more Fabrics(): add path property FabricsDelete(): new class for fabric delete endpoint FabricsDetails(): inherit path property from Fabrics() * Rename classes and files * Fabrics: Refactor, update docstrings, add endpoints. 1. Update all Fabrics subclass docstrings for consistency of content and format. 2. Add Raises section to all Fabrics subclass docstrings. 3. Refactor subclass.path into Fabrics().path_fabric_name which is added to, as needed, in subclasses 4. Add the following endpoints: - EpFabricConfigSave - EpFabricFreezeMode * Consistent docstring structure. 1. Add Endpoint section to all docstrings. 2. Modify all previously-unmodified docstrings for consistency. 3. Run thru black, isort, pylint. * Rename v1_common (V1Common) to common_v1 (CommonV1) * dcnm_endpoints: Add stagingmanagement, imagemanagement v1/__init__.py v1/image_management.py - ImageManagement() v1/rest/staging_management.py - StagingManagement() - EpStageImage() - EpStageInfo() - EpValidateImage() v1/rest/image_upgrade.py - ImageUpgrade() - EpInstallOptions() - EpUpgradeImage() * dcnm_endpoints: Add ImageMgmt endpoints /api/v1/imagemanagement/rest/imagemgnt - ImageMgmt() - EpBootFlashInfo() * image_mgmt.py rename to image_mgnt.py to parallel NDFC * Rename staging_management classes EpStageImage() -> EpImageStage() EpValidateImage() -> EpImageValidate() * dcnm_endpoints: Add policy_mgnt endpoint classes * dcnm_endpoints: Add UT, more... 1. Add unit tests for the following: - staging_management - policy_mgnt - image_upgrade - image_mgnt 2. Rename docstring Endpoint section to Path, throughout. 3. Add Verb section to docstrings throughout. 4. Move Raises section in docstrings to directly after Description throughout. 5. ControllerFeatures(): Modify to align with renamed EpFeatures() class. * dcnm_endpoints: Add UT for Fabrics, more... 1. Add unit tests for module_utils/common/api/v1/rest/control/fabrics.py 2. Modify property error messages for consistency. * dcnm_endpoints: docstring consistency across classes * dcnm_endpoints: Add endpoints + UT, more... 1. Add the following endpoints: - Fabrics(). EpFabricCreate() - Fabrics(). EpFabricUpdate() - Switches().EpFabricSummary() 2. Add UT for the above. 3. FabricTypes().valid_fabric_template_names: New property * dcnm_endpoints: Add configtemplate endpoints + UT * Fix PEP8 issues, import error test_controller_features.py was trying to import the old name, Features, for renamed class EpFeatures. * Fix PEP8 no line at end of file, and f-string issue * Fabrics().EpFabrics() new endpoint Also modify all usage examples to use "instance" for the instantiated class name. * FabricDetails(): Leverage EpFabrics() endpoint class 1. import EpFabrics, remove import for ApiEndpoints 2. FabricDetails().__init__(): replace instantiation of self.endpoints with self.ep_fabrics 3. FabricDetails().refresh_super() use EpFabrics() class for endpoint info. 4. Update associated unit tests. * FabricDetails(): run through black, isort, pylint * FabricConfigDeploy(): Use EpFabricConfigDeploy() endpoint class 1. import EpFabricConfigDeploy, remove import for ApiEndpoints 2. FabricConfigDeploy().__init__(): replace instantiation of self.endpoints with self.ep_config_deploy 3. FabricConfigDeploy().commit() use EpFabricConfigDeploy() class for endpoint info. 4. Update associated unit tests. * FabricConfigSave(): Use EpFabricConfigSave() endpoint class 1. import EpFabricConfigSave, remove import for ApiEndpoints 2. FabricConfigSave().__init__(): replace instantiation of self.endpoints with self.ep_config_save 3. FabricConfigSave().commit() use EpFabricConfigSave() class for endpoint info. 4. Update associated unit tests. 5. test_fabric_config_deploy.py: remove unused imports and update docstrings * FabricCreateCommon(): Use EpFabricCreate() 1. import EpFabricConfigSave, remove import for ApiEndpoints 2. FabricCreateCommon().__init__(): replace instantiation of self.endpoints with self.ep_fabric_create 3. FabricCreateCommon()._set_fabric_create_endpoint() use EpFabricCreate() class for endpoint info. 4. Update associated unit tests. 5. test_fabric_create_common.py: Add unit tests to bring FabricCreateCommon() UT coverage to 97% 6. test_fabric_config_deploy.py: rename EpFabricConfigDeploy() to MockEpFabricConfigDeploy() * FabricDelete: use EpFabricDelete() class 1. delete.py: Remove import for ApiEndpoints 2. delete.py: Add import for EpFabricDelete 3. FabricDelete.__init__(): remove self._endpoints instantiation 4. FabricDelete.__init__(): Add self.ep_fabric_delete = EpFabricDelete() 5. FabricDelete._set_fabric_delete_endpoint(): Modify to use self.ep_fabric_delete 6. Modify unit tests to reflect above changes. 7. Add integration test: dcnm_fabric_deleted_basic_ipfm and use to verify the above changes. * FabricSummary: Use EpFabricSummary(), more... 1. Add Fabrics().EpFabricSummary() class 2. FabricSummary: use EpFabricSummary() class 3. fabric_summary.py: Remove import for ApiEndpoints 4. fabric_summary.py: Add import for EpFabricSummary 5. FabricSummary.__init__(): remove self.endpoints instantiation 6. FabricSummary.__init__(): Add self.ep_fabric_summary = EpFabricSummary() 7. FabricSummary. _set_fabric_summary_endpoint(): Modify to use self.ep_fabric_summary 8. Modify unit tests to reflect above changes. * FabricReplacedCommon: use EpFabricUpdate(), more... 1. FabricReplacedCommon(): use EpFabricUpdate() instead of ApiEndpoints() for endpoint resolution. 2. test_fabric_replaced_bulk.py: Update unit tests to reflect 1 above. 3. test_fabric_summary.py: Fix import of EpFabricSummary 4. fabric_summary.py: Fix import of EpFabricSummary 5. Add integration test: dcnm_fabric_replaced_basic_ipfm 6. Update playbooks/roles/dcnm_fabric/dcnm_tests.yaml * Fabrics(): Remove EpFabricSummary() This class is already in Switches() where is properly belongs. Added a comment in /rest/control/fabrics.py directing future maintainers to /rest/control/switches.py * Align api.v1.* with NDFC REST API documentation Modify endpoint classes to align hierarchically with NFDC REST API docs. We have taken a couple liberties with class names for naming consistency, but the directory structure is now identical to the REST API docs. Modify dcnm_fabric modules and unit tests to import the classes from the new locations. * Fix empy-init errors * TemplateGetAll(): use EpTemplates() 1. TemplateGetAll(): use EpTemplates() for endpoint resolution 2. TemplateGetAll(): Modify rest_send, and results properties not to need RestSend() and Results() classes when verifying their input values. Remove RestSend() and Results() imports. * TemplateGet(): use EpTemplate() 1. TemplateGet(): use EpTemplate() for endpoint resolution 2. TemplateGet(): Modify rest_send, and results properties not to need RestSend() and Results() classes when verifying their input values. Remove RestSend() and Results() imports. * ControllerVersion(): Use EpVersion 1. ControllerVersion(): Use EpVersion for endpoint resolution. 2. ControllerVersion(): remove module docstring for consistency with other modules. 3. test_controller_version.py: run through black, isort, pylint. * FabricUpdateCommon(): Use EpFabricUpdate() 1. FabricUpdateCommon(): use EpFabricUpdate() for endpoint resolution. 2. test_fabric_updatee_bulk.py: Update unit tests to reflect 1 above. * dcnm_fabric: Remove ApiEndpoints() class This commit completely removes legacy endpoint resolution from the dcnm_fabric module. 1. Remove module_utils/fabric/endpoints.py 2. Remove unit tests for the above 3. Remove ApiEndpoints import from remaining dcnm_fabric files. - dcnm_fabric.py - test_template_get.py - test_template_get_all.py * Remove RestSend and Results import requirement Remove requirement that RestSend and Results be imported merely to verify rest_send and results properties. 1. FabricConfigDeploy(): Modify rest_send, and results properties not to need RestSend() and Results() classes when verifying their input values. Remove RestSend() and Results() imports. 2. FabricConfigSave(): Modify rest_send, and results properties not to need RestSend() and Results() classes when verifying their input values. Remove RestSend() and Results() imports. 3. ControllerFeatures(): modify rest_send setter for consistency with other classes. 4. Modify associated UT to reflect the above changes. * dcnm_fabric: IPFM, update FabricTypes() unit tests for IPFM. * FabricReplacedCommon().update_replaced_payload(): Simplify logic 1. FabricReplacedCommon().update_replaced_payload(): Simplify logic. I've run this through a test script with data representing all possible combinations, and the results for the original and simplified methods are the same. 2. test_fabric_replaced_bulk.py: Add one more combination to input test parameters. These should now be complete. 3. FabricTypes(): alphabetize _fabric_type_to_feature_map dict by key for easier readability. * FabricReplacedCommon().update_replaced_payload(): Further logic simplification * FabricReplacedCommon().update_replaced_payload(): docstring update Modify the docstring to remove mention of raising ValueError since this method no longer raises ValueError. * EpFabricConfigDeploy(): add switch_id property This will be useful for the dcnm_maintenance_mode module. - Add switch_id property - Update docstrings * Remove files associated with unpublished NDFC REST API path These files were related to an unpublished NDFC REST API path that we won't be using. Unpublished path: /api/v1/rest/* Published path: /api/v1/lan_fabric/rest/* * dcnm_maintenance_mode: Initial commit 1. Add dcnm_maintenance_mode.py - main module 2. Add module_utils/common/switch_details.py - This is a fork of existing SwitchDetails() with AnsibleModule dependency removed. 3. Results(): Update docstrings with Markdown formatting. 4. ParamsValidate(): Update docstrings with Markdown formatting. 5. MaintenanceMode(): New class to enable/disable switch maintenance mode. 6. ControllerResponseError(): Add a class docstring. 7. Add /api/v1/lan_fabric/rest.inventory/inventory.py 8. EpMaintenanceModeEnable(): Added to /api/v1/lan_fabric/rest/control/fabrics/fabrics.py 9. EpMaintenanceModeDisable(): Added to /api/v1/lan_fabric/rest/control/fabrics/fabrics.py * dcnm_maintenance_mode: Add to test/sanity/ignore-* * Fix PEP8 errors, more... 1. Query() was treating self.want as a dict instead of as a list. * Modify diff to indicate what mode was entered. Previously the diff looked like: ```json { "ip_address": "172.22.150.107", "maintenance_mode": "OK", "sequence_number": 1 } ``` Changed it to indicate the mode the switch was changed to. ```json { "ip_address": "172.22.150.107", "maintenance_mode": "normal", "sequence_number": 1 } ``` * SwitchDetails(): add maintenance_mode property maintenance_mode is synthesized from mode and system_mode. mode: NDFC's current configuration for the switch's systemMode system_mode: The switch's current running state for systemMode. When mode and system_mode differ, NDFC reports this (in a private API) as "inconsistent". maintenance_mode is intended to mimick the behavior of NDFC's private API. maintenance_mode will return "inconsistent if mode != system_mode. maintenance_mode will otherwise return mode (i.e. NDFC's current state for the switch's system mode) * SwitchDetails(): compare values using lower() * MaintenanceMode(): implement config-deploy 1. import EpFabricConfigDeploy. 2. Add a deploy property. 3. Add method deploy_switch() and call from commit() if deploy is True. 4. Refactor commit() to move parameter validation to verify_commit_parameters() 5. Improve some docstrings. 6. EpFabricConfigDeploy(): Update docstring Usage section to include switch_id. * Use SwitchDetails().maintenance_mode property 1. dcnm_maintenance_mode.py 1. get_have() change mode key to maintenance_mode in self.have to reflect that we are accessing SwitchDetails().maintenance_mode property 2. Merged().get_need() change mode key to maintenance_mode in self.need so that it's more clear that we are working with maintenance mode rather than some other mode. * RestSend(): improve docstrings * Handle "inconsistent" and "migration" states. * Handle non-existent switch case. * General error handling improvements, more... 1. SwitchDetails().refresh(): Catch and re-raise ValueError if mandatory parameters are not set. 2. ParamsSpec().params setter: Raise ValueError if value is not a dict. 3. Common().__init__(): Catch ParamsSpec().params ValueError and call fail_json() if self.params is invalid. 4. SwitchDetails(): Remove unused json import. * Implement query state. 1. Common().get_have(): Move method to Merged() 2. Merged().get_have(): Added from Common() and slightly modified. 3. Query().get_have(): New method - differs from Merged().get_have() in that it doesn't call fail_json() if mode is "inconsistent" or "migration". 4. main(): remove commented code. * Bulk per-fabric config-deploy 1. MaintenanceMode(): modify to accept a list of config dicts and process all switches simultaneously, as opposed to one at a time. This was needed because it takes way too long to config-deploy each switch individually. 2. Fabrics().EpFabricsConfigDeploy(): Modify to access a list for switch_id. 3. Merged().send_need(): Modify to align with the rewritten MaintenanceMode() class. * MaintenanceMode().change_system_mode() simplify, more... 1. MaintenanceMode().change_system_mode(): We originally thought that the maintenance-mode endpoint supported bulk update via comma-separate list of serial_number (similar to config-deploy). It doesn't. However, changing system mode is a very fast operation and so initiating this per-switch is not time consuming. Reverted change_system_mode() back to its original (simpler) implementation; plus a few enhancements. 2. Updated class docstring to include detailed information about what exceptions are raised for each public-facing property and method. 3. Add ControllerResponseError exceptions to change_system_mode() and deploy_switches() with useful error messages. 4. Reorder build_deploy_dict() to be closer to the method that uses it; deploy_switches(). 5. Remove unused imports 6. Remove unused vars * Error handling, and query state content. 1. Merged(): Remove role key from self.have. 2. Merged(): fail_json() if switch is in inconsistent or migration states. 3. Merged(): fail_json() if fabric freezeMode is enabled for a switch's hosting fabric. 4. Query(): Add freezeMode state to query result diff with key deployment_disabled and value of True or False. 5. SwitchDetails(): Add freeze_mode property. * Handle read-only fabrics, more... All changes in this commit are within dcnm_maintenance_mode.py 1. Common().__init__: Remove several things that require AnsibleModule to be set and add them to parts of the code where AnsibleModule has already been set. 2. Throughout: Add try-except blocks around vulnerable calls. 3. Common(), Merge(), Query(): replace calls to fail_json() with exceptions and catch these in main() 4. freezeMode (returned by .../allswitches endpoint) is set to null for read-only LAN_Classic fabrics. Hence, we cannot use it for this (and maybe other) fabric type(s). Leverage FabricDetailsByName() and raise exception if IS_READ_ONLY == True for a switch's hosting fabric. 5. For all methods, add a Raises section to their docstrings indicating if and when they raise exceptions, and what type of exceptions are raised. 6. Query().__init__(): Change input parameter from ansible_module to params. 7. main(): else statement was using task.ansible_module, but there would be no instantiate task here. Fixed. * Query(): Update deployment_disabled for read-only fabrics. This commit changes only dcnm_maintenance_mode.py Query(): In the case of LAN_Classic fabrics (and perhaps other fabric types), leverage FabricDetailsByName() and reference fabric parameter IS_READ_ONLY to determine if the fabric is read-only. Update "deployment_disabled" to True if either IS_READ_ONLY == True or freezeMode == True. Previously, we were updating "deployment_disable" only in the case of freezeMode == True. * SwitchDetails(): Improve docstrings 1. Add Raises section to all method docstrings. 2. For all properties that call SwitchDetails()._get(), add a note in the docstring that the property can potentially raise ValueError. * SwitchDetails(): Fix PEP8 whitespace in blank line * api: Add unit tests Add unit tests for the following classes: - EpFabricConfigDeploy - EpFabrics - EpMaintenanceModeDisable - EpMaintenanceModeEnable - Fabrics * Fix PEP8 errors, more... Unit tests failed because I forgot to add modified api fabrics.py that the UT were testing :-( * Rename api unit test files to reflect the endpoint path Naming the files to directly match the endpoint path. This should make it easier to identify the corrent file to modify in the future. * MaintenanceMode(): Various cleanup, more... 1. MaintenanceMode().verify_config_parameters(): combine calls into single try-except block. 2, MaintenanceMode().change_system_mode(): combine calls into single try-except block. 3. MaintenanceMode().deploy_switches(): combine calls into single try-except block. 4. Remove commented code. 5. Update docstrings for several methods to indicate more precisely what exceptions are raised and for what reasons. * Harden error handling Common() raises ValueError if params does not contain required keys or if the value of required keys are None. Merge()__init__() and Query().__init__() need to catch this. Also, in main() move Merge() and Query() class instantiation into the try-except block. * MaintenanceMode: initial unit tests * test_maintenance_mode_00120: update, more... 1. test_maintenance_mode_00120: update missing checks 2. MaintenanceMode(): remove temporary debug statements * Deprecate common classes requiring AnsibleModule 1. Deprecate the following common classes that have AnsibleModule dependency. - MergeDicts() - merge_dicts.py - ParamsMergeDefaults() - params_merge_defaults.py - ParamsValidate() - params_validate.py 2. Add versions of the above that are not dependent on AnsibleModule. - MergeDicts() - merge_dicts_v2.py - ParamsMergeDefaults() - params_merge_defaults_v2.py - ParamsValidate() - params_validate_v2.py 3. Copied v1 unit tests and modified for the v2 versions. Over time, modules using the deprecated versions (dcnm_image_upgrade, dcnm_image_policy, dcnm_fabric) can be transitioned to the v2 versions. MaintenanceMode() is now using the v2 versions. * Fix PEP8 errors, more... 1. Fix PEP8 errors from the last commit. 2. Common().get_want(): Add try-except block around Want(). * dcnm_maintenance_mode: remove deprecated imports 1. dcnm_maintenance_mode.py: Remove deprecated (PEP 585) imports from typing since our minimum Python version is now 3.9. 2. Want().want: Change type hint to list instead of Dict[str, Any] 3. Want().params_spec.setter: Do not require instance of ParamsSpec to validate input. 3. Want().validator.setter: Implement input validation. 4. Merged().get_need(): Raise ValueError if switch does not exist. 5. ParamsValidate() (v2)._ipaddress_guard(): Modify TypeError message to include the pretty name for the type. 6. ParamsValidate() (v2).parameters setter: Modify TypeError message to include the pretty name for the type. 7. Update unit tests to reflect the above changes. * Want().want: Fix type hint * MaintenanceMode: Add type hints, more... 1. MaintenanceMode: Add method return value type hints 2. MaintenanceMode: In several properties and methods, raise TypeError rather than ValueError if type is invalid. 3. MaintenanceMode: Update docstrings Below, Want() is in modules/dcnm_maintenance_mode.py 4. Want(): In several properties and methods, raise TypeError rather than ValueError if type is invalid. 5. Want(): Update docstrings 6. test_maintenance_mode_00110: Fix docstring * MaintenanceModeInfo: new class, more... 1. In module_utils/common/maintenance_mode.py - MaintenanceModeInfo: New class to retrieve maintenance mode info. 2. In dcnm_maintenance_mode.py - Merge().get_have(): Rewrite to leverage MaintenanceModeInfo() - Query().get_have(): Rewrite to leverage MaintenanceModeInfo() * RestSend() v2. New class, more... 1. rest_send_v2.py - RestSend(): New class that leverages dependency injection to remove all dependencies on AnsibleModule. 2. rest_send_v2.py - RestSend().save_settings() new method to save current setting of check_mode and timeout. 3. rest_send_v2.py - RestSend().restore_settings() new method to restore saved setting of check_mode and timeout. 4. dcnm_sender.py: Sender() - injected into RestSend(). Sender() uses dcnm_send(), and hence, AnsibleModule, but hides these from RestSend(). In the future, RestSend() could use a different Sender() that, say, uses the Requests module. 5. SwitchDetails(): Modify to use rest_send_v2.py 6. MaintenanceMode(): Modify to use rest_send_v2.py * Remove unused imports After the previous commit, SwitchDetails() and FabricDetails() are no longer needed in dcnm_maintenance_mode.py, since they've been moved to MaintenanceMode() and MaintenanceModeInfo(). * Abstract response handling Abstract response handling by defining a "response handler" interface. Leverage this abstraction in RestSend() version 2. 1. module_utils/common/response_handler.py: Implementation of the response handler interface. See the docstring for ResponseHandler() in this file for interface details. 2. module_utils/common/rest_send_v2.py: Leverage the response handler interface and remove concrete local response handling methods. 3. dcnm_maintenance_mode.py: Modifiy RestSend() instantiation to include injection of the ResponseHandler() class. * ResultHandler(): Update unit tests 1. Update unit tests to expect TypeError when input to result.setter and response.setter is not a dict. * RestSend() v2: Update usage sections of docstring * Hardening and docstring updates module_utils/common/dcnm_send.py: - Update class docstring Raises section to include all exceptions that should be caught. - Update class docstring Usage section to include appropriate try-except block. - Update commit() docstring Raises section to remove AnsibleModule.fail_json() and add all cases where exceptions might be reaised. rest_send_v2.py: - commit_normal_mode(): - Update docstring Raises section. - Add try-except block around _verify_commit_parameters() - Add try-except block around sender.commit() * MockSender(): mock the Sender() class 1. MockSender(): mock the Sender() class to return simulated responses. We added a gen property to set the generator 2. test_maintenance_mode.py - Update to use MockSender() rather than mocking dcnm_send() 3. test_maintenance_mode.py - Update to import RestSend() version 2 since this is what MaintenanceMode() is using. 4. test_maintenance_mode.py - renumber test case 00120 to 00220. 5. MaintenanceMode(): Change a few error messages for consistency. * MaintenanceMode(): add/update unit tests. 1. MaintenanceMode().deploy: Update error message. 2. test_maintenance_mode_00220: - update to test normal mode as well. 3. test_maintenance_mode_00400 - Verify MaintenanceMode().verify_config_parameters() re-raises - ``ValueError`` if: - ``deploy`` raises ``TypeError`` 4. test_maintenance_mode_00500: - Verify MaintenanceMode().verify_config_parameters() re-raises - ``ValueError`` if: - ``fabric_name`` raises ``ValueError`` due to being an invalid value. 5. test_maintenance_mode_00600: - Verify MaintenanceMode().verify_config_parameters() re-raises - ``ValueError`` if: - ``mode`` raises ``ValueError`` due to being an invalid value. * Log() version 2. Simplify usage. 1. Log(): new version 2 class. This simplifies usage within our main module files to two lines: log = Log() log.commit() 2. Log(): Add a 'develop' property to enable exceptions from the logging system itself. By default, this is disabled (False). 3. Log(): Ensure that the logging config file does not specify any logging handers that emit to console, stderr, stdout (since these latter two could be redirected to the console). 4. Log(): Update docstring with usage examples and an example logging config file. 5. dcnm_maintenance_mode.py: Use the Log() version 2 class. * Log() v2: 96% unit test coverage * Log() v2: Error handling improvements. 1. Log(): Update error messages for consistency. 2. Log().validate_logging_config(): Simply logic to raise exception if the logging config contains any handlers not in self.valid_handlers. 3. Log().validate_logging_config(): Raise ValueError if no handlers are found in the logging config file. * MaintenanceMode(): Add unit test test_maintenance_mode_00700: - Verify MaintenanceMode().change_system_mode() raises ``ValueError`` when ``EpMaintenanceModeEnable`` or ``EpMaintenanceModeDisable`` raise any of: - ``TypeError`` - ``ValueError`` * MaintenanceMode: Add unit test test_maintenance_mode_00230: - Verify commit() unsuccessful case: - RETURN_CODE == 500. - commit raises ``ValueError`` when change_system_mode() raises ``ControllerResponseError``. - Controller response contains expected structure and values. * dcnm_maintenance_mode: Hardening 1. Merged().send_need(): Wrap MaintenanceMode() in try-except block. 2. Merged().get_have(): Wrap MaintenanceModeInfo() in try-except block. 3. Query().get_have(): Wrap MaintenanceModeInfo() in try-except block. 4. MaintenanceMode(): Update class docstring. * Log() v2: Fix class docstring issues. 1. Log() v2: Add TypeError to class docstring Raises section. 2. Log() v2: Fix indentation in class docstring. Most lines were indented one extra space. * Fix Results() update to remove duplicate result and response The following classes were incorrectly updating Results() with duplicated entries for result and response keys. FabricDetails() SwitchDetails() * FabricDetails(): Backout last commit (only for FabricDetails) FabricDetails() has dependent code that does not like the change made in the last commit. I'll copy FabricDetails() to module_utils/common and make the changes in the copied version. The existing code within dcnm_fabric can remain as-is and we can modify it to use the new FabricDetails() from module_utils/common later. * Results().did_anything_change(): return False if state == query Results().did_anything_change(): Update conditional. BACKGROUND: Previously, Results().did_anything_change() returned False only when self.action == "query". This is wrong. It's worked up until now because existing modules set Results().action to "query". However, action is intended to be a freeform string that describes what action was taken, so could be any string depending on what future modules set it to. The conditional should have been: if self.state == "query" CHANGES: Modified the conditional to be: if self.action == "query" or self.state == "query" TODO: We should remove self.action from the conditional after testing that existing modules still work correctly after it's been removed. For now, we can leave self.action in the conditional, since it's unlikely that self.action will be set specifically to "query" for future modules that make changes to the controller. * Results(): raise TypeError instead of ValueError 1. Results(): modify all properties to raise TypeError instead of ValueError when they are passed unexpected types. 2. tests/unit/modules/dcnm/dcnm_image_policy/test_image_policy_common.py: Modify test cases to assert for TypeError instead of ValueError * MaintenanceMode: use RestSend() v2, more... 1. test_maintenance_mode.py: Modify to reflect changes to MaintenanceMode() 2. dcnm_maintenance_mode.py: Query(): Modify the Results() update - Add a custom response. - Change action to "maintenance_mode_info" 3. FabricDetails() v2. New class in module_utils/fabric to eventually replace FabricDetails() v1. 4. SwichDetails(): Update docstrings. Rename validate_commit_parameters() to validate_refresh_parameters() 5. SwichDetails(): Wrap RestSend() and Results() in try-except blocks. 6. SwichDetails(): Update rest_send and results properties to raise TypeError if not passed instances of RestSend() and Results(), respectively. 7. RestSend() v2: Update docstrings. 8. MaintenanceMode(): Use RestSend() v2 9. MaintenanceModeInfo(): Use RestSend() v2 * FabricDetails() v2: 49% unit test coverage. 1. FabricDetails()__init__() v2: improve error messages when check_mode and state are missing from params. 2. FabricDetails() v2: Initial batch of unit tests. * Use class decorators to remove duplicated code 1. Properties(): New class containing: a. properties shared by many classes. b. class decorator wrapper methods 2. MaintenanceMode(): Replace rest_send and results properties with decorators. 3. MaintenanceModeInfo(): Replace rest_send and results properties with decorators. 4. test_maintenance_mode.py: Update unit tests to reflect the above. * Fix several item assignments MaintenanceModeInfo(): In converting this class to use _var rather than properties["var"], I forgot a few occurances. Cleaned this up. * SwitchDetails(): inject rest_send and results with class decorators SwitchDetails(): Remove rest_send and results and inject from Properties() class. SwitchDetails(): Update class docstrings for consistency. * FabricDetails() v2: inject rest_send and results with class decorators FabricDetails(): Remove rest_send and results and inject from Properties() class. FabricDetails(): Update class docstrings for consistency. Properties(): Fix missing space in rest_send error message. * FabricDetails() v2: Fix PEP8 too many blank lines Also, add the following to elide no-member error reporting: # pylint: disable=no-member * MaintenanceModeInfo(): Move to maintenance_mode_info.py For cases where we just need to query the maintenance mode state, we can save some imports by moving MaintenanceModeInfo() to a separate file. Moving classes into separate files also helps with editing tasks like search/replace and lessens the likelihood of editing the wrong class. * Common(): inject rest_send with class decorator dcnm_maintenance_mode.py: 1. Common(): inject rest_send property from Properties(). 2. main(): isolate AnsibleModule to the top of the function. 3. Merged().commit(): raise ValueError if rest_send is not set. 4. Query().commit(): raise ValueError if rest_send is not set. * MaintenanceMode: 94% unit test coverage 1. test_maintenance_mode_00220: - Modify to test for deploy == False and deploy == True in addition to mode tests. - Now tests the following cases: - mode == maintenance, deploy == False - mode == maintenance, deploy == True - mode == normal, deploy == False - mode == normal, deploy == True 2. test_maintenance_mode_00800: - Verify MaintenanceMode().change_system_mode() raises ``ValueError`` when ``MaintenanceMode().results()`` raises any of: - ``TypeError`` - ``ValueError`` 3. dcnm_maintenance_mode.py: use params in error message rather than ansible_module.params * FabricDetails() v2: Hardening. FabricDetails().__init__() can potentially raise ValueError. Hence, need to catch this exception, per below. - FabricDetailsByName(): Wrap super()..__init__() in try-except block. - FabricDetailsByNvPair(): Wrap super()..__init__() in try-except block. * FabricDetails() v2: More hardening. FabricDetails().refresh_super() can potentially raise ValueError. Hence, need to catch this exception, per below. - FabricDetailsByName().refresh(): Wrap self.super_refresh() in try-except block. - FabricDetailsByNvPair(): Wrap self.super_refresh() in try-except block. * MaintenanceMode(): 100% unit test coverage MaintenanceMode().__init__(): instantiate EpFabricConfigDeploy() so it becomes a testable attribute for test case test_maintenance_mode_00800. MaintenanceMode().deploy_switch(): Add a period (.) to the end of ControllerResponseError message to improve the corresponding unit test regex to cover the whole message. Renamed test case: test_maintenance_mode_00800 -> test_maintenance_mode_00900 Added the following test cases: test_maintenance_mode_00800: - Verify MaintenanceMode().deploy_switches() raises ``ValueError`` when ``EpFabricConfigDeploy`` raises any of: - ``TypeError`` - ``ValueError`` test_maintenance_mode_01000: - Verify MaintenanceMode().commit() raises ``ValueError`` when ``MaintenanceMode().deploy_switches()`` raises ``ControllerResponseError`` when the RETURN_CODE in the response is not 200. * MaintenanceModeInfo: 49% unit test coverage 1. test_maintenance_mode_info.py: initial unit tests. 2. test_mainteance_mode.py: organize asserts alphabetically. 3. common_utils.py: Add fixtures and responses for MaintenanceModeInfo() 4. SwitchDetails: self.conversions should be self.conversion. * Forgot to add the mocks in the last commit. Test cases were failing due to missing mocks. * MockSwitchDetails(): Remove pylint not-callable Missed this one in the last commit. * Mock*(): Remove pylint disable= statements Didn't notice the "pylint disable=" statements at the top of each file which were copy/pasted from one of the unit test files where they are needed. * MaintenanceModeInfo(): 64% unit test coverage, more... 1. MockSwitchDetails(): Populate properties from responses_SwitchDetails.json if mock_response_key is set. MockSwitchDetails().filter must be set to an IP address prior to setting mock_response_key. 2. MockSwitchDetails(): Update getters and setters to raise mock_exception if mock_class and mock_property match the getter/setter criteria. 3. MockFabricDetailsByName(): Update getters and setters to raise mock_exception if mock_class and mock_property match the getter/setter criteria. 4. MaintenanceModeInfo(): Remove some debug logs. * MaintenanceModeInfo: 81% unit test coverage. MockFabricDetailsByName(): call from refresh() if mock_response_key isn't None. MockFabricDetailsByName(): add _get() method and mock_response_key property. MockSwitchDetails(): call from refresh() if mock_response_key isn't None. MockSwitchDetails().populate_mocked_properties(): remove. Replace with _get(). MockSwitchDetails() add ability to throw exception from any property. * sender_file.py Sender(): New class to simulate controller responses DISCUSSION: Sender(), in sender_file.py, implements the sender interface. It is injected into RestSend() v2. RestSend() has no knowledge of how controller responses are retrieved, as long as the sender interface is conformed to. Hence, the rest of the code base (that uses RestSend) can be unit tested without having to mock anything. The actual code is tested, rather than mocks. 1. dcnm_sender.py - rename to sender_dcnm.py for consistency with sender_file.py. Future Sender() classes, e.g. that leverage Requests, would be named e.g. sender_requests.py, etc. 2. test_maintenance_mode_info.py: Converted all test cases to use the above. 3. MockSwitchDetails(): Modified to mock ONLY the exceptions raised by SwitchDetails. It no longer duplicates the functionality of Sender(). 4. dcnm_maintenance_mode.py: Changed import to use sender_dcnm. 5. module_utils/common/sender_file.py: New file 6. module_utils/common/sender_dcnm.py: Update docstring. 7. module_utils/common/rest_send_v2.py: Update docstring. 8. module_utils/common/maintenance_mode_info.py: Update docstring. * MockSender(): Remove MockSender() was a test implementation of sender_file.py Sender(). Removed this, in favor of Send() from sender_file.py, in the following files: 1. tests/unit/module_utils/common/common_utils.py 2. tests/unit/module_utils/common/test_maintenance_mode.py 3. tests/unit/modules/dcnm/dcnm_fabric/test_fabric_details_v2.py * RestSend(), FabricDetails(): Update docstrings 1. Update the docstrings in the v2 version of these classes. 2. FabricDetails().register_result(): Add try-except block around results update. * MockFabricDetailsByName: Mock exceptions only. 1. MockFabricDetailsByName(): Modified to mock ONLY the exceptions raised by MockFabricDetailsByName. It no longer duplicates the functionality of Sender(). * MaintenanceModeInfo: 81% unit test coverage 1. MaintenanceModeInfo: Add negative test 00310- switch serialNumber key in controller response is null, or missing. 2. MaintenanceModeInfo: Update testcase 00300 docstring to clarify difference with 00310. 3. MaintenanceModeInfo(): Update ValueError message with more detail. This is the message tested by testcase 00310. * MaintenanceModeInfo: Fix fabric_read_only property assignment 1. MaintenanceModeInfo(): property was being assigned the value of fabric_freeze_mode. Fixed. 2. MaintenanceModeInfo: Add unit test 00600, which verifies fabric_read_only is True if nvPairs.IS_READ_ONLY is true. 3. MaintenanceModeInfo: Fix assert for fabric_read_only value in unit test 00510. 4. responses_FabricDetailsByName.json: Remove unused fixture test_maintenance_mode_info_00210a 5. responses_FabricDetailsByName.json: Add fixture test_maintenance_mode_info_00600a. 6. responses_SwitchDetails.json: Add fixture for test_maintenance_mode_info_00600a. * MaintenanceModeInfo().__init__(): initialize self._filter, more... 1. MaintenanceModeInfo(): self._filter was not being set in __init__(). Fixed. 2. SwitchDetails().role: Update docstring to clarify that role is an alias of switch_role. 3. MaintenanceModeInfo: Add the following unit tests: - test_maintenance_mode_info_00700: Verify role is set to "na" when switchRole is null in the controller response. - test_maintenance_mode_info_00800: Verify get() raises ValueError if filter is not set. * MaintenanceModeInfo: 89% unit test coverage 1. test_maintenance_mode_info_00810a: Verify ``get()`` raises ``ValueError`` if ``filter`` (switch IP) is not found in the controller response when the user accesses a property. 2. test_maintenance_mode_info_00820: Verify ``refresh`` re-raises ``ValueError`` raised by ``SwitchDetails()._get()`` when ``item`` is not found in the controller response. In this, case ``item`` is ``freezeMode``. * MaintenanceModeInfo: 94% unit test coverage 1. test_maintenance_mode_info_00900: Verify ``config`` raises ``TypeError`` when set to an invalid type. 2. test_maintenance_mode_info_00910: Verify ``config`` raises ``TypeError`` when an element in the list is not a ``str`` * MaintenanceModeInfo: 100% unit test coverage. 1. MaintenanceModeInfo: Add ip_address as a key in the info dict i.e. info[ip_address]["ip_address"] 2. Add the following test cases: - test_maintenance_mode_info_01000: Verify ``info`` raises ``ValueError`` when accessed before ``refresh()`` is called. - test_maintenance_mode_info_01010 Verify ``info`` returns expected information in the happy path. * FabricDetails() v2: 43% unit test coverage. Added the following test cases: 1. test_fabric_details_v2_00130 Verify refresh_super() behavior when RETURN_CODE is 500. 2. test_fabric_details_v2_00140 Verify refresh_super() raises ``ValueError when ``register_result()`` raises ``ValueError``. * FabricDetails() v2: unit test coverage 47% Add the following test cases: - test_fabric_details_v2_00150 Verify refresh_super() behavior when ``rest_send`` is not set. - test_fabric_details_v2_00160 Verify refresh_super() behavior when ``results`` is not set. - test_fabric_details_v2_00170 Verify refresh_super() raises ``ValueError`` when ``rest_send`` raises ``TypeError``. * FabricDetails: 76% unit test coverage 1. dcnm_fabric/utils.py: Add fixture and response reader for fabric_details_by_name_v2 2. test_fabric_details_by_name_v2.py - Add the following test cases - test_fabric_details_by_name_v2_00200: Verify property access after 200 controller response - test_fabric_details_by_name_v2_00300: Verify properties return None if property is missing in the controller response. * FabricDetails: 78% unit test coverage 1. test_fabric_details_by_name_v2_00000 Verify that refresh() raises ``ValueError`` if ``refresh_super()`` raises ``ValueError`` * FabricDetails: 79% unit test coverage 1. Add testcase: test_fabric_details_by_name_v2_00400 Verify refresh() raises ``ValueError`` if ``FabricDetails().refresh_super()`` raises ``ValueError``. 2. test_fabric_details_by_name_v2.py: Remove unused imports EpFabrics, ConversionUtils. * FabricDetailsByName: 81% unit test coverage 1. Added test cases: - test_fabric_details_by_name_v2_00500a Verify ``_get_nv_pair()`` raises ``ValueError`` if ``filter`` is not set prior to accessing a property. 2. Updated docstrings for other test cases for accuracy. * Update sanity/ignore-2.[15,16].txt Added to both: plugins/modules/dcnm_maintenance_mode.py validate-modules:missing-gplv3-license # GPLv3 license header not found in the first 20 lines of the module * fabric_details_v2.py: 84% unit test coverage 1. Added the following test cases: - test_fabric_details_by_name_v2_00510a Verify that property getters for ``nvPairs`` items return ``None`` when ``_get_nv_pair()`` raises ``ValueError`` because fabric does not exist. - test_fabric_details_by_name_v2_00600 Verify that ``filtered_data`` property getter raises ``ValueError`` when ``filter`` is not set. - test_fabric_details_by_name_v2_00610 Verify that ``filtered_data`` property returns expected values when ``filter`` is set and matches a fabric on the controller. 2. FabricDetailsByName().filtered_data.getter: Modify error message. * fabric_details_v2.py: 87% unit test coverage 1. Add the following test cases test_fabric_details_by_name_v2_00700a Verify that property getters for top-level items return ``None`` when ``_get()`` raises ``ValueError`` because ``filter`` is not set prior to accessing a property. test_fabric_details_by_name_v2_00710 Verify that property getters for top-level items return ``None`` when ``_get()`` raises ``ValueError`` because fabric does not exist. * fabric_details_v2.py: 95% unit test coverage 1. FabricDetailsByNvPair(): fix docstring to move refresh() to the right place (must be called AFTER setting filter_key and filter_value. 2. Add the following test cases: - test_fabric_details_by_nv_pair_v2_00000 Verify that __init__ raises ``ValueError`` if ``super().__init__`` raises ``ValueError`` - test_fabric_details_by_nv_pair_v2_00200 Verify nvPair access after 200 controller response. * fabric_details_v2.py: 100% unit test coverage 1. FabricDetailsByNvPair(): If no fabrics exist (len self.data == 0), set results before returning. 2. Add the following test cases. - test_fabric_details_by_nv_pair_v2_00210a Verify behavior when FABRIC_NAME is missing from nvPairs. (negative test case) - test_fabric_details_by_nv_pair_v2_00400 Verify refresh() raises ``ValueError`` if ``FabricDetails().refresh_super()`` raises. - test_fabric_details_by_nv_pair_v2_00600 Verify that ``refresh()`` raises ``ValueError`` when ``filter_key`` is not set. test_fabric_details_by_nv_pair_v2_00610 Verify that ``refresh()`` raises ``ValueError`` when ``filter_value`` is not set. * sender_dcnm.py: 66% unit test coverage. 1. sender_dcnm.py: covert properties dict to individual private vars. 2. sender_dcnm.py: Sender().commit(): wrap _verify_commit_parameters() in try-exept block. 3. module_utils/common/common_utils.py: add fixtures and response functions for sender_dcnm and sender_file. 4. test_sender_dcnm.py: initial test cases. - test_sender_dcnm_00000 Class properties are initialized to expected values - test_sender_dcnm_00100 Verify ``commit()`` re-raises ``ValueError`` when ``_verify_commit_parameters()`` raises ``ValueError`` due to ``ansible_module`` not being set. - test_sender_dcnm_00110 Verify ``commit()`` re-raises ``ValueError`` when ``_verify_commit_parameters()`` raises ``ValueError`` due to ``path`` not being set. - test_sender_dcnm_00120 Verify ``commit()`` re-raises ``ValueError`` when ``_verify_commit_parameters()`` raises ``ValueError`` due to ``verb`` not being set. * sender_dcnm.py: 100% unit test coverage. 1. Sender().__init__(): initialize self._dcnm_send for easier unit test patching. 2. Sender(): modify property error messages for consistency. 3. Add the following test cases. - test_sender_dcnm_00200 Verify ``commit()`` populates ``response`` with expected values for ``verb`` == POST and ``payload`` == None. - test_sender_dcnm_00210 Verify ``commit()`` populates ``response`` with expected values for ``verb`` == POST and ``payload`` != None. - test_sender_dcnm_00300 Verify ``ansible_module.setter`` raises ``TypeError`` if passed something other than an AnsibleModule() instance. - test_sender_dcnm_00400 Verify ``payload.setter`` raises ``TypeError`` if passed something other than a ``dict``. - test_sender_dcnm_00500 Verify ``response.setter`` raises ``TypeError`` if passed something other than a ``dict``. - test_sender_dcnm_00600 Verify ``verb.setter`` raises ``ValueError`` if passed an invalid value (not one of DELETE, GET, POST, PUT). * sender_file.py: 100% unit test coverage. 1. Add unit tests for sender_file.py. 2. test_sender_dcnm.py: fix assert in test 00000. 3. test_response_handler.py: Align with ResponseHandler() changes. 4. ResponseHandler(): use dunder vars for private vars, rather than dict. 5. sender_dcnm.py: Minor error message cleanup. 6. sender_file.py: Sender().commit() catch ValueError raised by _validate_commit_parameters() 6. sender_file.py: Sender().gen() raise TypeError if input value does not support response_generator interface. 6. module_utils/common/common_utils.py: ResponseGenerator() add implements property that returns a string representing the interface that is implemented. * Remove duplicate ResponseGenerator class ResponseGenerator() was located in both the following locations: - tests/unit/modules/dcnm/dcnm_fabric/utils.py - tests/unit/module_utils/common/common_utils.py We changed RsponseGenerator() to include an "implements" property, which broke all the unit tests that were using the copy that didn't include this property. Modified all the unit test file imports to point to the copy in common_utils.py and removed the other copy in utils.py. * RestSend() v2: 73% unit test coverage Add the following unit tests: - test_rest_send_v2_00000 Verify class properties are initialized to expected values - test_rest_send_v2_00100 Verify ``_verify_commit_parameters()`` raises ``ValueError`` due to ``path`` not being set. - test_rest_send_v2_00110 Verify ``_verify_commit_parameters()`` raises ``ValueError`` due to ``response_handler`` not being set. - test_rest_send_v2_00120 Verify ``_verify_commit_parameters()`` raises ``ValueError`` due to ``response_handler`` not being set. - test_rest_send_v2_00130 Verify ``_verify_commit_parameters()`` raises ``ValueError`` due to ``response_handler`` not being set. * RestSend() v2: 81% unit test coverage Add the following test case: - test_rest_send_v2_00200 Verify ``commit_check_mode()`` happy path. * RestSend().commit(): Catch and re-raise exceptions 1. RestSend().commit(): v2. Catch exceptions thrown by commit_check_mode() and commit_normal_mode() and re-raise them as ValueError with message indicating commit() is in the call stack. 2. Update unit tests to reflect the modified error message. * RestSend() v2: 83% unit test coverage. Add the following test cases. - test_rest_send_v2_00210 Verify ``commit_check_mode()`` happy path when ``verb`` is "POST". - test_rest_send_v2_00500 Verify ``check_mode.setter`` raises ``TypeError`` when set to inappropriate types, and does not raise when set to boolean. 2. RestSend(): Tweak check_mode error message. * RestSend() v2: 84% unit test coverage. 1. Added the following testcase. - test_rest_send_v2_00600 Verify ``response_current.setter`` raises ``TypeError`` when set to inappropriate types, and does not raise when set to dict. 2. RestSend().response_current.setter: tweaked error message to use method_name rather than hardcoded string. * RestSend() v2: 88% unit test coverage. 1. Added the following test cases - test_rest_send_v2_00700 Verify ``response.setter`` raises ``TypeError`` when set to inappropriate types, and does not raise when set to dict. - test_rest_send_v2_00800 Verify ``result_current.setter`` raises ``TypeError`` when set to inappropriate types, and does not raise when set to dict. - test_rest_send_v2_00900 Verify ``result.setter`` raises ``TypeError`` when set to inappropriate types, and does not raise when set to dict. 2. RestSend() v2: Tweak error messages. * RestSend() v2: 89% unit test coverage, more... 1. ResponseHandler().implements: Property to return the implemented interface string. 2. RestSend().response_hendler: Modify property to check that the correct interface is implemented. 3. test_rest_send_v2.py: Renumber test cases: test_rest_send_v2_00800 -> test_rest_send_v2_00900 test_rest_send_v2_00900 -> test_rest_send_v2_01000 Add test cases: - test_rest_send_v2_00800 Verify ``response_handler.setter`` raises ``TypeError`` when set to inappropriate types, and does not raise when set to a class that implements the response_handler_v1 interface. * RestSend v2: 90% unit test coverage. 1. Add the following test cases - test_rest_send_v2_00220 Verify ``commit_check_mode()`` sad path when ``response_handler.commit()`` raises ``ValueError``. * sender_file.py: Add ability to simulate exceptions * RestSend() v2: 92% unit test coverage. Added the following test cases. - test_rest_send_v2_00300 Verify ``commit_normal_mode()`` happy path when ``verb`` is "POST" and ``payload`` is set. - test_rest_send_v2_00310 Verify ``commit_normal_mode()`` sad path when ``Sender().commit()`` raises ``ValueError``. * RestSend().send_interval: Need to check for bool RestSend().send_interval: In validating the input, we need to check for bool type first. * Fix invalid escape. * RestSend() v2: 93% unit test coverage. Added the following test cases: - test_rest_send_v2_01100 Verify ``send_interval.setter`` raises ``TypeError`` when set to inappropriate types, and does not raise when set to integer. * Add "implements" property to several classes. Add an "implements" property to the following classes: - Response_Handler() - RestSend() v2 - Sender() (sender_dcnm.py) - Sender() (sender_file.py) * RestSend() v2: property assignment modifications RestSend() v2: remove self.properties in favor of _property. * RestSend().commit_normal_mode(): remove unneeded try-except * RestSend() v2: 95% unit test coverage. 1. RestSend(): Fix two error messages. 2. Add the following test cases. - test_rest_send_v2_00320 Verify ``commit_normal_mode()`` sad path when ``response_handler.commit()`` raises ``ValueError``. - test_rest_send_v2_01200 Verify ``failed_result.getter`` returns dictionary with expected key/values. - test_rest_send_v2_01300 Verify ``implements.getter`` returns expected string. 3. Modify the following testcase. - test_rest_send_v2_00320 Modify match to reflect change in RestSend() error message. * RestSend() remove unneeded method RestSend()._strip_invalid_json_from_response_data() didn't work and wasn't all that useful. Removing it for now. * RestSend() v2: 96% unit test coverage. 1. RestSend().sender: Validate based on "implements" property. 2. Add the following test cases. - test_rest_send_v2_01400 - Verify ``sender.setter`` raises ``TypeError`` when set to anything other than a class that implements sender_v1. - Verify that ``sender.getter`` returns Sender() class when properly set. * RestSend() v2: 99% unit test coverage. 1. RestSend(): Tweak validations for the following properties: - timeout - unit_test - verb 2. Add the following test cases: - test_rest_send_v2_01500 Verify ``timeout.setter`` raises ``TypeError`` when set to inappropriate types, and does not raise when set to integer. - test_rest_send_v2_01600 Verify ``unit_test.setter`` raises ``TypeError`` when set to inappropriate types, and does not raise when set to boolean. - test_rest_send_v2_01700 - Verify ``verb.setter`` raises ``TypeError`` when set to non-string types. - Verify ``verb.setter`` raises ``ValueError`` when set to inappropriate values. - Verify that ``verb.setter`` does not raise when set to one of "DELETE", "GET", "POST", or "PUT". * SwitchDetails(): 75% unit test coverage. Added the following test cases: - test_switch_details_00000 Verify class properties are initialized to expected values - test_switch_details_00100 Verify ``validate_refresh_parameters()`` raises ``ValueError`` due to ``rest_send`` not being set. - test_switch_details_00110 Verify ``validate_refresh_parameters()`` raises ``ValueError`` due to ``results`` not being set. * SwitchDetails(): Fix potential KeyError on non-200 response 1. SwitchDetails().refresh(): For non-200 responses, if DATA is empty, a KeyError would be thrown when trying to access "ipAddress" for each switch. Fixed by testing for "ipAddress" existence before access. 2. SwitchDetails(): updated docstring Usage section. * SwitchDetails(): 85% unit test coverage. Added the following test cases: - test_switch_details_00200 Verify ``refresh()`` happy path. - test_switch_details_00300 Verify ``refresh()`` sad path where 500 response is returned. * SwitchDetails(): 91% unit test coverage. 1. SwitchDetails().update_results(): Fix conditional. results.failed is a set(), and so the conditional needed to be changed to test set() membership for True. This was causing ControllerResponseError() not to be raised in cases where it should be raised. 2. Add the following unit tests. - test_switch_details_00400 Verify ``refresh()`` catches ``ValueError`` raised by ``send_request()`` when ``Sender()`` is configured to raise ``ValueError``. 3. Modify the following unit tests. - test_switch_details_00300 Modify the expected error message. * SwitchDetails(): 93% unit test coverage. Added the following test cases. - test_switch_details_00500 Verify ``_get()`` raises ``ValueError`` if ``filter`` is not set before accessing properties that use ``_get()``. * SwitchDetails(): 94% unit test coverage. 1. SwitchDetails().update_results(): update error message to give better visibility into its origin. 2. Rename the following testcase: test_switch_details_00500 -> test_switch_details_00600 2. Add the following testcases: - test_switch_details_00500 Verify ``refresh()`` catches and re-raises ``ValueError`` raised by ``update_results()``. 3. RestSend() v2: run thorugh black and isort. * SwitchDetails(): 99% unit test coverage. Add the following test cases. - test_switch_details_00700 Verify ``maintenance_mode`` raises ``ValueError`` if ``mode`` is ``null`` in the controller response. - test_switch_details_00710 Verify ``maintenance_mode`` raises ``ValueError`` if system_mode is ``null`` in the controller response. - test_switch_details_00720 Verify ``maintenance_mode`` returns "migration" if mode == "Migration" in the controller response. - test_switch_details_00730 Verify ``maintenance_mode`` returns "inconsistent" if mode != system_mode in the controller response. - test_switch_details_00740 Verify ``maintenance_mode`` returns "maintenance" if ``mode == "Maintenance" and ``system_mode`` == "Maintenance" in the controller response. - test_switch_details_00750 Verify ``maintenance_mode`` returns "normal" if mode == "Normal" and system_mode == "Normal" in the controller response. - test_switch_details_00800 Verify ``platform`` returns ``None`` if model == ``null`` in the controller response. - SwitchDetails().maintenance_mode: Tweak error messages. * Initial integration test DESCRIPTION - merged_normal_to_maintenance State: merged Test: Change normal mode switches to maintenance mode with config-deploy. * MaintenanceMode(): Fix deploy endpoint MaintenanceMode(): The deploy endpoint needed to have query-string added to instruct NDFC to wait until deploy finished before continuing: /fabrics/{fabric_name}/switches/{serial_number}/deploy-maintenance-mode?waitForModeChange=true * dcnm_maintenance_mode: inconsistent mode, change handling. The changes in this commit were needed because config-deploy cannot be used for deploying maintenance mode. Rather deploy-maintenance-mode endpoint must be used with the query-string waitForModeChange set to true. Also, because deploy-maintenance-mode is optional, it is expected that switch mode could be "inconsistent". Previously, we raised an error in this situation. Removed this error. 1. Changed the following unit tests: - test_maintenance_mode_00220 - changed to yield response from response_DeployMaintenanceMode.json - check results for deploy case only if deploy == True - expect action == deploy_maintenance_mode rather than config_deploy - test_maintenance_mode_00800 - Mock EpMaintenanceModeDeploy rather than EpFabricConfigDeploy - yield a second response with RETURN_CODE == 200 and MESSAGE == OK - change expected error message. 2. tests/unit/module_utils/common/common_utils.py - Remove responses_config_deploy - Add responses_deploy_maintenance_mode 3. dcnm_maintenance_mode.py - Merged(): Remove raise ValueError if mode == "inconsistent" 4. maintenance_mode.py - build_endpoints(): new method - deploy_switches(): refactor out functionality in build_endpoints() - Use dict self.endpoints rather than endpoint object. This was required to allow mocking of the endpoint object. - deploy_switches(): modify error message if RETURN_CODE != 200 5. api/v1/lan_fabric/rest/control/fabrics/fabrics.py - Add property wait_for_mode_change to allow setting of waitForModeChange query string. 6. Add playbooks/roles/dcnm_maintenance_mode/* 7. Modify playbooks/roles/dcnm_fabric/* to be specific to the dcnm_fabric role. * Add wait_for_mode_change playbook parameter Expose playbook parameter wait_for_mode_change. Default is currently false (which aligns with the NDFC GUI), but we can change this easily if needed. 1. test_maintenance_mode.py: Add wait_for_mode_change to CONFIG shared by unit tests. 2. tests/integration/targets/dcnm_maintenance_mode/*.yaml : Restructure tests. 3. dcnm_maintenance_mode.py: Update the following to handle wait_for_mode_change: - DOCUMENTATION - EXAMPLES - ParamsSpec() - Merged().get_need() * Fix validate-modules DOCUMENTATION error. * Same fix as last commit, but for switch-level. * Merged().get_need(): Update docstring Merged().get_need(): Update docstring to include wait_for_mode_change in example JSON structure. * MaintenanceMode: Add unit tests, wait_for_mode_change All changes are in test_maintenance_mode.py - renumber unit tests to position wait_for_mode_change test in logical order. - Add test case test_maintenance_mode_00700 for wait_for_mode_change. - Modify test_maintenance_mode_00310 to include wait_for_mode_change. * dcnm_maintenance_mode.py: 47% unit test coverage, more... 1. tests/unit/modules/dcnm/dcnm_maintenance_mode/* - Add initial set of tests, fixtures, and utils 2. dcnm_maintenance_mode.py - Update DOCUMENTATION 3. dcnm_maintenance_mode.py - ParamsSpec() - Add choices for mode - Add defaults for deploy, mode, wait_for_mode_change 4. dcnm_maintenance_mode.py - Common() - Update Raises section of docstring for __init__() - __init__(): raise ValueError…
1 parent cc92275 commit 71fb3a4

File tree

117 files changed

+27157
-346
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

117 files changed

+27157
-346
lines changed

playbooks/roles/dcnm_fabric/dcnm_tests.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
---
2-
# This playbook can be used to execute the dcnm_fabric test role.
2+
# This playbook can be used to execute integration tests for
3+
# the role located in:
34
#
45
# Modify the vars section with details for testing setup.
56
#
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
all:
2+
vars:
3+
ansible_user: "admin"
4+
ansible_password: "password-secret"
5+
ansible_python_interpreter: python
6+
ansible_httpapi_validate_certs: False
7+
ansible_httpapi_use_ssl: True
8+
children:
9+
dcnm:
10+
vars:
11+
ansible_connection: ansible.netcommon.httpapi
12+
ansible_network_os: cisco.dcnm.dcnm
13+
hosts:
14+
dcnm-instance.example.com:
15+
nxos:
16+
hosts:
17+
n9k-hosta.example.com:
18+
ansible_connection: ansible.netcommon.network_cli
19+
ansible_network_os: cisco.nxos.nxos
20+
ansible_ssh_port: 22
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
---
2+
# This playbook can be used to execute integration tests for
3+
# the role located in:
4+
#
5+
# tests/integration/targets/dcnm_maintenance_mode
6+
#
7+
# Modify the vars section with details for your testing setup.
8+
#
9+
# NOTES:
10+
# 1. For the IPFM test cases (dcnm_*_ipfm), ensure that the controller
11+
# is running in IPFM mode. i.e. Ensure that
12+
# Fabric Controller -> Admin -> System Settings -> Feature Management
13+
# "IP Fabric for Media" is checked.
14+
# 2. For all other test cases, ensure that
15+
# Fabric Controller -> Admin -> System Settings -> Feature Management
16+
# "Fabric Builder" is checked.
17+
- hosts: dcnm
18+
gather_facts: no
19+
connection: ansible.netcommon.httpapi
20+
21+
vars:
22+
# See the following location for available test cases:
23+
# tests/integration/targets/dcnm_maintenance_mode/tests
24+
# testcase: 00_setup_fabrics_1x_rw
25+
# testcase: 00_setup_fabrics_2x_rw
26+
# testcase: 01_merged_maintenance_mode_deploy
27+
# testcase: 01_merged_maintenance_mode_no_deploy
28+
fabric_name_1: VXLAN_EVPN_Fabric
29+
fabric_type_1: VXLAN_EVPN
30+
fabric_name_2: VXLAN_EVPN_MSD_Fabric
31+
fabric_type_2: VXLAN_EVPN_MSD
32+
fabric_name_3: LAN_CLASSIC_Fabric
33+
fabric_type_3: LAN_CLASSIC
34+
fabric_name_4: IPFM_Fabric
35+
fabric_type_4: IPFM
36+
leaf_1: 172.22.150.103
37+
leaf_2: 172.22.150.104
38+
nxos_username: admin
39+
nxos_password: myNxosPassword
40+
41+
roles:
42+
- dcnm_maintenance_mode

0 commit comments

Comments
 (0)