Repository: chef/automate
Pull request #7799 (2023-04-03 05:21:23)

Take input of Sudo Password for CLI Commands
### :nut_and_bolt: Description: What code changed, and why?
Added sudo_password support for HA cmd in ruby
<!-- /!\ Please ensure that you are NOT disclosing any customer information without their consent /!\ -->

### :chains: Related Resources
https://chefio.atlassian.net/browse/CHEF-795
https://github.com/chef/automate/pull/7774
### :+1: Definition of Done

### :athletic_shoe: How to Build and Test the Change
- Rebuild `automate-cli` (`rebuild components/automate-cli/`) or can use (`akrishna/automate-cli/0.1.0/20230412082516`), `automate-ha-cluster-ctl` (`rebuild components/automate-cluster-ctl/`) or can use (`akrishna/automate-ha-cluster-ctl/0.1.0/20230411133555`), and `automate-ha-deployment`(`rebuild components/automate-backend-deployment/`) or can use (`akrishna/automate-ha-deployment/0.1.0/20230411141141`).
- Upload the above packages `hab pkg upload <PATH_TO_PACKAGE_HART_FILE>`.
- Create an airgap bundle with new packages `sudo ./chef-automate airgap bundle create -m latest_semver.json --channel dev`. Update this [latest_semver.json](https://packages.chef.io/manifests/dev/automate/latest_semver.json) manifest file with your origins. 
Note: Do not update the `automate-cli` origin in the manifest file,  just install the new `automate-cli` on Bastion.
- Set the environment variable `sudo_password`. For eg. `export sudo_password=1234`.
- Run deployment command with -E flag to preserve environment variable. For eg. `sudo -E ./chef-automate deploy config.toml --airgap-bundle automate-4.5.104.aib`. Refer [here](https://www.petefreitag.com/item/877.cfm) for passing environment variables to the sudo command.
### :white_check_mark: Checklist

**All PRs** must tick these:

- [ ] I have read the [CONTRIBUTING document](https://github.com/chef/automate/blob/master/CONTRIBUTING.md).
- [ ] All commits signed-off for the [Developer Certification of Origin](https://github.com/chef/chef/blob/master/CONTRIBUTING.md#developer-certification-of-origin-dco).

With occasional exceptions, all PRs **from Progress employees** must tick these:

- [ ] Is the code clear? *(complicated code or lots of comments--subdivide and use well-named methods, meaningful variable names, etc.)*
- [ ] Consistency checked? *(user notifications, user prompts, visual patterns, code patterns, variable names)*
- [ ] Repeated code blocks eliminated? *(adapt and reuse existing components, blocks, functions, etc.)*
- [ ] Spelling, grammar, typos checked? *(at a minimum use `make spell` in any component directory)*
- [ ] Code well-formatted? *(indents, line breaks, etc. improve rather than hinder readability)*

All PRs **from Progress employees** should tick these if appropriate:

- [ ] Tests added/updated? (all new code needs new tests)
- [ ] Docs added/updated? (all customer-facing changes)

*Please add a note next to any checkbox above if you are NOT ticking it.*

### :camera: Screenshots, if applicable
![Screenshot 2023-04-12 at 1 42 43 PM](https://user-images.githubusercontent.com/11033984/231395369-6da25e63-ecb8-4969-8507-5a7afef6d480.png)

![Screenshot 2023-04-12 at 1 41 54 PM](https://user-images.githubusercontent.com/11033984/231395292-e5067f01-9652-4c56-a0bc-8c3f2d012a31.png)

Video: https://progresssoftware.sharepoint.com/:v:/s/ChefCoreC/EacHYiZu7aFBgNkiBpoRPwkB0f_Ngkk_CR2vOxTCdbtMfA?e=janCk5


netlify[bot]: ### <span aria-hidden="true">👷</span> Deploy Preview for *chef-automate* processing.


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | ab9c930a44ab377f1f4ea6d5c4f076b457d5778d |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/chef-automate/deploys/642a625679c2a700083b96db |
sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=chef_automate&pullRequest=7799)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=coverage&view=list) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=chef_automate&pullRequest=7799)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=coverage&view=list) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=chef_automate&pullRequest=7799)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=coverage&view=list) No Coverage information  
[![No Duplication information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/NoDuplicationInfo-16px.png 'No Duplication information')](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=duplicated_lines_density&view=list) No Duplication information


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=chef_automate&pullRequest=7799)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL) [![B](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/B-16px.png 'B')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL) [1 Code Smell](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL)

[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/0-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=new_coverage&view=list) [0.0% Coverage](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=new_coverage&view=list)  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=chef_automate&pullRequest=7799)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=chef_automate&pullRequest=7799&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL) [1 Code Smell](https://sonarcloud.io/project/issues?id=chef_automate&pullRequest=7799&resolved=false&types=CODE_SMELL)

[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/0-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=new_coverage&view=list) [0.0% Coverage](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=new_coverage&view=list)  
[![28.6%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/20plus-16px.png '28.6%')](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=new_duplicated_lines_density&view=list) [28.6% Duplication](https://sonarcloud.io/component_measures?id=chef_automate&pullRequest=7799&metric=new_duplicated_lines_density&view=list)



Patch:
diff --git a/.bldr.toml b/.bldr.toml
index c58bc3ae0..6818e031d 100644
--- a/.bldr.toml
+++ b/.bldr.toml
@@ -440,6 +440,7 @@ paths = [
   "components/local-user-service/*",
   "lib/cereal/*",
   "lib/config/*",
+  "lib/config_parser/*",
   "lib/db/*",
   "lib/grpc/*",
   "lib/httputils/*",
@@ -452,12 +453,14 @@ paths = [
   "lib/proc/*",
   "lib/product/*",
   "lib/proxy/*",
+  "lib/reporting/*",
   "lib/secrets/*",
   "lib/stringutils/*",
   "lib/tls/*",
   "lib/tracing/*",
   "lib/user/*",
   "lib/uuid4/*",
+  "lib/verification/*",
   "lib/version/*"
 ]
 
diff --git a/.license_scout.yml b/.license_scout.yml
index afb17194a..7c2c789b4 100644
--- a/.license_scout.yml
+++ b/.license_scout.yml
@@ -329,6 +329,9 @@ fallbacks:
     - name: github.com/apparentlymart/go-textseg
       license_id: Unlicense
       license_content: https://github.com/apparentlymart/go-textseg/blob/master/LICENSE
+    - name: github.com/globalsign/mgo
+      license_id: Unlicense
+      license_content: https://github.com/globalsign/mgo/blob/master/LICENSE
 
   habitat:
     - name: chef/mlsa
diff --git a/VERSION b/VERSION
index f2cd3d3d8..3a92c29fc 100644
--- a/VERSION
+++ b/VERSION
@@ -1,1 +1,1 @@
-4.5.105
\ No newline at end of file
+4.5.110
\ No newline at end of file
diff --git a/components/automate-cli/cmd/chef-automate/automateConstants.go b/components/automate-cli/cmd/chef-automate/automateConstants.go
index 1857cf080..4adc03cca 100644
--- a/components/automate-cli/cmd/chef-automate/automateConstants.go
+++ b/components/automate-cli/cmd/chef-automate/automateConstants.go
@@ -62,6 +62,10 @@ const (
 
 	GET_FRONTEND_CONFIG = `echo "y" | sudo chef-automate config show %s`
 
+	PRE_FLIGHT_CHECK = `cd /tmp;
+	chmod +x chef-automate;
+	sudo ./chef-automate preflight-check --airgap`
+
 	GET_APPLIED_CONFIG = `
 	source <(sudo cat /hab/sup/default/SystemdEnvironmentFile.sh);
 	automate-backend-ctl applied --svc=automate-ha-%s
diff --git a/components/automate-cli/cmd/chef-automate/cmdUtils.go b/components/automate-cli/cmd/chef-automate/cmdUtils.go
index 1c69b9802..7912cf4ea 100644
--- a/components/automate-cli/cmd/chef-automate/cmdUtils.go
+++ b/components/automate-cli/cmd/chef-automate/cmdUtils.go
@@ -128,6 +128,11 @@ func (c *remoteCmdExecutor) executeCmdOnGivenNodes(input *CmdInputs, nodeIps []s
 	inputFileToOutputFileMap := map[string]string{}
 	for _, file := range inputFiles {
 		destinationFile := remoteService + "_" + timestamp + "_" + file
+		if strings.Contains(file, "/") {
+			filePath := strings.Split(file, "/")
+			lastFileidx := len(filePath) - 1
+			destinationFile = filePath[lastFileidx]
+		}
 		inputFileToOutputFileMap[file] = destinationFile
 	}
 
@@ -185,7 +190,7 @@ func (c *remoteCmdExecutor) executeCmdOnNode(command string, inputFiles map[stri
 	}
 
 	output, err := sshUtil.connectAndExecuteCommandOnRemote(command, true)
-	if err != nil {
+	if err != nil && len(output) == 0 {
 		rc.Error = err
 		resultChan <- rc
 		return
@@ -205,9 +210,8 @@ func (c *remoteCmdExecutor) executeCmdOnNode(command string, inputFiles map[stri
 		}
 	}
 
-	if errorCheckEnableInOutput {
-		err = checkResultOutputForError(output)
-	}
+	err = checkIfErrorPresentInOutput(errorCheckEnableInOutput, output)
+
 	if err != nil {
 		rc.Error = err
 		resultChan <- rc
@@ -218,6 +222,13 @@ func (c *remoteCmdExecutor) executeCmdOnNode(command string, inputFiles map[stri
 	resultChan <- rc
 }
 
+func checkIfErrorPresentInOutput(errorCheckEnableInOutput bool, output string) error {
+	if errorCheckEnableInOutput {
+		return checkResultOutputForError(output)
+	}
+	return nil
+}
+
 // preCmdExecCheck will check and execute PreExec function. Also returns nodeips for given remoteservice with error if any.
 func preCmdExecCheck(node *Cmd, sshUtil SSHUtil, infra *AutomteHAInfraDetails, remoteService string, timestamp string, writer *cli.Writer) ([]string, error) {
 	var nodeIps []string
@@ -382,7 +393,9 @@ func appendChildFileToParentFile(hostIp, parent, child string) (string, error) {
 
 // checkResultOutputForError checks If the output contains the word "error" then return error
 func checkResultOutputForError(output string) error {
-	if strings.Contains(strings.ToUpper(strings.TrimSpace(output)), "ERROR") {
+	if strings.Contains(strings.ToUpper(strings.TrimSpace(output)), "ERROR") &&
+		!strings.Contains(strings.ToUpper(strings.TrimSpace(output)),
+			strings.ToUpper("PreflightError: One or more preflight checks failed")) {
 		return errors.New(output)
 	}
 	return nil
diff --git a/components/automate-cli/cmd/chef-automate/config.toml b/components/automate-cli/cmd/chef-automate/config.toml
index afaa61109..0d8d9afd8 100644
--- a/components/automate-cli/cmd/chef-automate/config.toml
+++ b/components/automate-cli/cmd/chef-automate/config.toml
@@ -12,7 +12,6 @@ workspace_path = "/hab/a2_deploy_workspace"
 ssh_user = "centos"
 # private ssh key file path to access instances
 ssh_key_file = "~/.ssh/A2HA.pem"
-# sudo_password = ""
 # logging_monitoring_management = ""
 # new_elk = ""
 # existing_elk_instance_ip ""
diff --git a/components/automate-cli/cmd/chef-automate/genA2haRbTmpl.go b/components/automate-cli/cmd/chef-automate/genA2haRbTmpl.go
index 3f5a28406..c9d9cf8ad 100644
--- a/components/automate-cli/cmd/chef-automate/genA2haRbTmpl.go
+++ b/components/automate-cli/cmd/chef-automate/genA2haRbTmpl.go
@@ -66,7 +66,7 @@ opensearch do
   {{ if .Opensearch.Config.PublicKey }} public_key "{{ .Opensearch.Config.PublicKey }}" {{ else }} # public_key "{{ .Opensearch.Config.PublicKey }}" {{ end }}
   admin_dn "{{ .Opensearch.Config.AdminDn }}"
   nodes_dn "{{ .Opensearch.Config.NodesDn }}"
-  {{ if .Opensearch.Config.CertsByIP }} certs_by_ip  "{ {{ range $index, $element := .Opensearch.Config.CertsByIP}}{{if $index}} \n {{end}} \"{{$element.IP}}\" = { private_key = <<-EOT\n{{$element.PrivateKey}}\nEOT\n\n public_key = <<-EOT\n{{$element.PublicKey}}\nEOT\n\n nodes_dn = <<EOT\n{{$element.NodesDn}}EOT\n } {{end}} }" {{end}}
+  {{ if .Opensearch.Config.CertsByIP }} certs_by_ip  "{ {{ range $index, $element := .Opensearch.Config.CertsByIP}}{{if $index}} \n {{end}} \"{{$element.IP}}\" = { private_key = <<-EOT\n{{$element.PrivateKey}}\nEOT\n\n public_key = <<-EOT\n{{$element.PublicKey}}\nEOT\n\n nodes_dn = <<-EOT\n{{$element.NodesDn}}\nEOT\n } {{end}} }" {{end}}
 end
 
 ###############################################################
diff --git a/components/automate-cli/cmd/chef-automate/pre_flight_check.go b/components/automate-cli/cmd/chef-automate/pre_flight_check.go
index b885c5264..41d8b4172 100644
--- a/components/automate-cli/cmd/chef-automate/pre_flight_check.go
+++ b/components/automate-cli/cmd/chef-automate/pre_flight_check.go
@@ -7,6 +7,7 @@ import (
 	"os"
 	"strings"
 
+	"github.com/pkg/errors"
 	"github.com/spf13/cobra"
 
 	"github.com/chef/automate/api/config/deployment"
@@ -17,12 +18,84 @@ import (
 	"github.com/chef/automate/lib/version"
 )
 
+var preflightCmdFlags = struct {
+	airgap             bool
+	waitTimeout        int
+	configPath         string
+	haDeploymentConfig bool
+	automate           bool
+	chef_server        bool
+	frontend           bool
+	node               string
+}{}
+
+type InfraKeyValues struct {
+	Value []string `json:"value"`
+	Type  []string `json:"type"`
+}
+
+type InfraKeyValue struct {
+	Value string `json:"value"`
+	Type  string `json:"type"`
+}
+
 func init() {
 	preflightCheckCmd.PersistentFlags().BoolVar(
 		&preflightCmdFlags.airgap,
 		"airgap",
 		false,
 		"Pass this flag when the environment is airgapped")
+	preflightCheckCmd.PersistentFlags().BoolVar(
+		&preflightCmdFlags.haDeploymentConfig,
+		"ha-deployment-config",
+		false,
+		"Pass this flag to run pre-flight check on automate-HA")
+	showConfigCmd.PersistentFlags().SetAnnotation("ha-deployment-config", docs.Compatibility, []string{docs.CompatiblewithHA})
+	preflightCheckCmd.PersistentFlags().BoolVar(
+		&preflightCmdFlags.frontend,
+		"fe",
+		false,
+		"Pass this flag to run pre-flight check on all Frontend nodes")
+	showConfigCmd.PersistentFlags().SetAnnotation("fe", docs.Compatibility, []string{docs.CompatiblewithHA})
+	preflightCheckCmd.PersistentFlags().BoolVarP(
+		&preflightCmdFlags.frontend,
+		"frontend",
+		"f",
+		false,
+		"Pass this flag to run pre-flight check on all Frontend nodes")
+	showConfigCmd.PersistentFlags().SetAnnotation("frontend", docs.Compatibility, []string{docs.CompatiblewithHA})
+	preflightCheckCmd.PersistentFlags().BoolVarP(
+		&preflightCmdFlags.automate,
+		"automate",
+		"a",
+		false,
+		"Pass this flag to run pre-flight check on automate node(HA)")
+	showConfigCmd.PersistentFlags().SetAnnotation("automate", docs.Compatibility, []string{docs.CompatiblewithHA})
+	preflightCheckCmd.PersistentFlags().BoolVar(
+		&preflightCmdFlags.automate,
+		"a2",
+		false,
+		"Pass this flag to run pre-flight check on automate node(HA)")
+	showConfigCmd.PersistentFlags().SetAnnotation("a2", docs.Compatibility, []string{docs.CompatiblewithHA})
+	preflightCheckCmd.PersistentFlags().BoolVarP(
+		&preflightCmdFlags.chef_server,
+		"chef_server",
+		"c",
+		false,
+		"Pass this flag to run pre-flight check on chef-server node(HA)")
+	showConfigCmd.PersistentFlags().SetAnnotation("chef_server", docs.Compatibility, []string{docs.CompatiblewithHA})
+	preflightCheckCmd.PersistentFlags().BoolVar(
+		&preflightCmdFlags.chef_server,
+		"cs",
+		false,
+		"Pass this flag to run pre-flight check on chef-server node(HA)")
+	showConfigCmd.PersistentFlags().SetAnnotation("cs", docs.Compatibility, []string{docs.CompatiblewithHA})
+	preflightCheckCmd.PersistentFlags().StringVar(
+		&preflightCmdFlags.node,
+		"node",
+		"",
+		"Pass this flag to run pre-flight check on a perticular node node(HA)")
+	showConfigCmd.PersistentFlags().SetAnnotation("node", docs.Compatibility, []string{docs.CompatiblewithHA})
 	preflightCheckCmd.PersistentFlags().StringVar(
 		&preflightCmdFlags.configPath,
 		"config",
@@ -33,11 +106,6 @@ func init() {
 	preflightCheckCmd.AddCommand(newMigratePreflightCmd())
 }
 
-var preflightCmdFlags = struct {
-	airgap     bool
-	configPath string
-}{}
-
 var preflightCheckCmd = &cobra.Command{
 	Use:   "preflight-check",
 	Short: "Perform preflight check",
@@ -58,6 +126,26 @@ func loadMergedConfigForPreflight() (*deployment.AutomateConfig, error) {
 }
 
 func runPreflightCheckCmd(cmd *cobra.Command, args []string) error {
+	if preflightCmdFlags.haDeploymentConfig {
+		var configPath = ""
+		if len(args) == 0 {
+			return errors.Errorf("Config file should be passed with ha-deployment-config flag")
+		}
+		configPath = args[0]
+		infra, err := getInfraDetails(configPath)
+		if err != nil {
+			return err
+		}
+		nodeMap := constructAndGetNodeMap(infra)
+		cmdUtil := NewRemoteCmdExecutor(nodeMap)
+
+		if preflightCmdFlags.automate || preflightCmdFlags.chef_server || preflightCmdFlags.frontend {
+			err = cmdUtil.Execute()
+		} else {
+			writer.Println(cmd.UsageString())
+		}
+		return err
+	}
 	cfg, err := loadMergedConfigForPreflight()
 	if err != nil {
 		return err
@@ -65,10 +153,28 @@ func runPreflightCheckCmd(cmd *cobra.Command, args []string) error {
 	if err := client.Preflight(writer, cfg, version.BuildTime, preflightCmdFlags.airgap); err != nil {
 		return err
 	}
-
 	return nil
 }
 
+func getInfraDetails(configPath string) (*AutomteHAInfraDetails, error) {
+	var infra *AutomteHAInfraDetails
+	var err error
+	var deploymentType string
+	if isA2HARBFileExist() {
+		infra, err = getAutomateHAInfraDetails()
+	} else {
+		deploymentType, err = getModeFromConfig(configPath)
+		if err != nil {
+			return nil, errors.Errorf("%v", err)
+		}
+		infra, err = getInfraDetailsForDeploymentType(deploymentType, configPath)
+		if err != nil {
+			return nil, errors.Errorf("%v", err)
+		}
+	}
+	return infra, err
+}
+
 var migratePreflightCmdFlags = migrateCmdFlagSet{}
 
 func newMigratePreflightCmd() *cobra.Command {
@@ -344,3 +450,89 @@ func runChefServerChecks(u *a1upgrade.A1Upgrade) error {
 
 	return nil
 }
+
+func populateInfraDetails(config ExistingInfraConfigToml) *AutomteHAInfraDetails {
+
+	var infra AutomteHAInfraDetails
+	infra.Outputs.SSHKeyFile = InfraKeyValue{
+		Value: config.Architecture.ConfigInitials.SSHKeyFile,
+	}
+	infra.Outputs.SSHPort = InfraKeyValue{
+		Value: config.Architecture.ConfigInitials.SSHPort,
+	}
+	infra.Outputs.SSHUser = InfraKeyValue{
+		Value: config.Architecture.ConfigInitials.SSHUser,
+	}
+	infra.Outputs.AutomatePrivateIps = InfraKeyValues{
+		Value: config.ExistingInfra.Config.AutomatePrivateIps,
+	}
+	infra.Outputs.ChefServerPrivateIps = InfraKeyValues{
+		Value: config.ExistingInfra.Config.ChefServerPrivateIps,
+	}
+	return &infra
+}
+
+func getInfraDetailsForDeploymentType(deploymentType string, configPath string) (*AutomteHAInfraDetails, error) {
+	var infra *AutomteHAInfraDetails
+	var err error
+	if deploymentType == EXISTING_INFRA_MODE {
+		config, err := getExistingInfraConfig(configPath)
+		if err != nil {
+			return nil, errors.Errorf("%v", err)
+		}
+		infra = populateInfraDetails(*config)
+	}
+
+	if deploymentType == AWS_MODE {
+		infra, err = getAutomateHAInfraDetails()
+		if err != nil {
+			return nil, errors.Errorf("%v", err)
+		}
+	}
+	return infra, nil
+}
+
+func constructAndGetNodeMap(infra *AutomteHAInfraDetails) *NodeTypeAndCmd {
+	frontendCommand := fmt.Sprint(PRE_FLIGHT_CHECK)
+	inputFilePath := "/usr/bin/chef-automate"
+	nodeMap := &NodeTypeAndCmd{
+		Frontend: &Cmd{
+			CmdInputs: &CmdInputs{
+				Cmd:                      frontendCommand,
+				WaitTimeout:              preflightCmdFlags.waitTimeout,
+				ErrorCheckEnableInOutput: true,
+				Single:                   false,
+				NodeIp:                   preflightCmdFlags.node,
+				InputFiles:               []string{inputFilePath},
+				Outputfiles:              []string{},
+				NodeType:                 preflightCmdFlags.frontend,
+			},
+		},
+		Automate: &Cmd{
+			CmdInputs: &CmdInputs{
+				Cmd:                      frontendCommand,
+				WaitTimeout:              preflightCmdFlags.waitTimeout,
+				ErrorCheckEnableInOutput: true,
+				Single:                   false,
+				NodeIp:                   preflightCmdFlags.node,
+				InputFiles:               []string{inputFilePath},
+				Outputfiles:              []string{},
+				NodeType:                 preflightCmdFlags.automate,
+			},
+		},
+		ChefServer: &Cmd{
+			CmdInputs: &CmdInputs{
+				Cmd:                      frontendCommand,
+				WaitTimeout:              preflightCmdFlags.waitTimeout,
+				ErrorCheckEnableInOutput: true,
+				Single:                   false,
+				NodeIp:                   preflightCmdFlags.node,
+				InputFiles:               []string{inputFilePath},
+				Outputfiles:              []string{},
+				NodeType:                 preflightCmdFlags.chef_server,
+			},
+		},
+		Infra: infra,
+	}
+	return nodeMap
+}
diff --git a/components/automate-cli/cmd/chef-automate/pullAndGenerateConfig.go b/components/automate-cli/cmd/chef-automate/pullAndGenerateConfig.go
index 348a1c763..ff656a1d6 100644
--- a/components/automate-cli/cmd/chef-automate/pullAndGenerateConfig.go
+++ b/components/automate-cli/cmd/chef-automate/pullAndGenerateConfig.go
@@ -297,7 +297,7 @@ func (p *PullConfigsImpl) pullAutomateConfigs() (map[string]*dc.AutomateConfig,
 			continue
 		}
 		p.sshUtil.getSSHConfig().hostIP = ip
-		rawOutput, err := p.sshUtil.connectAndExecuteCommandOnRemote(GET_FRONTEND_CONFIG, true)
+		rawOutput, err := p.sshUtil.connectAndExecuteCommandOnRemote(fmt.Sprintf(GET_FRONTEND_CONFIG, ""), true)
 		if err != nil {
 			return nil, err
 		}
@@ -318,7 +318,7 @@ func (p *PullConfigsImpl) pullChefServerConfigs() (map[string]*dc.AutomateConfig
 			continue
 		}
 		p.sshUtil.getSSHConfig().hostIP = ip
-		rawOutput, err := p.sshUtil.connectAndExecuteCommandOnRemote(GET_FRONTEND_CONFIG, true)
+		rawOutput, err := p.sshUtil.connectAndExecuteCommandOnRemote(fmt.Sprintf(GET_FRONTEND_CONFIG, ""), true)
 		if err != nil {
 			return nil, err
 		}
diff --git a/components/automate-cli/cmd/chef-automate/sshUtils.go b/components/automate-cli/cmd/chef-automate/sshUtils.go
index 11dba7e23..6b02cb150 100644
--- a/components/automate-cli/cmd/chef-automate/sshUtils.go
+++ b/components/automate-cli/cmd/chef-automate/sshUtils.go
@@ -186,9 +186,7 @@ func (s *SSHUtilImpl) connectAndExecuteCommandOnRemote(remoteCommands string, sp
 	}
 	defer session.Close()
 
-	if spinner {
-		writer.StartSpinner()
-	}
+	startSpinnerIfRequired(spinner)
 
 	var output string
 	errCh := make(chan error)
@@ -205,6 +203,10 @@ func (s *SSHUtilImpl) connectAndExecuteCommandOnRemote(remoteCommands string, sp
 			output = pattern.ReplaceAllString(output, "")
 		}
 		if err != nil {
+			if strings.Contains(output, "sudo: no tty present and no askpass program specified") {
+				errCh <- errors.New("The sudo password is missing. Make sure to provide sudo_password as enviroment variable and pass -E option while running command.")
+				return
+			}
 			errCh <- err
 			return
 		}
@@ -216,16 +218,12 @@ func (s *SSHUtilImpl) connectAndExecuteCommandOnRemote(remoteCommands string, sp
 		return "", errors.New("command timed out")
 	case err := <-errCh:
 		if err != nil {
-			if spinner {
-				writer.StopSpinner()
-			}
+			stopSpinnerIfRequired(spinner)
 			return output, err
 		}
 	}
 
-	if spinner {
-		writer.StopSpinner()
-	}
+	stopSpinnerIfRequired(spinner)
 
 	logrus.Debug("Execution of command done......")
 	return output, nil
@@ -299,7 +297,10 @@ func (s *SSHUtilImpl) copyFileToRemote(srcFilePath string, destFileName string,
 	cmd := "scp"
 	exec_args := []string{"-P " + s.SshConfig.sshPort, "-o StrictHostKeyChecking=no", "-i", s.SshConfig.sshKeyFile, "-r", srcFilePath, s.SshConfig.sshUser + "@" + s.SshConfig.hostIP + ":/tmp/" + destFileName}
 	if err := exec.Command(cmd, exec_args...).Run(); err != nil {
-		writer.Printf("Failed to copy config file to remote %s\n", err.Error())
+		writer.Printf("\n"+"Failed to copy file %s to remote %s\n", srcFilePath, err.Error())
+		if srcFilePath == "/usr/bin/chef-automate" {
+			writer.Printf("Please copy your chef-automate binary to /usr/bin" + "\n")
+		}
 		return err
 	}
 	if removeFile {
@@ -407,3 +408,15 @@ func getSudoPassword() string {
 	sudoPassword := os.Getenv(SUDO_PASSWORD)
 	return sudoPassword
 }
+
+func startSpinnerIfRequired(spinner bool) {
+	if spinner {
+		writer.StartSpinner()
+	}
+}
+
+func stopSpinnerIfRequired(spinner bool) {
+	if spinner {
+		writer.StopSpinner()
+	}
+}
diff --git a/components/automate-cli/cmd/chef-automate/verify.go b/components/automate-cli/cmd/chef-automate/verify.go
new file mode 100644
index 000000000..56e3c9f83
--- /dev/null
+++ b/components/automate-cli/cmd/chef-automate/verify.go
@@ -0,0 +1,223 @@
+package main
+
+import (
+	"fmt"
+
+	"github.com/chef/automate/components/automate-cli/pkg/docs"
+	"github.com/chef/automate/components/automate-cli/pkg/status"
+	verification "github.com/chef/automate/lib/verification"
+	"github.com/spf13/cobra"
+)
+
+type verifyCmdFlags struct {
+	file                      string
+	haAWSProvision            bool
+	haAWSManagedProvision     bool
+	haOnpremDeploy            bool
+	haOnPremAWSManagedDeploy  bool
+	haOnPremCustManagedDeploy bool
+	haAWSDeploy               bool
+	haAWSManagedDeploy        bool
+	standaloneDeploy          bool
+	certificates              bool
+}
+
+type verifyCmdFlow struct {
+	Verification      verification.Verification
+	A2HARBFileExist   bool
+	ManagedServicesOn bool
+}
+
+func init() {
+	flagsObj := verifyCmdFlags{}
+
+	verifyCmd := &cobra.Command{
+		Use:   "verify",
+		Short: "Verify Chef Automate setup",
+		Long:  "Verify Chef Automate config files and Infrastructure",
+		Annotations: map[string]string{
+			docs.Compatibility: docs.Compatibility,
+		},
+		Args: cobra.RangeArgs(0, 1),
+		RunE: verifyCmdFunc(&flagsObj),
+	}
+
+	// flags for Verify Command
+	verifyCmd.PersistentFlags().BoolVar(
+		&flagsObj.haAWSProvision,
+		"ha-aws-provision",
+		false,
+		"Use this flag to verify the AWS Provision config")
+	verifyCmd.PersistentFlags().BoolVar(
+		&flagsObj.haAWSManagedProvision,
+		"ha-aws-managed-provision",
+		false,
+		"Use this flag to verify the AWS Provision config with Managed services")
+	verifyCmd.PersistentFlags().BoolVar(
+		&flagsObj.haOnpremDeploy,
+		"ha-onprem-deploy",
+		false,
+		"Use this flag to verify the On-Premise setup and config with Chef Managed services")
+	verifyCmd.PersistentFlags().BoolVar(
+		&flagsObj.haOnPremAWSManagedDeploy,
+		"ha-onprem-aws-deploy",
+		false,
+		"Use this flag to verify the On-Premise setup and config with AWS Managed services")
+	verifyCmd.PersistentFlags().BoolVar(
+		&flagsObj.haOnPremCustManagedDeploy,
+		"ha-onprem-customer-deploy",
+		false,
+		"Use this flag to verify the On-Premise setup and config with Customer Managed services")
+	verifyCmd.PersistentFlags().BoolVar(
+		&flagsObj.haAWSDeploy,
+		"ha-aws-deploy",
+		false,
+		"Use this flag to verify the AWS Deployment setup and config")
+	verifyCmd.PersistentFlags().BoolVar(
+		&flagsObj.haAWSManagedDeploy,
+		"ha-aws-managed-deploy",
+		false,
+		"Use this flag to verify the AWS Deployment setup and config with Managed Services")
+	verifyCmd.PersistentFlags().BoolVar(
+		&flagsObj.standaloneDeploy,
+		"standalone-deploy",
+		false,
+		"Use this flag to verify the Automate standalone setup and config")
+	verifyCmd.PersistentFlags().BoolVar(
+		&flagsObj.certificates,
+		"certificates",
+		false,
+		"Use this flag to verify the certificates provided in the file")
+	verifyCmd.PersistentFlags().StringVar(
+		&flagsObj.file,
+		"file",
+		"",
+		"Config file that needs to be verified")
+	RootCmd.AddCommand(verifyCmd)
+}
+
+func verifyCmdFunc(flagsObj *verifyCmdFlags) func(cmd *cobra.Command, args []string) error {
+	return func(cmd *cobra.Command, args []string) error {
+		c := verifyCmdFlow{
+			Verification:      &verification.VerificationModule{},
+			A2HARBFileExist:   isA2HARBFileExist(),
+			ManagedServicesOn: isManagedServicesOn(),
+		}
+		return c.runVerifyCmd(cmd, args, flagsObj)
+	}
+}
+
+func (v *verifyCmdFlow) runVerifyCmd(cmd *cobra.Command, args []string, flagsObj *verifyCmdFlags) error {
+	var configPath = ""
+	if len(args) > 0 {
+		configPath = args[0]
+	}
+
+	switch true {
+	case flagsObj.haAWSProvision:
+		err := v.verifyHaAWSProvision(configPath)
+		return err
+	case flagsObj.haAWSManagedProvision:
+		err := v.verifyHaAWSManagedProvision(configPath)
+		return err
+	case flagsObj.haAWSDeploy:
+		err := v.verifyHaAWSDeploy(configPath)
+		return err
+	case flagsObj.haAWSManagedDeploy:
+		err := v.verifyHaAWSManagedDeploy(configPath)
+		return err
+	case flagsObj.standaloneDeploy:
+		err := v.verifyStandaloneDeploy(configPath)
+		return err
+	case flagsObj.haOnpremDeploy:
+		err := v.verifyHaOnpremDeploy(configPath)
+		return err
+	case flagsObj.haOnPremAWSManagedDeploy:
+		err := v.verifyHaOnPremAWSManagedDeploy(configPath)
+		return err
+	case flagsObj.haOnPremCustManagedDeploy:
+		err := v.verifyHaOnPremCustManagedDeploy(configPath)
+		return err
+	case flagsObj.certificates:
+		err := v.Verification.VerifyCertificates("")
+		return err
+	default:
+		fmt.Println(cmd.UsageString())
+		return nil
+	}
+
+}
+
+func (v *verifyCmdFlow) verifyHaAWSProvision(configPath string) error {
+	if err := v.Verification.VerifyHAAWSProvision(configPath); err != nil {
+		return status.Annotate(err, status.ConfigError)
+	}
+
+	return nil
+}
+
+func (v *verifyCmdFlow) verifyHaAWSManagedProvision(configPath string) error {
+	if err := v.Verification.VerifyHAAWSManagedProvision(configPath); err != nil {
+		return status.Annotate(err, status.ConfigError)
+	}
+
+	return nil
+}
+
+func (v *verifyCmdFlow) verifyHaAWSDeploy(configPath string) error {
+	if !v.ManagedServicesOn {
+		if v.A2HARBFileExist {
+			if err := v.Verification.VerifyHAAWSDeployment(configPath); err != nil {
+				return status.Annotate(err, status.ConfigError)
+			}
+			return nil
+		}
+		return status.New(status.InvalidCommandArgsError, errProvisonInfra)
+	}
+	return status.New(status.InvalidCommandArgsError, "This flag will not verify the Managed Services Setup. Please use the --ha-aws-managed-deploy flag.")
+}
+
+func (v *verifyCmdFlow) verifyHaAWSManagedDeploy(configPath string) error {
+	if v.ManagedServicesOn {
+		if v.A2HARBFileExist {
+			if err := v.Verification.VerifyHAAWSManagedDeployment(configPath); err != nil {
+				return status.Annotate(err, status.ConfigError)
+			}
+			return nil
+		}
+		return status.New(status.InvalidCommandArgsError, errProvisonInfra)
+	}
+	return status.New(status.InvalidCommandArgsError, "Managed Services flag is not set. Cannot verify the config.")
+}
+
+func (v *verifyCmdFlow) verifyStandaloneDeploy(configPath string) error {
+	if v.A2HARBFileExist {
+		return status.New(status.InvalidCommandArgsError, "Deployment type does not match with the requested flag.")
+	}
+	if err := v.Verification.VerifyStandaloneDeployment(configPath); err != nil {
+		return status.Annotate(err, status.ConfigError)
+	}
+
+	return nil
+}
+
+func (v *verifyCmdFlow) verifyHaOnpremDeploy(configPath string) error {
+	if err := v.Verification.VerifyOnPremDeployment(configPath); err != nil {
+		return status.Annotate(err, status.ConfigError)
+	}
+	return nil
+}
+
+func (v *verifyCmdFlow) verifyHaOnPremAWSManagedDeploy(configPath string) error {
+	if err := v.Verification.VerifyOnPremAWSManagedDeployment(configPath); err != nil {
+		return status.Annotate(err, status.ConfigError)
+	}
+	return nil
+}
+
+func (v *verifyCmdFlow) verifyHaOnPremCustManagedDeploy(configPath string) error {
+	if err := v.Verification.VerifyOnPremCustManagedDeployment(configPath); err != nil {
+		return status.Annotate(err, status.ConfigError)
+	}
+	return nil
+}
diff --git a/components/automate-cluster-ctl/libexec/cluster-gather-logs b/components/automate-cluster-ctl/libexec/cluster-gather-logs
index ab3e09336..6714059ec 100755
--- a/components/automate-cluster-ctl/libexec/cluster-gather-logs
+++ b/components/automate-cluster-ctl/libexec/cluster-gather-logs
@@ -22,6 +22,9 @@ class AutomateClusterGatherlogs < AutomateCluster::Command
     ssh = AutomateCluster::SSH.new
     timestamp = Time.now.strftime('%Y%m%d%H%M%S')
 
+    # store the secret envs so we can pass them to the command
+    store_secret_envs
+
     ssh.connections do |type, conn|
       frontend = %w{automate chef_server}.include?(type)
 
@@ -65,6 +68,18 @@ class AutomateClusterGatherlogs < AutomateCluster::Command
     end
   end
 
+  # store the sudo_password from the env variable in the secrets hash
+  def store_secret_envs
+    sudo_password = ENV['sudo_password']
+    # If the sudo_password is set, store it in the secrets hash
+    if sudo_password
+      # Set a new secret
+      secrets.set('sudo_password', sudo_password)
+      # Save the updated secrets store to disk
+      secrets.save(File.expand_path(AutomateCluster::Config.secrets_store_file))
+    end
+  end
+
   def sudo_cmd(backend)
     ["echo #{sudo_password(backend)} |", sudo_command, '-S', sudo_options]
   end
diff --git a/components/automate-cluster-ctl/libexec/cluster-status b/components/automate-cluster-ctl/libexec/cluster-status
index f11f50ccd..70d66eabc 100755
--- a/components/automate-cluster-ctl/libexec/cluster-status
+++ b/components/automate-cluster-ctl/libexec/cluster-status
@@ -17,6 +17,10 @@ class AutomateClusterStatus < AutomateCluster::Command
   def execute
     be_service_data = []
     fe_service_data = []
+
+    # store the secret envs so we can pass them to the command
+    store_secret_envs
+    
     if AutomateCluster::Config.aws.setup_managed_services == true
       wait_while 'Fetching service status' do
         fe_service_data += fe_status('automate') if name.nil? || name == 'automate'
@@ -54,6 +58,18 @@ class AutomateClusterStatus < AutomateCluster::Command
     @fe_sudo_password ||= AutomateCluster.secrets['fe_sudo_password'] || AutomateCluster.secrets['sudo_password']
   end
 
+  # store the sudo_password from the env variable in the secrets hash
+  def store_secret_envs
+    sudo_password = ENV['sudo_password']
+    # If the sudo_password is set, store it in the secrets hash
+    if sudo_password
+      # Set a new secret
+      secrets.set('sudo_password', sudo_password)
+      # Save the updated secrets store to disk
+      secrets.save(File.expand_path(AutomateCluster::Config.secrets_store_file))
+    end
+  end
+
   def fe_status(service)
     ssh = AutomateCluster::SSH.new
 
diff --git a/components/docs-chef-io/content/automate/ha_automate_to_automate_ha.md b/components/docs-chef-io/content/automate/ha_automate_to_automate_ha.md
index b2b1d718a..ca2d84999 100644
--- a/components/docs-chef-io/content/automate/ha_automate_to_automate_ha.md
+++ b/components/docs-chef-io/content/automate/ha_automate_to_automate_ha.md
@@ -78,6 +78,13 @@ minimum version of Chef Automate: [20201230192246](https://docs.chef.io/release_
     {{% automate/char-warn %}}
     {{< /warning >}}
 
+    Update the backup paths to match the elasticsearch snapshot location from the A2HA:
+
+    ```bash
+    [global.v1.external.opensearch.backup.fs]
+    path = "/mnt/automate_backups/elasticsearch"
+    ```
+
 1. Unpack the `bootstrap.abb` file on all the Frontend nodes:
 
     Login to Each Frontend Node and then run after copying the `bootstrap.abb` file.
diff --git a/components/docs-chef-io/content/automate/ha_aws_deploy_steps.md b/components/docs-chef-io/content/automate/ha_aws_deploy_steps.md
index b1945f46d..586ec118f 100644
--- a/components/docs-chef-io/content/automate/ha_aws_deploy_steps.md
+++ b/components/docs-chef-io/content/automate/ha_aws_deploy_steps.md
@@ -54,7 +54,7 @@ Follow the steps below to deploy Chef Automate High Availability (HA) on AWS (Am
 
 - PLEASE DONOT MODIFY THE WORKSPACE PATH it should always be "/hab/a2_deploy_workspace"
 - We currently don't support AD managed users in nodes. We only support local linux users.
-- If you have configured sudo password for the user, then you need to create an environment variable `sudo_password` and set the password as the value of the variable. Example: `export sudo_password=<password>`. And then run all sudo commands with `sudo -E or --preserve-env` option. Example: `sudo -E ./chef-automate deploy config.toml --airgap-bundle automate.aib`. This is required for the `chef-automate` CLI to run the commands with sudo privileges.
+- If you have configured sudo password for the user, then you need to create an environment variable `sudo_password` and set the password as the value of the variable. Example: `export sudo_password=<password>`. And then run all sudo commands with `sudo -E or --preserve-env` option. Example: `sudo -E ./chef-automate deploy config.toml --airgap-bundle automate.aib`. This is required for the `chef-automate` CLI to run the commands with sudo privileges. Please refer [this](/automate/ha_sudo_password/) for details.
 
 {{< /warning >}}
 
@@ -102,7 +102,6 @@ Run the following steps on Bastion Host Machine:
    - Give `ssh_user` which has access to all the machines. Example: `ubuntu`
    - Give `ssh_port` in case your AMI is running on custom ssh port, default will be 22.
    - Give `ssh_key_file` path, this should have been download from AWS SSH Key Pair which we want to use to create all the VM's. Thus, we will be able to access all VM's using this.
-   - `sudo_password` is only meant to switch to sudo user. If you have configured password for sudo user, please provide it here.
    - We support only private key authentication.
    - Set `backup_config` to `"efs"` or `"s3"`
    - If `backup_config` is `s3` then set `s3_bucketName` to a Unique Value.
@@ -219,7 +218,6 @@ Check if Chef Automate UI is accessible by going to (Domain used for Chef Automa
 ssh_user = "ec2-user"
 ssh_port = "22"
 ssh_key_file = "~/.ssh/my-key.pem"
-# sudo_password = ""
 backup_config = "s3"
 s3_bucketName = "My-Bucket-Name"
 secrets_key_file = "/hab/a2_deploy_workspace/secrets.key"
diff --git a/components/docs-chef-io/content/automate/ha_aws_managed_deploy_steps.md b/components/docs-chef-io/content/automate/ha_aws_managed_deploy_steps.md
index cf8b5118f..de1b3d83e 100644
--- a/components/docs-chef-io/content/automate/ha_aws_managed_deploy_steps.md
+++ b/components/docs-chef-io/content/automate/ha_aws_managed_deploy_steps.md
@@ -67,7 +67,7 @@ Set the above prerequisites in `~/.aws/credentials` in Bastion Host:
 
 - PLEASE DONOT MODIFY THE WORKSPACE PATH it should always be "/hab/a2_deploy_workspace"
 - We currently don't support AD managed users in nodes. We only support local linux users.
-- If you have configured sudo password for the user, then you need to create an environment variable `sudo_password` and set the password as the value of the variable. Example: `export sudo_password=<password>`. And then run all sudo commands with `sudo -E or --preserve-env` option. Example: `sudo -E ./chef-automate deploy config.toml --airgap-bundle automate.aib`. This is required for the `chef-automate` CLI to run the commands with sudo privileges.
+- If you have configured sudo password for the user, then you need to create an environment variable `sudo_password` and set the password as the value of the variable. Example: `export sudo_password=<password>`. And then run all sudo commands with `sudo -E or --preserve-env` option. Example: `sudo -E ./chef-automate deploy config.toml --airgap-bundle automate.aib`. This is required for the `chef-automate` CLI to run the commands with sudo privileges. Please refer [this](/automate/ha_sudo_password/) for details.
 
 {{< /warning >}}
 
@@ -105,7 +105,6 @@ Set the above prerequisites in `~/.aws/credentials` in Bastion Host:
    - Give `ssh_user` which has access to all the machines. Example: `ubuntu`.
    - Give `ssh_port` if your AMI runs on custom **ssh port**. The default value is 22.
    - Give `ssh_key_file` path, downloaded from **AWS SSH Key Pair**, which you want to use to create all the VMs. This will let you access all the VMs.
-   - `sudo_password` is only meant to switch to sudo user. If you have configured password for sudo user, please provide it here.
    - We support only private key authentication.
    - Set `backup_config` to `"s3"`. If `backup_config` is `s3`, set `s3_bucketName`.
    - Set `admin_password` to access Chef Automate UI for user `admin`.
@@ -224,7 +223,6 @@ Check if Chef Automate UI is accessible by going to (Domain used for Chef Automa
 ssh_user = "ec2-user"
 ssh_port = "22"
 ssh_key_file = "~/.ssh/my-key.pem"
-# sudo_password = ""
 backup_config = "s3"
 s3_bucketName = "My-Bucket-Name"
 secrets_key_file = "/hab/a2_deploy_workspace/secrets.key"
diff --git a/components/docs-chef-io/content/automate/ha_chef_backend_to_automate_ha.md b/components/docs-chef-io/content/automate/ha_chef_backend_to_automate_ha.md
index 2557b18c0..9ddcf3e2c 100644
--- a/components/docs-chef-io/content/automate/ha_chef_backend_to_automate_ha.md
+++ b/components/docs-chef-io/content/automate/ha_chef_backend_to_automate_ha.md
@@ -179,7 +179,6 @@ workspace_path = "/hab/a2_deploy_workspace"
 ssh_user = "myusername"
 ssh_port = "22"
 ssh_key_file = "~/.ssh/mykey.pem"
-sudo_password = ""
 
 # DON'T MODIFY THE BELOW LINE (backup_mount)
 backup_mount = "/mnt/automate_backups"
diff --git a/components/docs-chef-io/content/automate/ha_onprim_deployment_procedure.md b/components/docs-chef-io/content/automate/ha_onprim_deployment_procedure.md
index 543b0f9a8..c09501c97 100644
--- a/components/docs-chef-io/content/automate/ha_onprim_deployment_procedure.md
+++ b/components/docs-chef-io/content/automate/ha_onprim_deployment_procedure.md
@@ -55,7 +55,7 @@ sudo sed -i 's/SELINUX=enforcing/SELINUX=permissive/g' /etc/selinux/config
 
 - PLEASE DONOT MODIFY THE WORKSPACE PATH it should always be "/hab/a2_deploy_workspace"
 - We currently don't support AD managed users in nodes. We only support local linux users.
-- If you have configured sudo password for the user, then you need to create an environment variable `sudo_password` and set the password as the value of the variable. Example: `export sudo_password=<password>`. And then run all sudo commands with `sudo -E or --preserve-env` option. Example: `sudo -E ./chef-automate deploy config.toml --airgap-bundle automate.aib`. This is required for the `chef-automate` CLI to run the commands with sudo privileges.
+- If you have configured sudo password for the user, then you need to create an environment variable `sudo_password` and set the password as the value of the variable. Example: `export sudo_password=<password>`. And then run all sudo commands with `sudo -E or --preserve-env` option. Example: `sudo -E ./chef-automate deploy config.toml --airgap-bundle automate.aib`. This is required for the `chef-automate` CLI to run the commands with sudo privileges. Please refer [this](/automate/ha_sudo_password/) for details.
 
 {{< /warning >}}
 
@@ -112,7 +112,6 @@ sudo sed -i 's/SELINUX=enforcing/SELINUX=permissive/g' /etc/selinux/config
    - Give `ssh_user` which has access to all the machines. Example: `ubuntu`
    - Give `ssh_port` in case your AMI is running on custom ssh port, default will be 22.
    - Give the `ssh_key_file` path; this key should have access to all the Machines or VMs.
-   - `sudo_password` is only meant to switch to sudo user. If you have configured a password for the sudo user, please provide it here.
    - We support only private key authentication.
    - Provide `backup_config` based on the type of backup storage you have. This field can be optionally left empty during deployment and can be patched at later point. Allowed values are `object_storage` and `file_system`.
    - If `backup_config` is `object_storage`, make sure to fill values under `[object_storage.config]`
diff --git a/components/docs-chef-io/content/automate/ha_sudo_password.md b/components/docs-chef-io/content/automate/ha_sudo_password.md
new file mode 100644
index 000000000..0afe7616a
--- /dev/null
+++ b/components/docs-chef-io/content/automate/ha_sudo_password.md
@@ -0,0 +1,34 @@
++++
+title = "Sudo Password"
+draft = false
+gh_repo = "automate"
+[menu]
+  [menu.automate]
+    title = "Sudo Password"
+    parent = "automate/deploy_high_availability/reference"
+    identifier = "automate/deploy_high_availability/reference/ha_sudo_password.md Sudo Password"
+    weight = 210
++++
+
+{{< warning >}}
+{{% automate/ha-warn %}}
+{{< /warning >}}
+
+This page explains enabling the `sudo password` for the Chef Automate High Availability (HA) deployment.
+
+If you have configured the sudo password for the user, you need to create an environment variable **sudo_password** and set the password as the variable's value. Example: `export sudo_password=YOUR_SUDO_PASSWORD`. One done, run all sudo commands with the `sudo -E` or `--preserve-env` option. Example: `sudo -E chef-automate iam version`. This is required for the chef-automate CLI to run the commands with sudo privileges.
+
+## Steps to Enable Sudo Password
+
+To enable the `sudo password` for the Chef Automate HA deployment, follow the steps below:
+
+1. Create a `sudo_password` environment variable. Example: `export sudo_password=1234`.
+2. Pass the `sudo_password` environment variable to the `chef-automate` CLI commands. Example: `sudo -E chef-automate iam version`.
+
+   a. To pass all your environment variables, including the `sudo_password` to the `chef-automate` CLI commands, you can use the `-E` or `--preserve-env` option. Example: `sudo -E chef-automate iam version` or `sudo --preserve-env chef-automate iam version`.
+
+   b. To pass the `sudo_password` environment variable to the `chef-automate` CLI commands, you can supply the environment variable name to the `--preserve-env` argument. Example: `sudo --preserve-env=sudo_password chef-automate iam version`.
+
+3. You can also set environment variables directly in the sudo command. Example: `sudo sudo_password=1234 chef-automate iam version`.
+
+Pass the `sudo_password` environment variable to all the `chef-automate` CLI commands.
diff --git a/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate.yaml b/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate.yaml
index 0d79e21a9..2e32cfa43 100644
--- a/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate.yaml
+++ b/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate.yaml
@@ -55,6 +55,7 @@ see_also:
 - test - Run Automate HA smoke tests
 - uninstall - Uninstall Chef Automate
 - upgrade - upgrade automate to the latest version
+- verify - Verify Chef Automate setup
 - version - Show CLI version
 - workspace - Set workspace env for Automate HA.
 supported_on: Bastion
diff --git a/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate_preflight-check.yaml b/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate_preflight-check.yaml
index cd59def0e..7291cad28 100644
--- a/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate_preflight-check.yaml
+++ b/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate_preflight-check.yaml
@@ -4,15 +4,44 @@ usage: chef-automate preflight-check [flags]
 description: |
   Perform preflight check to verify host meets installation criteria.
 options:
+- name: a2
+  default_value: "false"
+  usage: Pass this flag to run pre-flight check on automate node(HA)
 - name: airgap
   default_value: "false"
   usage: Pass this flag when the environment is airgapped
+- name: automate
+  shorthand: a
+  default_value: "false"
+  usage: Pass this flag to run pre-flight check on automate node(HA)
+- name: chef_server
+  shorthand: c
+  default_value: "false"
+  usage: |
+    Pass this flag to run pre-flight check on chef-server node(HA)
 - name: config
   usage: Optional config file to use
+- name: cs
+  default_value: "false"
+  usage: |
+    Pass this flag to run pre-flight check on chef-server node(HA)
+- name: fe
+  default_value: "false"
+  usage: Pass this flag to run pre-flight check on all Frontend nodes
+- name: frontend
+  shorthand: f
+  default_value: "false"
+  usage: Pass this flag to run pre-flight check on all Frontend nodes
+- name: ha-deployment-config
+  default_value: "false"
+  usage: Pass this flag to run pre-flight check on automate-HA
 - name: help
   shorthand: h
   default_value: "false"
   usage: help for preflight-check
+- name: node
+  usage: |
+    Pass this flag to run pre-flight check on a perticular node node(HA)
 inherited_options:
 - name: debug
   shorthand: d
diff --git a/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate_preflight-check_migrate-from-v1.yaml b/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate_preflight-check_migrate-from-v1.yaml
index 6280bc62d..b6e9327a6 100644
--- a/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate_preflight-check_migrate-from-v1.yaml
+++ b/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate_preflight-check_migrate-from-v1.yaml
@@ -40,18 +40,47 @@ options:
   usage: |
     Optionally do not check if your Chef Automate v1 installation has workflow configured (default = false)
 inherited_options:
+- name: a2
+  default_value: "false"
+  usage: Pass this flag to run pre-flight check on automate node(HA)
 - name: airgap
   default_value: "false"
   usage: Pass this flag when the environment is airgapped
+- name: automate
+  shorthand: a
+  default_value: "false"
+  usage: Pass this flag to run pre-flight check on automate node(HA)
+- name: chef_server
+  shorthand: c
+  default_value: "false"
+  usage: |
+    Pass this flag to run pre-flight check on chef-server node(HA)
 - name: config
   usage: Optional config file to use
+- name: cs
+  default_value: "false"
+  usage: |
+    Pass this flag to run pre-flight check on chef-server node(HA)
 - name: debug
   shorthand: d
   default_value: "false"
   usage: Enable debug output
+- name: fe
+  default_value: "false"
+  usage: Pass this flag to run pre-flight check on all Frontend nodes
+- name: frontend
+  shorthand: f
+  default_value: "false"
+  usage: Pass this flag to run pre-flight check on all Frontend nodes
+- name: ha-deployment-config
+  default_value: "false"
+  usage: Pass this flag to run pre-flight check on automate-HA
 - name: no-check-version
   default_value: "false"
   usage: Disable version check
+- name: node
+  usage: |
+    Pass this flag to run pre-flight check on a perticular node node(HA)
 - name: result-json
   usage: Write command result as JSON to PATH
 see_also:
diff --git a/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate_verify.yaml b/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate_verify.yaml
new file mode 100644
index 000000000..5cba26356
--- /dev/null
+++ b/components/docs-chef-io/data/automate/cli_chef_automate/commands/chef-automate_verify.yaml
@@ -0,0 +1,58 @@
+name: chef-automate verify
+synopsis: Verify Chef Automate setup
+usage: chef-automate verify [flags]
+description: Verify Chef Automate config files and Infrastructure
+options:
+- name: certificates
+  default_value: "false"
+  usage: |
+    Use this flag to verify the certificates provided in the file
+- name: file
+  usage: Config file that needs to be verified
+- name: ha-aws-deploy
+  default_value: "false"
+  usage: Use this flag to verify the AWS Deployment setup and config
+- name: ha-aws-managed-deploy
+  default_value: "false"
+  usage: |
+    Use this flag to verify the AWS Deployment setup and config with Managed Services
+- name: ha-aws-managed-provision
+  default_value: "false"
+  usage: |
+    Use this flag to verify the AWS Provision config with Managed services
+- name: ha-aws-provision
+  default_value: "false"
+  usage: Use this flag to verify the AWS Provision config
+- name: ha-onprem-aws-deploy
+  default_value: "false"
+  usage: |
+    Use this flag to verify the On-Premise setup and config with AWS Managed services
+- name: ha-onprem-customer-deploy
+  default_value: "false"
+  usage: |
+    Use this flag to verify the On-Premise setup and config with Customer Managed services
+- name: ha-onprem-deploy
+  default_value: "false"
+  usage: |
+    Use this flag to verify the On-Premise setup and config with Chef Managed services
+- name: help
+  shorthand: h
+  default_value: "false"
+  usage: help for verify
+- name: standalone-deploy
+  default_value: "false"
+  usage: |
+    Use this flag to verify the Automate standalone setup and config
+inherited_options:
+- name: debug
+  shorthand: d
+  default_value: "false"
+  usage: Enable debug output
+- name: no-check-version
+  default_value: "false"
+  usage: Disable version check
+- name: result-json
+  usage: Write command result as JSON to PATH
+see_also:
+- chef-automate - Chef Automate CLI
+compatible_with: compatibility
diff --git a/go.mod b/go.mod
index c553dcab3..706b701d0 100644
--- a/go.mod
+++ b/go.mod
@@ -67,6 +67,7 @@ require (
 	github.com/iancoleman/strcase v0.0.0-20190422225806-e506e3ef7365 // indirect
 	github.com/imdario/mergo v0.3.13
 	github.com/jaswdr/faker v1.0.2
+	github.com/jedib0t/go-pretty/v5 v5.0.2-alpha
 	github.com/jhump/protoreflect v1.7.1-0.20200723220026-11eaaf73e0ec
 	github.com/kevinburke/go-bindata v3.16.0+incompatible
 	github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348
@@ -74,7 +75,6 @@ require (
 	github.com/lib/pq v1.8.0
 	github.com/lyft/protoc-gen-star v0.4.16-0.20200805193024-077ca8f98fb2
 	github.com/mattn/go-isatty v0.0.12 // indirect
-	github.com/mattn/go-runewidth v0.0.9 // indirect
 	github.com/mattn/go-sqlite3 v1.11.0 // indirect
 	github.com/minio/minio-go/v7 v7.0.14
 	github.com/mitchellh/go-homedir v1.1.0
diff --git a/go.sum b/go.sum
index aba2a3d83..a71edd28b 100644
--- a/go.sum
+++ b/go.sum
@@ -122,6 +122,8 @@ github.com/armon/go-metrics v0.0.0-20190430140413-ec5e00d3c878/go.mod h1:3AMJUQh
 github.com/armon/go-metrics v0.3.2 h1:EyUnxyP2yaGpLgMiuyyz8sHnByqeTJUfGs72pdH0i4A=
 github.com/armon/go-metrics v0.3.2/go.mod h1:4O98XIr/9W0sxpJ8UaYkvjk10Iff7SnFrb4QAOwNTFc=
 github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
+github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco=
+github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
 github.com/aws/aws-sdk-go v1.15.27/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0=
 github.com/aws/aws-sdk-go v1.19.18/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
 github.com/aws/aws-sdk-go v1.19.45/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo=
@@ -236,6 +238,9 @@ github.com/ghodss/yaml v0.0.0-20180820084758-c7ce16629ff4/go.mod h1:4dBDuWmgqj2H
 github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/ghodss/yaml v1.0.1-0.20180503022059-e9ed3c6dfb39 h1:8aiwjJixH9Dws9c0mE6yeghmrVhe6csuB+onSjeW31Q=
 github.com/ghodss/yaml v1.0.1-0.20180503022059-e9ed3c6dfb39/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
+github.com/globalsign/mgo v0.0.0-20180905125535-1ca0a4f7cbcb/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
+github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8 h1:DujepqpGd1hyOd7aW59XpK7Qymp8iy83xq74fLr21is=
+github.com/globalsign/mgo v0.0.0-20181015135952-eeefdecb41b8/go.mod h1:xkRDCp4j0OGD1HRkm4kmhM+pmpv3AKq5SU7GMg4oO/Q=
 github.com/go-chef/chef v0.23.2-0.20201213054559-3243f736d651 h1:r1JMgPxoXlMKblknr8f6f3SafrfL2oKyPCqglTQN7xA=
 github.com/go-chef/chef v0.23.2-0.20201213054559-3243f736d651/go.mod h1:9Ptf9dFZDkpC3qLxpNhHMyG6TxCmMzonqPKXTh+xVm4=
 github.com/go-delve/delve v1.3.1 h1:LI0X4aAE0N7ay8uR48aMJ6GNTxamIpcxi1THjwJjenI=
@@ -253,6 +258,11 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9
 github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
 github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8=
 github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM=
+github.com/go-openapi/errors v0.17.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
+github.com/go-openapi/errors v0.19.0 h1:guf3T2lnCBKlODmERt4T9GtMWRpJOikgKGyIvi0xcb8=
+github.com/go-openapi/errors v0.19.0/go.mod h1:LcZQpmvG4wyF5j4IhA73wkLFQg+QJXOQHVjmcZxhka0=
+github.com/go-openapi/strfmt v0.19.0 h1:0Dn9qy1G9+UJfRU7TR8bmdGxb4uifB7HNrJjOnV0yPk=
+github.com/go-openapi/strfmt v0.19.0/go.mod h1:+uW+93UVvGGq2qGaZxdDeJqSAqBqBdl+ZPMF/cC8nDY=
 github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w=
 github.com/go-sql-driver/mysql v1.5.0 h1:ozyZYNQW3x3HtqT1jira07DN2PArx2v7/mN66gGcHOs=
 github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
@@ -444,6 +454,8 @@ github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NH
 github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
 github.com/jaswdr/faker v1.0.2 h1:3iRZztCC4oU67i67qGcyhIxeKgHQQH/iCifJOj3uOSI=
 github.com/jaswdr/faker v1.0.2/go.mod h1:9S4x1SRPC3m+iLgZTx2HZ0/R1/B0hwuL8uvOAiuJNtg=
+github.com/jedib0t/go-pretty/v5 v5.0.2-alpha h1:rRYHSFWZ3egaMVREb5NgN17UanLMWM2s7EhG3u/1Yy4=
+github.com/jedib0t/go-pretty/v5 v5.0.2-alpha/go.mod h1:DAKhNY3KVw+n6uMJ+WIzEs2XHfuQpMu2taSsKOXbTBw=
 github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI=
 github.com/jhump/protoreflect v1.7.1-0.20200723220026-11eaaf73e0ec h1:LeWD9kGWul9js18sWzNP2SjMuO6smUEpXt8OmRs7qU0=
 github.com/jhump/protoreflect v1.7.1-0.20200723220026-11eaaf73e0ec/go.mod h1:D8nEtk+lKr8kMTMiLayswAtSSeHYDaRYk9r78Cy11mM=
@@ -513,6 +525,8 @@ github.com/lyft/protoc-gen-star v0.4.16-0.20200805193024-077ca8f98fb2 h1:P5EAf1f
 github.com/lyft/protoc-gen-star v0.4.16-0.20200805193024-077ca8f98fb2/go.mod h1:mE8fbna26u7aEA2QCVvvfBU/ZrPgocG1206xAFPcs94=
 github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4=
 github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
+github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
+github.com/mailru/easyjson v0.0.0-20190403194419-1ea4449da983/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
 github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/mattn/go-colorable v0.0.0-20170327083344-ded68f7a9561/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
@@ -628,6 +642,7 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
 github.com/pkg/profile v0.0.0-20170413231811-06b906832ed0/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
+github.com/pkg/profile v1.2.1/go.mod h1:hJw3o1OdXxsrSjjVksARp5W95eeEaEfptyVZyv6JUPA=
 github.com/pkg/profile v1.5.0 h1:042Buzk+NhDI+DeSAA62RwJL8VAuZUMQZUjCsRz1Mug=
 github.com/pkg/profile v1.5.0/go.mod h1:qBsxPvzyUincmltOk6iyRVxHYg4adc0OFOv72ZdLa18=
 github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI=
@@ -913,6 +928,7 @@ golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJ
 golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sys v0.0.0-20171017063910-8dbc5d05d6ed/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
diff --git a/lib/config_parser/parser.go b/lib/config_parser/parser.go
new file mode 100644
index 000000000..e37dc0c80
--- /dev/null
+++ b/lib/config_parser/parser.go
@@ -0,0 +1,78 @@
+package config_parser
+
+import (
+	sc "github.com/chef/automate/api/config/deployment"
+	"github.com/chef/automate/components/automate-cli/pkg/status"
+	"github.com/chef/automate/lib/io/fileutils"
+	ptoml "github.com/pelletier/go-toml"
+)
+
+type ConfigParser interface {
+	ParseAWSAutomateConfig(configFile string) (*HAAwsConfigToml, error)
+	ParseOnPremConfig(configFile string) (*HAOnPremConfigToml, error)
+	ParseStandaloneConfig(configFile string) (*sc.AutomateConfig, error)
+}
+
+type ConfigParserImpl struct{}
+
+func (cp *ConfigParserImpl) ParseAWSAutomateConfig(configFile string) (*HAAwsConfigToml, error) {
+	return ParseAWSAutomateConfig(configFile)
+}
+
+func (cp *ConfigParserImpl) ParseOnPremConfig(configFile string) (*HAOnPremConfigToml, error) {
+	return ParseOnPremConfig(configFile)
+}
+
+func (cp *ConfigParserImpl) ParseStandaloneConfig(configFile string) (*sc.AutomateConfig, error) {
+	return ParseStandaloneConfig(configFile)
+}
+
+func ParseAWSAutomateConfig(configFile string) (*HAAwsConfigToml, error) {
+
+	/* This function will read the config toml file and will try to parse it in the structure.
+	   On successful parse, it will return the config structure. This is applicable for both
+	   AWS Provision and Deployment configuration both with Chef Managed and AWS Managed resources. */
+
+	fileUtils := &fileutils.FileSystemUtils{}
+	templateBytes, err := fileUtils.ReadFile(configFile)
+	if err != nil {
+		return nil, status.Wrap(err, status.FileAccessError, "error in reading config toml file")
+	}
+	config := HAAwsConfigToml{}
+	err = ptoml.Unmarshal(templateBytes, &config)
+	if err != nil {
+		return nil, status.Wrap(err, status.ConfigError, "error in unmarshalling config toml file")
+	}
+	return &config, nil
+}
+
+func ParseOnPremConfig(configFile string) (*HAOnPremConfigToml, error) {
+
+	/* This function will read the OnPrem config toml file and will try to parse it in the structure.
+	   On successful parse, it will return the config structure. This is applicable for Chef Managed,
+	   AWS Managed and Customer Managed resources*/
+
+	fileUtils := &fileutils.FileSystemUtils{}
+	templateBytes, err := fileUtils.ReadFile(configFile)
+	if err != nil {
+		return nil, status.Wrap(err, status.FileAccessError, "error in reading config toml file")
+	}
+	config := HAOnPremConfigToml{}
+	err = ptoml.Unmarshal(templateBytes, &config)
+	if err != nil {
+		return nil, status.Wrap(err, status.ConfigError, "error in unmarshalling config toml file")
+	}
+	return &config, nil
+}
+
+func ParseStandaloneConfig(configFile string) (*sc.AutomateConfig, error) {
+
+	/* This function will read the Standalone Automate config toml file and will try to parse it in the structure.
+	   On successful parse, it will return the config structure. */
+
+	config, err := sc.LoadUserOverrideConfigFile(configFile)
+	if err != nil {
+		return nil, err
+	}
+	return config, nil
+}
diff --git a/lib/config_parser/setupConfig.go b/lib/config_parser/setupConfig.go
new file mode 100644
index 000000000..167d14e0e
--- /dev/null
+++ b/lib/config_parser/setupConfig.go
@@ -0,0 +1,262 @@
+package config_parser
+
+type CertByIP struct {
+	IP         string `toml:"ip"`
+	PrivateKey string `toml:"private_key"`
+	PublicKey  string `toml:"public_key"`
+	NodesDn    string `toml:"nodes_dn,omitempty"`
+}
+
+type HAAwsConfigToml struct {
+	Architecture struct {
+		ConfigInitials struct {
+			SecretsKeyFile              string `toml:"secrets_key_file"`
+			SecretsStoreFile            string `toml:"secrets_store_file"`
+			Architecture                string `toml:"architecture"`
+			WorkspacePath               string `toml:"workspace_path"`
+			SSHUser                     string `toml:"ssh_user"`
+			SSHKeyFile                  string `toml:"ssh_key_file"`
+			SSHPort                     string `toml:"ssh_port"`
+			SudoPassword                string `toml:"sudo_password"`
+			LoggingMonitoringManagement string `toml:"logging_monitoring_management"`
+			NewElk                      string `toml:"new_elk"`
+			ExistingElkInstanceIP       string `toml:"existing_elk_instance_ip"`
+			ExistingElkPort             string `toml:"existing_elk_port"`
+			ExistingElkCert             string `toml:"existing_elk_cert"`
+			ExistingElkUsername         string `toml:"existing_elk_username"`
+			ExistingElkPassword         string `toml:"existing_elk_password"`
+			BackupMount                 string `toml:"backup_mount"`
+			BackupConfig                string `toml:"backup_config"`
+			S3BucketName                string `toml:"s3_bucketName"`
+			HabitatUIDGid               string `toml:"habitat_uid_gid"`
+		} `toml:"aws"`
+	} `toml:"architecture"`
+	Automate struct {
+		Config struct {
+			AdminPassword     string     `toml:"admin_password"`
+			Fqdn              string     `toml:"fqdn"`
+			AutomateSetupType string     `toml:"automate_setup_type"`
+			InstanceCount     string     `toml:"instance_count"`
+			TeamsPort         string     `toml:"teams_port"`
+			ConfigFile        string     `toml:"config_file"`
+			EnableCustomCerts bool       `toml:"enable_custom_certs"`
+			RootCA            string     `toml:"root_ca"`
+			PrivateKey        string     `toml:"private_key"`
+			PublicKey         string     `toml:"public_key"`
+			CertsByIP         []CertByIP `toml:"certs_by_ip"`
+		} `toml:"config"`
+	} `toml:"automate"`
+	ChefServer struct {
+		Config struct {
+			InstanceCount     string     `toml:"instance_count"`
+			EnableCustomCerts bool       `toml:"enable_custom_certs"`
+			PrivateKey        string     `toml:"private_key"`
+			PublicKey         string     `toml:"public_key"`
+			CertsByIP         []CertByIP `toml:"certs_by_ip"`
+		} `toml:"config"`
+	} `toml:"chef_server"`
+	Opensearch struct {
+		Config struct {
+			InstanceCount     string     `toml:"instance_count"`
+			EnableCustomCerts bool       `toml:"enable_custom_certs"`
+			RootCA            string     `toml:"root_ca"`
+			AdminCert         string     `toml:"admin_cert"`
+			AdminKey          string     `toml:"admin_key"`
+			PrivateKey        string     `toml:"private_key"`
+			PublicKey         string     `toml:"public_key"`
+			AdminDn           string     `toml:"admin_dn"`
+			NodesDn           string     `toml:"nodes_dn"`
+			CertsByIP         []CertByIP `toml:"certs_by_ip"`
+		} `toml:"config"`
+	} `toml:"opensearch"`
+	Postgresql struct {
+		Config struct {
+			InstanceCount     string     `toml:"instance_count"`
+			EnableCustomCerts bool       `toml:"enable_custom_certs"`
+			RootCA            string     `toml:"root_ca"`
+			PrivateKey        string     `toml:"private_key"`
+			PublicKey         string     `toml:"public_key"`
+			CertsByIP         []CertByIP `toml:"certs_by_ip"`
+		} `toml:"config"`
+	} `toml:"postgresql"`
+	Aws struct {
+		Config struct {
+			Profile                      string   `toml:"profile"`
+			Region                       string   `toml:"region"`
+			AwsVpcId                     string   `toml:"aws_vpc_id"`
+			AwsCidrBlockAddr             string   `toml:"aws_cidr_block_addr"`
+			PrivateCustomSubnets         []string `toml:"private_custom_subnets"`
+			PublicCustomSubnets          []string `toml:"public_custom_subnets"`
+			SSHKeyPairName               string   `toml:"ssh_key_pair_name"`
+			SetupManagedServices         bool     `toml:"setup_managed_services"`
+			OpensearchDomainName         string   `toml:"managed_opensearch_domain_name"`
+			OpensearchDomainUrl          string   `toml:"managed_opensearch_domain_url"`
+			OpensearchUsername           string   `toml:"managed_opensearch_username"`
+			OpensearchUserPassword       string   `toml:"managed_opensearch_user_password"`
+			OpensearchCertificate        string   `toml:"managed_opensearch_certificate"`
+			AwsOsSnapshotRoleArn         string   `toml:"aws_os_snapshot_role_arn"`
+			OsUserAccessKeyId            string   `toml:"os_snapshot_user_access_key_id"`
+			OsUserAccessKeySecret        string   `toml:"os_snapshot_user_access_key_secret"`
+			RDSInstanceUrl               string   `toml:"managed_rds_instance_url"`
+			RDSSuperUserName             string   `toml:"managed_rds_superuser_username"`
+			RDSSuperUserPassword         string   `toml:"managed_rds_superuser_password"`
+			RDSDBUserName                string   `toml:"managed_rds_dbuser_username"`
+			RDSDBUserPassword            string   `toml:"managed_rds_dbuser_password"`
+			RDSCertificate               string   `toml:"managed_rds_certificate"`
+			AmiFilterName                string   `toml:"ami_filter_name"`
+			AmiFilterVirtType            string   `toml:"ami_filter_virt_type"`
+			AmiFilterOwner               string   `toml:"ami_filter_owner"`
+			AmiID                        string   `toml:"ami_id"`
+			LBAccessLogs                 string   `toml:"lb_access_logs"`
+			DeleteOnTermination          bool     `toml:"delete_on_termination"`
+			AutomateServerInstanceType   string   `toml:"automate_server_instance_type"`
+			ChefServerInstanceType       string   `toml:"chef_server_instance_type"`
+			OpensearchServerInstanceType string   `toml:"opensearch_server_instance_type"`
+			PostgresqlServerInstanceType string   `toml:"postgresql_server_instance_type"`
+			AutomateLbCertificateArn     string   `toml:"automate_lb_certificate_arn"`
+			ChefServerLbCertificateArn   string   `toml:"chef_server_lb_certificate_arn"`
+			AutomateEbsVolumeIops        string   `toml:"automate_ebs_volume_iops"`
+			AutomateEbsVolumeSize        string   `toml:"automate_ebs_volume_size"`
+			AutomateEbsVolumeType        string   `toml:"automate_ebs_volume_type"`
+			ChefEbsVolumeIops            string   `toml:"chef_ebs_volume_iops"`
+			ChefEbsVolumeSize            string   `toml:"chef_ebs_volume_size"`
+			ChefEbsVolumeType            string   `toml:"chef_ebs_volume_type"`
+			OpensearchEbsVolumeIops      string   `toml:"opensearch_ebs_volume_iops"`
+			OpensearchEbsVolumeSize      string   `toml:"opensearch_ebs_volume_size"`
+			OpensearchEbsVolumeType      string   `toml:"opensearch_ebs_volume_type"`
+			PostgresqlEbsVolumeIops      string   `toml:"postgresql_ebs_volume_iops"`
+			PostgresqlEbsVolumeSize      string   `toml:"postgresql_ebs_volume_size"`
+			PostgresqlEbsVolumeType      string   `toml:"postgresql_ebs_volume_type"`
+			XContact                     string   `toml:"X-Contact"`
+			XDept                        string   `toml:"X-Dept"`
+			XProject                     string   `toml:"X-Project"`
+			XProduction                  string   `toml:"X-Production"`
+			XCustomer                    string   `toml:"X-Customer"`
+			AwsAutomateRoute53Prefix     string   `toml:"aws_automate_route53_prefix"`
+			AwsChefServerRoute53Prefix   string   `toml:"aws_chef_server_route53_prefix"`
+			AwsRoute53HostedZone         string   `toml:"aws_route53_hosted_zone"`
+			PostrgesqlDbIdentifier       string   `toml:"postgresql_db_identifier"`
+			ElasticsearchDomainName      string   `toml:"elasticsearch_domain_name"`
+			RDSInstanceType              string   `toml:"rds_postgresql_instance_type"`
+			RDSRestoreIdentifier         string   `toml:"rds_postgresql_restore_identifier"`
+			DatadogAPIKey                string   `toml:"datadog_api_key"`
+			UseExistingManagedInfra      bool     `toml:"use_existing_managed_infra"`
+		} `toml:"config"`
+	} `toml:"aws"`
+}
+
+type HAOnPremConfigToml struct {
+	Architecture struct {
+		ConfigInitials struct {
+			SecretsKeyFile              string `toml:"secrets_key_file,omitempty"`
+			SecretsStoreFile            string `toml:"secrets_store_file,omitempty"`
+			Architecture                string `toml:"architecture,omitempty"`
+			WorkspacePath               string `toml:"workspace_path,omitempty"`
+			SSHUser                     string `toml:"ssh_user,omitempty"`
+			SSHKeyFile                  string `toml:"ssh_key_file,omitempty"`
+			SSHPort                     string `toml:"ssh_port,omitempty"`
+			SudoPassword                string `toml:"sudo_password,omitempty"`
+			LoggingMonitoringManagement string `toml:"logging_monitoring_management,omitempty"`
+			NewElk                      string `toml:"new_elk,omitempty"`
+			ExistingElkInstanceIP       string `toml:"existing_elk_instance_ip,omitempty"`
+			ExistingElkPort             string `toml:"existing_elk_port,omitempty"`
+			ExistingElkCert             string `toml:"existing_elk_cert,omitempty"`
+			ExistingElkUsername         string `toml:"existing_elk_username,omitempty"`
+			ExistingElkPassword         string `toml:"existing_elk_password,omitempty"`
+			BackupMount                 string `toml:"backup_mount,omitempty"`
+			HabitatUIDGid               string `toml:"habitat_uid_gid,omitempty"`
+			BackupConfig                string `toml:"backup_config,omitempty"`
+		} `toml:"existing_infra"`
+	} `toml:"architecture"`
+	Automate struct {
+		Config struct {
+			AdminPassword     string     `toml:"admin_password"`
+			Fqdn              string     `toml:"fqdn"`
+			InstanceCount     string     `toml:"instance_count"`
+			TeamsPort         string     `toml:"teams_port,omitempty"`
+			ConfigFile        string     `toml:"config_file"`
+			EnableCustomCerts bool       `toml:"enable_custom_certs"`
+			RootCA            string     `toml:"root_ca"`
+			PrivateKey        string     `toml:"private_key"`
+			PublicKey         string     `toml:"public_key"`
+			CertsByIP         []CertByIP `toml:"certs_by_ip"`
+		} `toml:"config"`
+	} `toml:"automate"`
+	ChefServer struct {
+		Config struct {
+			InstanceCount     string     `toml:"instance_count"`
+			EnableCustomCerts bool       `toml:"enable_custom_certs"`
+			PrivateKey        string     `toml:"private_key"`
+			PublicKey         string     `toml:"public_key"`
+			CertsByIP         []CertByIP `toml:"certs_by_ip"`
+		} `toml:"config"`
+	} `toml:"chef_server"`
+	Opensearch struct {
+		Config struct {
+			InstanceCount     string     `toml:"instance_count"`
+			EnableCustomCerts bool       `toml:"enable_custom_certs"`
+			RootCA            string     `toml:"root_ca"`
+			AdminCert         string     `toml:"admin_cert"`
+			AdminKey          string     `toml:"admin_key"`
+			PrivateKey        string     `toml:"private_key"`
+			PublicKey         string     `toml:"public_key"`
+			AdminDn           string     `toml:"admin_dn"`
+			NodesDn           string     `toml:"nodes_dn"`
+			CertsByIP         []CertByIP `toml:"certs_by_ip"`
+		} `toml:"config"`
+	} `toml:"opensearch"`
+	Postgresql struct {
+		Config struct {
+			InstanceCount     string     `toml:"instance_count"`
+			EnableCustomCerts bool       `toml:"enable_custom_certs"`
+			RootCA            string     `toml:"root_ca"`
+			PrivateKey        string     `toml:"private_key"`
+			PublicKey         string     `toml:"public_key"`
+			CertsByIP         []CertByIP `toml:"certs_by_ip"`
+		} `toml:"config"`
+	} `toml:"postgresql"`
+	ExistingInfra struct {
+		Config struct {
+			AutomatePrivateIps   []string `toml:"automate_private_ips"`
+			ChefServerPrivateIps []string `toml:"chef_server_private_ips"`
+			OpensearchPrivateIps []string `toml:"opensearch_private_ips"`
+			PostgresqlPrivateIps []string `toml:"postgresql_private_ips"`
+		} `toml:"config"`
+	} `toml:"existing_infra"`
+	ExternalDB struct {
+		Database struct {
+			Type       string `toml:"type"`
+			PostgreSQL struct {
+				PostgreSQLInstanceURL       string `toml:"instance_url"`
+				PostgreSQLSuperUserName     string `toml:"superuser_username"`
+				PostgreSQLSuperUserPassword string `toml:"superuser_password"`
+				PostgreSQLDBUserName        string `toml:"dbuser_username"`
+				PostgreSQLDBUserPassword    string `toml:"dbuser_password"`
+				PostgreSQLCertificate       string `toml:"postgresql_certificate"`
+				PostgreSQLRootCert          string `toml:"postgresql_root_cert"`
+			} `toml:"postgre_sql"`
+			Opensearch struct {
+				OpensearchInstanceURL       string `toml:"opensearch_domain_url"`
+				OpensearchSuperUserName     string `toml:"opensearch_username"`
+				OpensearchSuperUserPassword string `toml:"opensearch_user_password"`
+				OpensearchCertificate       string `toml:"opensearch_certificate"`
+				OpensearchRootCert          string `toml:"opensearch_root_cert"`
+				OpensearchDomainName        string `toml:"opensearch_domain_name"`
+				AWS                         struct {
+					AwsOsSnapshotRoleArn  string `toml:"aws_os_snapshot_role_arn"`
+					OsUserAccessKeyId     string `toml:"os_snapshot_user_access_key_id"`
+					OsUserAccessKeySecret string `toml:"os_snapshot_user_access_key_secret"`
+				} `toml:"aws"`
+			} `toml:"open_search"`
+		} `toml:"database"`
+	} `toml:"external"`
+	ObjectStorage struct {
+		Config struct {
+			BucketName string `toml:"bucket_name"`
+			AccessKey  string `toml:"access_key"`
+			SecretKey  string `toml:"secret_key"`
+			Endpoint   string `toml:"endpoint"`
+			Region     string `toml:"region"`
+		} `toml:"config"`
+	} `toml:"object_storage"`
+}
diff --git a/lib/reporting/helperForVerification.go b/lib/reporting/helperForVerification.go
new file mode 100644
index 000000000..cef0e25c1
--- /dev/null
+++ b/lib/reporting/helperForVerification.go
@@ -0,0 +1,312 @@
+package reporting
+
+import (
+	"fmt"
+	"sort"
+	"strings"
+	"time"
+
+	"github.com/jedib0t/go-pretty/v5/table"
+)
+
+type VerificationReport struct {
+	TableKey     string
+	Report       Info
+	TotalReports int
+}
+
+type Info struct {
+	Hostip        string         `json:"hostip,omitempty"`
+	Parameter     string         `json:"parameter,omitempty"`
+	Status        string         `json:"status,omitempty"`
+	StatusMessage *StatusMessage `json:"statusMessage,omitempty"`
+	SummaryInfo   *SummaryInfo   `json:"summaryInfo,omitempty"`
+}
+
+type StatusMessage struct {
+	MainMessage string   `json:"mainMessage,omitempty"`
+	SubMessage  []string `json:"subMessage,omitempty"`
+}
+
+type SummaryInfo struct {
+	SuccessfulCount int      `json:"successfulCount,omitempty"`
+	FailedCount     int      `json:"failedCount,omitempty"`
+	ToResolve       []string `json:"toResolve,omitempty"`
+}
+
+type progress struct {
+	currentCount int
+	totalCount   int
+}
+
+func VerificationReports(reportChan chan VerificationReport, reporting Reporting, nodeInfoMap map[string][]Info, done chan bool) {
+	tableProgress := make(map[string]progress)
+	keyMap := make(map[string][]string)
+	tableKeys := reporting.GetAllTableKeys()
+	oldProgresslen := 0
+	for n := range reportChan {
+		time.Sleep(time.Second * 1)
+		report := n
+		info := report.Report
+		total := report.TotalReports
+		node := report.TableKey
+		var nodeinfo []Info
+		if _, ok := nodeInfoMap[node]; ok {
+			nodeinfo := nodeInfoMap[node]
+			nodeinfo = append(nodeinfo, info)
+			nodeInfoMap[node] = nodeinfo
+			oldCount := tableProgress[node].currentCount
+			tableProgress[node] = progress{
+				currentCount: oldCount + 1,
+				totalCount:   total,
+			}
+		} else {
+			nodeinfo = append(nodeinfo, info)
+			nodeInfoMap[node] = nodeinfo
+			keyMap[node] = matchNodeNameWithRespectiveTablesName(node, tableKeys)
+			tableProgress[node] = progress{
+				currentCount: 1,
+				totalCount:   total,
+			}
+		}
+		oldProgresslen = showProgress(tableProgress, oldProgresslen)
+	}
+	clearPrintedProgressMsg(len(tableProgress))
+	updateTablesWithData(reporting, nodeInfoMap, keyMap)
+	printTables(reporting, nodeInfoMap, keyMap)
+	done <- true
+}
+
+func printTables(reporting Reporting, nodeInfo map[string][]Info, keyMap map[string][]string) {
+	var summaryTables []*Table
+	keys := make([]string, len(nodeInfo))
+	i := 0
+	for key := range nodeInfo {
+		keys[i] = key
+		i++
+	}
+	sort.Strings(keys)
+	updateTableTitle(reporting, nodeInfo, keyMap)
+	for _, key := range keys {
+		statusTb := reporting.GetTable(keyMap[key][0])
+		summaryTb := reporting.GetTable(keyMap[key][1])
+		summaryTables = append(summaryTables, summaryTb)
+		printSingleTable(reporting, statusTb)
+	}
+	for _, summaryTable := range summaryTables {
+		printSingleTable(reporting, summaryTable)
+	}
+}
+
+func printSingleTable(reporting Reporting, table *Table) {
+	reporting.GenerateTableOutputAndPrint(table)
+	fmt.Print("\n")
+}
+
+func updateTablesWithData(reporting Reporting, nodeInfo map[string][]Info, keyMap map[string][]string) {
+	for key, value := range nodeInfo {
+		summaryMap := make(map[string]SummaryInfo)
+		statusTableRows, summaryTableRows := createSingleNodeRowsForBothTables(key, value, reporting, summaryMap)
+		reporting.GetTable(keyMap[key][0]).Rows = statusTableRows
+		reporting.GetTable(keyMap[key][1]).Rows = summaryTableRows
+	}
+}
+
+func createSingleNodeRowsForBothTables(title string, nodeInfo []Info, reporting Reporting, summaryMap map[string]SummaryInfo) ([]table.Row, []table.Row) {
+	var statusTableRows []table.Row
+	var summaryTableRows []table.Row
+	for idx, value := range nodeInfo {
+		singleRowEntry := createStatusTableRows(idx+1, &value, reporting)
+		statusTableRows = append(statusTableRows, singleRowEntry...)
+		summaryMap = createSummaryTableRowData(summaryMap, &value)
+	}
+	summaryTableRows = createSummaryTableRows(summaryMap, reporting)
+	return statusTableRows, summaryTableRows
+}
+
+func createStatusTableRows(index int, rowData *Info, reporting Reporting) []table.Row {
+	var row table.Row
+	var rows []table.Row
+
+	if rowData.Status == "Success" {
+		row = successRow(index, rowData, reporting)
+		rows = append(rows, row)
+	} else if rowData.Status == "Failed" {
+
+		row = failedRow(index, rowData, reporting)
+		rows = append(rows, row)
+	}
+	if len(rowData.StatusMessage.SubMessage) > 0 {
+		for _, value := range rowData.StatusMessage.SubMessage {
+			row = subMessageRow(value, rowData, reporting)
+			rows = append(rows, row)
+		}
+	}
+	return rows
+}
+
+func successRow(index int, rowData *Info, reporting Reporting) table.Row {
+	hostip := rowData.Hostip
+	parameter := rowData.Parameter
+	status := reporting.ChangeColour(Green, reporting.AppendSpecialCharater(Success, rowData.Status))
+	message := rowData.StatusMessage.MainMessage
+	row := table.Row{index, hostip, parameter, status, message}
+	return row
+}
+
+func failedRow(index int, rowData *Info, reporting Reporting) table.Row {
+	hostip := reporting.ChangeColour(Red, rowData.Hostip)
+	parameter := reporting.ChangeColour(Red, rowData.Parameter)
+	status := reporting.ChangeColour(Red, reporting.AppendSpecialCharater(Failed, rowData.Status))
+	message := reporting.ChangeColour(Red, rowData.StatusMessage.MainMessage)
+
+	row := table.Row{index, hostip, parameter, status, message}
+	return row
+}
+
+func subMessageRow(subMsg string, rowData *Info, reporting Reporting) table.Row {
+	var newSubMessage string
+	if rowData.Status == "Failed" {
+		key := reporting.AppendSpecialCharater(Failed, reporting.AppendSpecialCharater(SquareBracket, rowData.Status))
+		newSubMessage = reporting.ChangeColour(Red, key+subMsg)
+	} else {
+		key := reporting.ChangeColour(Yellow, reporting.AppendSpecialCharater(Warning, reporting.AppendSpecialCharater(SquareBracket, "Warning")))
+		newSubMessage = key + subMsg
+	}
+	row := table.Row{"", "", "", "", newSubMessage}
+	return row
+}
+
+func createSummaryTableRowData(summary map[string]SummaryInfo, rowData *Info) map[string]SummaryInfo {
+	var toResolve []string
+	if rowData.SummaryInfo.ToResolve != nil && len(rowData.SummaryInfo.ToResolve) > 0 {
+		toResolve = []string{fmt.Sprintf("%s:", rowData.Hostip)}
+		rowData.SummaryInfo.ToResolve = createIndexForToResolve(rowData.SummaryInfo.ToResolve)
+		toResolve = append(toResolve, rowData.SummaryInfo.ToResolve...)
+	}
+	if _, ok := summary[rowData.Parameter]; ok {
+		singleParameterSummary := summary[rowData.Parameter]
+		singleParameterSummary.SuccessfulCount = singleParameterSummary.SuccessfulCount + rowData.SummaryInfo.SuccessfulCount
+		singleParameterSummary.FailedCount = singleParameterSummary.FailedCount + rowData.SummaryInfo.FailedCount
+		singleParameterSummary.ToResolve = append(singleParameterSummary.ToResolve, toResolve...)
+
+		summary[rowData.Parameter] = singleParameterSummary
+		return summary
+	}
+
+	summary[rowData.Parameter] = SummaryInfo{
+		SuccessfulCount: rowData.SummaryInfo.SuccessfulCount,
+		FailedCount:     rowData.SummaryInfo.FailedCount,
+		ToResolve:       toResolve,
+	}
+
+	return summary
+}
+
+func createSummaryTableRows(rowData map[string]SummaryInfo, reporting Reporting) []table.Row {
+	var rows []table.Row
+	for key, value := range rowData {
+		if key != "" {
+			singleParameterRow := createSingleParameterRows(key, value, reporting)
+			rows = append(rows, singleParameterRow...)
+		}
+	}
+	return rows
+}
+
+func createSingleParameterRows(parameter string, parameterSummary SummaryInfo, reporting Reporting) []table.Row {
+	var row table.Row
+	var rows []table.Row
+	successCount := reporting.ChangeColour(Green, fmt.Sprintf("%d", parameterSummary.SuccessfulCount))
+	failedCount := reporting.ChangeColour(Red, fmt.Sprintf("%d", parameterSummary.FailedCount))
+	toResolve := parameterSummary.ToResolve
+	if len(toResolve) > 1 {
+		row = table.Row{parameter, successCount, failedCount, toResolve[0]}
+		rows = append(rows, row)
+		for _, value := range toResolve[1:] {
+			row = table.Row{"", "", "", value}
+			rows = append(rows, row)
+		}
+	} else {
+		row = table.Row{parameter, successCount, failedCount, ""}
+		rows = append(rows, row)
+	}
+	return rows
+}
+
+func showProgress(tableProgess map[string]progress, lines int) int {
+	clearPrintedProgressMsg(lines)
+	keys := make([]string, len(tableProgess))
+	i := 0
+	for key := range tableProgess {
+		keys[i] = key
+		i++
+	}
+	sort.Strings(keys)
+	for _, key := range keys {
+		percent := float64(tableProgess[key].currentCount) / float64(tableProgess[key].totalCount) * 100
+		progressMsg := fmt.Sprintf("%-12s %.2f%%\n", key, percent)
+		fmt.Print(progressMsg)
+	}
+	return len(keys)
+}
+
+func clearPrintedProgressMsg(lines int) {
+	if lines > 0 {
+		fmt.Printf("\033[%dA\033[J", lines)
+	}
+}
+
+func updateTableTitle(reporting Reporting, nodeInfo map[string][]Info, keyMap map[string][]string) {
+	var failed bool
+	for key, value := range nodeInfo {
+		title := reporting.GetTable(keyMap[key][0]).Title
+		if checkStatusNotEmpty(value) {
+			return
+		}
+		failed = checkFailedStatus(value)
+		if failed {
+			updatedTile := reporting.ChangeColour(Red, reporting.AppendSpecialCharater(Failed, title))
+			reporting.GetTable(keyMap[key][0]).Title = updatedTile
+		} else {
+			updatedTile := reporting.ChangeColour(Green, reporting.AppendSpecialCharater(Success, title))
+			reporting.GetTable(keyMap[key][0]).Title = updatedTile
+		}
+	}
+}
+
+func checkStatusNotEmpty(info []Info) bool {
+	for _, v := range info {
+		if v.Status == "" {
+			return true
+		}
+	}
+	return false
+}
+
+func checkFailedStatus(info []Info) bool {
+	for _, v := range info {
+		if v.Status == "Failed" {
+			return true
+		}
+	}
+	return false
+}
+
+func matchNodeNameWithRespectiveTablesName(substring string, keys []string) []string {
+	var matchingKeys []string
+	for _, key := range keys {
+		if strings.Contains(key, substring) {
+			matchingKeys = append(matchingKeys, key)
+		}
+	}
+	sort.Strings(matchingKeys)
+	return matchingKeys
+}
+
+func createIndexForToResolve(data []string) []string {
+	for key, value := range data {
+		data[key] = fmt.Sprintf("%d. %s", key+1, value)
+	}
+	return data
+}
diff --git a/lib/reporting/reporting.go b/lib/reporting/reporting.go
new file mode 100644
index 000000000..b054252a6
--- /dev/null
+++ b/lib/reporting/reporting.go
@@ -0,0 +1,130 @@
+package reporting
+
+import (
+	"sort"
+
+	"github.com/chef/automate/components/automate-deployment/pkg/cli"
+	"github.com/fatih/color"
+	"github.com/jedib0t/go-pretty/v5/table"
+)
+
+const (
+	Red = iota
+	Green
+	Yellow
+)
+
+const (
+	Failed = iota
+	Success
+	Warning
+	SquareBracket
+)
+
+type Reporting interface {
+	GetTable(key string) *Table
+	SetTable(key string, table *Table)
+	GetAllTableKeys() []string
+	GetAllTables() map[string]*Table
+	AppendSpecialCharater(symbol int, str string) string
+	ChangeColour(fgColor int, msg string) string
+	GenerateTableOutputAndPrint(table *Table)
+}
+
+type Table struct {
+	Title     string
+	Rows      []table.Row
+	Header    table.Row
+	Footer    table.Row
+	ColConfig []table.ColumnConfig
+}
+
+type ReportingModule struct {
+	writer *cli.Writer
+	tables map[string]*Table
+}
+
+func NewReportingModule(wr *cli.Writer, tables map[string]*Table) Reporting {
+	newReportingModule := &ReportingModule{
+		writer: wr,
+		tables: tables,
+	}
+	return newReportingModule
+}
+
+// GetTable returns table present in tables map for given key.
+func (r *ReportingModule) GetTable(key string) *Table {
+	return r.tables[key]
+}
+
+// GetAllTableKeys returns all keys present in tables map
+func (r *ReportingModule) GetAllTableKeys() []string {
+	keys := make([]string, len(r.tables))
+	i := 0
+	for key := range r.tables {
+		keys[i] = key
+		i++
+	}
+	sort.Strings(keys)
+	return keys
+}
+
+// GetAllTables returns tables map
+func (r *ReportingModule) GetAllTables() map[string]*Table {
+	return r.tables
+}
+
+// SetTable sets the value of tables[key] in tables map to table provided in argument
+func (r *ReportingModule) SetTable(key string, table *Table) {
+	r.tables[key] = table
+}
+
+// AppendSpecialCharater returns a string.
+// Function appends a special char at the start of the str provided in arguments and returns that string
+func (r *ReportingModule) AppendSpecialCharater(symbol int, str string) string {
+	failedSymbol := "✖ "
+	successSymbol := "✔ "
+	warningSymbol := "! "
+
+	switch symbol {
+	case Failed:
+		msg := failedSymbol + str
+		return msg
+	case Success:
+		msg := successSymbol + str
+		return msg
+	case Warning:
+		msg := warningSymbol + str
+		return msg
+	case SquareBracket:
+		msg := "[ " + str + " ] "
+		return msg
+	}
+
+	return str
+}
+
+// ChangeColour returns a string.
+// Function changes the color of the msg provided in arguments to the color given
+func (r *ReportingModule) ChangeColour(fgColor int, msg string) string {
+	switch fgColor {
+	case Red:
+		return color.New(color.FgRed).Sprint(msg)
+	case Green:
+		return color.New(color.FgGreen).Sprint(msg)
+	case Yellow:
+		return color.New(color.FgYellow).Sprint(msg)
+	default:
+		return msg
+	}
+}
+
+// GenerateTableOutputAndPrint prints table provided as argument
+func (r *ReportingModule) GenerateTableOutputAndPrint(tb *Table) {
+	tbWriter := table.NewWriter()
+	tbWriter.SetColumnConfigs(tb.ColConfig)
+	tbWriter.AppendHeader(tb.Header)
+	tbWriter.AppendRows(tb.Rows)
+	r.writer.Println(tb.Title)
+	r.writer.Println(tbWriter.Render())
+}
diff --git a/lib/verification/checks.go b/lib/verification/checks.go
new file mode 100644
index 000000000..849059ab9
--- /dev/null
+++ b/lib/verification/checks.go
@@ -0,0 +1,271 @@
+package verification
+
+import (
+	sc "github.com/chef/automate/api/config/deployment"
+	"github.com/chef/automate/lib/config_parser"
+	"github.com/chef/automate/lib/reporting"
+)
+
+const (
+	systemResources  = "System Resources"
+	softwareVersions = "Software Versions"
+)
+
+type Result struct {
+	Valid  bool
+	Report reporting.Info
+}
+
+func validateAWSProvisionConfig(config *config_parser.HAAwsConfigToml) {
+
+	/* Write the checks to validate if all the required fields for AWS Infra Provision without Managed Services
+	are filled in the parsed config */
+
+	if config.Aws.Config.SetupManagedServices {
+		/* Write the checks to validate if all the required fields for AWS Infra Provision with Managed Services
+		are filled in the parsed config */
+	}
+
+}
+
+func validateAWSManagedProvisionConfig(config *config_parser.HAAwsConfigToml) {
+
+	/* Write the checks to validate if all the required fields for AWS Infra Provision with Managed Services
+	are filled in the parsed config */
+
+}
+
+func validateAWSDeploymentConfig(config *config_parser.HAAwsConfigToml) {
+
+	/* Write the checks to validate if all the required fields for AWS Deployment without Managed Services
+	are filled in the parsed config */
+
+}
+
+func validateAWSManagedDeploymentConfig(config *config_parser.HAAwsConfigToml) {
+
+	/* Write the checks to validate if all the required fields for AWS Deployment with Managed Services
+	are filled in the parsed config */
+
+}
+
+func validateOnPremConfig(config *config_parser.HAOnPremConfigToml) {
+
+	/* Write the checks to validate if all the required fields for On-Prem Deployment with Chef Managed Services
+	are filled in the parsed config */
+
+}
+
+func validateOnPremAWSConfig(config *config_parser.HAOnPremConfigToml) {
+
+	/* Write the checks to validate if all the required fields for On-Prem Deployment with AWS Managed Services
+	are filled in the parsed config */
+
+}
+
+func validateOnPremCustomerConfig(config *config_parser.HAOnPremConfigToml) {
+
+	/* Write the checks to validate if all the required fields for On-Prem Deployment with Customer Managed Services
+	are filled in the parsed config */
+
+}
+
+func validateStandaloneDeploymentConfig(config *sc.AutomateConfig) {
+
+	/* Write the checks to validate if all the required fields for On-Prem Deployment with Customer Managed Services
+	are filled in the parsed config */
+
+}
+
+func validateNodeReachability(ipaddress string, nodeType string, channel chan reporting.VerificationReport, numberOfNodes *numberOfNodes) {
+
+	/* Write the checks to validate if the nodes are reachable */
+
+	result := reporting.Info{
+		Hostip:    ipaddress,
+		Parameter: "Node Reachabilility",
+		Status:    "Success",
+		StatusMessage: &reporting.StatusMessage{
+			MainMessage: "Node " + ipaddress + " is reachable",
+		},
+		SummaryInfo: &reporting.SummaryInfo{
+			SuccessfulCount: 1,
+		},
+	}
+
+	chanWriter(channel, nodeType, result, numberOfNodes)
+
+}
+
+func validateCertificateExpiry(ipaddress string, certContents string) Result {
+
+	return Result{
+		Valid: true,
+		Report: reporting.Info{
+			Hostip:    ipaddress,
+			Parameter: "Certificates",
+			Status:    "Success",
+			StatusMessage: &reporting.StatusMessage{
+				MainMessage: "Certificate A validated successfully",
+			},
+		},
+	}
+
+	/* Write the checks to validate the expiry date of the certificate */
+
+}
+
+func validateCertificateFormat(ipaddress string, certContents string) Result {
+
+	return Result{
+		Valid: true,
+		Report: reporting.Info{
+			Hostip:    ipaddress,
+			Parameter: "Certificates",
+			Status:    "Failed",
+			StatusMessage: &reporting.StatusMessage{
+				MainMessage: "Certificate B validation failed",
+				SubMessage:  []string{"Certificate is not formatted properly"},
+			},
+			SummaryInfo: &reporting.SummaryInfo{
+				ToResolve: []string{"Add the start and end certificate markers"},
+			},
+		},
+	}
+
+	/* Write the checks to validate the expiry date of the certificate */
+
+}
+
+func validateFreeDisk(ipaddress string, nodeType string) Result {
+
+	if nodeType == "OpenSearch" {
+		return Result{
+			Valid: false,
+			Report: reporting.Info{
+				Hostip:    ipaddress,
+				Parameter: systemResources,
+				Status:    "Failed",
+				StatusMessage: &reporting.StatusMessage{
+					MainMessage: "System Resources check failed",
+					SubMessage:  []string{"/hab volume is not of 100 GB"},
+				},
+				SummaryInfo: &reporting.SummaryInfo{
+					ToResolve: []string{"Re-mount the hab volume with 100 GB"},
+				},
+			},
+		}
+	}
+	return Result{
+		Valid: true,
+		Report: reporting.Info{
+			Hostip:    ipaddress,
+			Parameter: systemResources,
+			Status:    "Success",
+			StatusMessage: &reporting.StatusMessage{
+				MainMessage: "System Resources as per the requirement",
+			},
+		},
+	}
+
+}
+
+func validateCPU(ipaddress string, nodeType string) Result {
+
+	if nodeType == "ChefServer" {
+		return Result{
+			Valid: true,
+			Report: reporting.Info{
+				Hostip:    ipaddress,
+				Parameter: systemResources,
+				Status:    "Success",
+				StatusMessage: &reporting.StatusMessage{
+					MainMessage: "System Resources as per the requirement",
+				},
+			},
+		}
+	}
+	return Result{
+		Valid: false,
+		Report: reporting.Info{
+			Hostip:    ipaddress,
+			Parameter: systemResources,
+			Status:    "Failed",
+			StatusMessage: &reporting.StatusMessage{
+				MainMessage: "System Resources check failed",
+				SubMessage:  []string{"CPU count is not as per the requirement"},
+			},
+			SummaryInfo: &reporting.SummaryInfo{
+				ToResolve: []string{"Increase the CPU of the machine. Machine should have 4 CPUs"},
+			},
+		},
+	}
+
+}
+
+func validateOSVersion(ipaddress string, nodeType string) Result {
+
+	if nodeType == "Automate" {
+		return Result{
+			Valid: false,
+			Report: reporting.Info{
+				Hostip:    ipaddress,
+				Parameter: softwareVersions,
+				Status:    "Failed",
+				StatusMessage: &reporting.StatusMessage{
+					MainMessage: "Software Versions check Failed",
+					SubMessage:  []string{"OS version is not Ubuntu 20.04"},
+				},
+				SummaryInfo: &reporting.SummaryInfo{
+					ToResolve: []string{"Setup the machine with Ubuntu 20.04"},
+				},
+			},
+		}
+	}
+	return Result{
+		Valid: true,
+		Report: reporting.Info{
+			Hostip:    ipaddress,
+			Parameter: softwareVersions,
+			Status:    "Success",
+			StatusMessage: &reporting.StatusMessage{
+				MainMessage: "Software Versions check Passed",
+			},
+		},
+	}
+
+}
+
+func validateLinuxCommands(ipaddress string, nodeType string) Result {
+
+	if nodeType == "OpenSearch" {
+		return Result{
+			Valid: true,
+			Report: reporting.Info{
+				Hostip:    ipaddress,
+				Parameter: softwareVersions,
+				Status:    "Success",
+				StatusMessage: &reporting.StatusMessage{
+					MainMessage: "Software Versions check Failed",
+					SubMessage:  []string{"make command failed"},
+				},
+				SummaryInfo: &reporting.SummaryInfo{
+					ToResolve: []string{"Add the required paths in the PATH folder"},
+				},
+			},
+		}
+	}
+
+	return Result{
+		Valid: true,
+		Report: reporting.Info{
+			Hostip:    ipaddress,
+			Parameter: softwareVersions,
+			Status:    "Success",
+			StatusMessage: &reporting.StatusMessage{
+				MainMessage: "Software Versions check Passed",
+			},
+		},
+	}
+
+}
diff --git a/lib/verification/mockVerify.go b/lib/verification/mockVerify.go
new file mode 100644
index 000000000..b8318648b
--- /dev/null
+++ b/lib/verification/mockVerify.go
@@ -0,0 +1,49 @@
+package verification
+
+type VerificationMock struct {
+	VerifyHAAWSProvisionFunc              func(configFile string) error
+	VerifyHAAWSManagedProvisionFunc       func(configFile string) error
+	VerifyHAAWSDeploymentFunc             func(configFile string) error
+	VerifyHAAWSManagedDeploymentFunc      func(configFile string) error
+	VerifyOnPremDeploymentFunc            func(configFile string) error
+	VerifyOnPremAWSManagedDeploymentFunc  func(configFile string) error
+	VerifyOnPremCustManagedDeploymentFunc func(configFile string) error
+	VerifyStandaloneDeploymentFunc        func(configFile string) error
+	VerifyCertificatesFunc                func(configFile string) error
+}
+
+func (v *VerificationMock) VerifyHAAWSProvision(configFile string) error {
+	return v.VerifyHAAWSProvisionFunc(configFile)
+}
+
+func (v *VerificationMock) VerifyHAAWSManagedProvision(configFile string) error {
+	return v.VerifyHAAWSManagedProvisionFunc(configFile)
+}
+
+func (v *VerificationMock) VerifyHAAWSDeployment(configFile string) error {
+	return v.VerifyHAAWSDeploymentFunc(configFile)
+}
+
+func (v *VerificationMock) VerifyHAAWSManagedDeployment(configFile string) error {
+	return v.VerifyHAAWSManagedDeploymentFunc(configFile)
+}
+
+func (v *VerificationMock) VerifyOnPremDeployment(configFile string) error {
+	return v.VerifyOnPremDeploymentFunc(configFile)
+}
+
+func (v *VerificationMock) VerifyOnPremAWSManagedDeployment(configFile string) error {
+	return v.VerifyOnPremAWSManagedDeploymentFunc(configFile)
+}
+
+func (v *VerificationMock) VerifyOnPremCustManagedDeployment(configFile string) error {
+	return v.VerifyOnPremCustManagedDeploymentFunc(configFile)
+}
+
+func (v *VerificationMock) VerifyStandaloneDeployment(configFile string) error {
+	return v.VerifyStandaloneDeploymentFunc(configFile)
+}
+
+func (v *VerificationMock) VerifyCertificates(configFile string) error {
+	return v.VerifyCertificatesFunc(configFile)
+}
diff --git a/lib/verification/verify.go b/lib/verification/verify.go
new file mode 100644
index 000000000..2684228d0
--- /dev/null
+++ b/lib/verification/verify.go
@@ -0,0 +1,425 @@
+package verification
+
+import (
+	"fmt"
+	"os"
+	"sync"
+
+	"github.com/chef/automate/components/automate-deployment/pkg/cli"
+	"github.com/chef/automate/lib/config_parser"
+	"github.com/chef/automate/lib/reporting"
+	"github.com/jedib0t/go-pretty/v5/table"
+)
+
+type Verification interface {
+	VerifyHAAWSProvision(configFile string) error
+	VerifyHAAWSManagedProvision(configFile string) error
+	VerifyHAAWSDeployment(configFile string) error
+	VerifyHAAWSManagedDeployment(configFile string) error
+	VerifyOnPremDeployment(configFile string) error
+	VerifyOnPremAWSManagedDeployment(configFile string) error
+	VerifyOnPremCustManagedDeployment(configFile string) error
+	VerifyStandaloneDeployment(configFile string) error
+	VerifyCertificates(configFile string) error
+}
+
+type VerificationModule struct{}
+
+type report struct {
+	ipaddress             string
+	parameter             string
+	message               string
+	errors                []string
+	resolutions           []string
+	successfulChecksCount int
+	failedChecksCount     int
+}
+
+type numberOfNodes struct {
+	numberOfAutomateNodes    int
+	numberOfChefServerNodes  int
+	numberOfPostgresSQLNodes int
+	numberOfOpenSearchNodes  int
+}
+
+var reportChan = make(chan reporting.VerificationReport)
+var nodeInfoMap = make(map[string][]reporting.Info)
+var doneChan = make(chan bool, 1)
+
+func (v *VerificationModule) VerifyHAAWSProvision(configFile string) error {
+	configParser := &config_parser.ConfigParserImpl{}
+	config, err := configParser.ParseAWSAutomateConfig(configFile)
+	if err != nil {
+		return err
+	}
+
+	validateAWSProvisionConfig(config)
+	return nil
+}
+
+func (v *VerificationModule) VerifyHAAWSManagedProvision(configFile string) error {
+	configParser := &config_parser.ConfigParserImpl{}
+	config, err := configParser.ParseAWSAutomateConfig(configFile)
+	if err != nil {
+		return err
+	}
+	validateAWSManagedProvisionConfig(config)
+	return nil
+}
+
+func (v *VerificationModule) VerifyHAAWSDeployment(configFile string) error {
+	configParser := &config_parser.ConfigParserImpl{}
+	config, err := configParser.ParseAWSAutomateConfig(configFile)
+	if err != nil {
+		return err
+	}
+	validateAWSDeploymentConfig(config)
+	return nil
+}
+
+func (v *VerificationModule) VerifyHAAWSManagedDeployment(configFile string) error {
+	configParser := &config_parser.ConfigParserImpl{}
+	config, err := configParser.ParseAWSAutomateConfig(configFile)
+	if err != nil {
+		return err
+	}
+	validateAWSManagedDeploymentConfig(config)
+	return nil
+}
+
+func (v *VerificationModule) VerifyOnPremAWSManagedDeployment(configFile string) error {
+	configParser := &config_parser.ConfigParserImpl{}
+	config, err := configParser.ParseOnPremConfig(configFile)
+	if err != nil {
+		return err
+	}
+	validateOnPremAWSConfig(config)
+	return nil
+}
+
+func (v *VerificationModule) VerifyOnPremCustManagedDeployment(configFile string) error {
+	configParser := &config_parser.ConfigParserImpl{}
+	config, err := configParser.ParseOnPremConfig(configFile)
+	if err != nil {
+		return err
+	}
+	validateOnPremCustomerConfig(config)
+	return nil
+}
+
+func (v *VerificationModule) VerifyStandaloneDeployment(configFile string) error {
+	configParser := &config_parser.ConfigParserImpl{}
+	config, err := configParser.ParseStandaloneConfig(configFile)
+	if err != nil {
+		return err
+	}
+	validateStandaloneDeploymentConfig(config)
+	return nil
+}
+
+func (v *VerificationModule) VerifyCertificates(certContents string) error {
+
+	return nil
+}
+
+func (v *VerificationModule) VerifyOnPremDeployment(configFile string) error {
+
+	configParser := &config_parser.ConfigParserImpl{}
+	config, err := configParser.ParseOnPremConfig(configFile)
+	if err != nil {
+		return err
+	}
+	var ipsMap = make(map[string]string)
+	automateIps := config.ExistingInfra.Config.AutomatePrivateIps
+	chefServerIps := config.ExistingInfra.Config.ChefServerPrivateIps
+	opensearchIps := config.ExistingInfra.Config.OpensearchPrivateIps
+	postgresIps := config.ExistingInfra.Config.PostgresqlPrivateIps
+
+	dataMap := map[string][]string{
+		"Automate":    automateIps,
+		"ChefServer":  chefServerIps,
+		"OpenSearch":  opensearchIps,
+		"PostgresSQL": postgresIps,
+	}
+
+	for nodeType, nodeIps := range dataMap {
+		constructMap(nodeIps, nodeType, &ipsMap)
+	}
+
+	numberOfNodes := &numberOfNodes{
+		numberOfAutomateNodes:    len(automateIps),
+		numberOfChefServerNodes:  len(chefServerIps),
+		numberOfPostgresSQLNodes: len(postgresIps),
+		numberOfOpenSearchNodes:  len(opensearchIps),
+	}
+
+	startReportModule(numberOfNodes)
+
+	//validateOnPremConfig(config)
+
+	runTests(ipsMap, numberOfNodes)
+
+	return nil
+}
+
+func constructMap(nodeIps []string, nodeType string, m *map[string]string) {
+	for _, val := range nodeIps {
+		(*m)[val] = nodeType
+	}
+}
+
+func runTests(ipsMap map[string]string, numberOfNodes *numberOfNodes) {
+	var wg sync.WaitGroup
+
+	for k, v := range ipsMap {
+		wg.Add(3)
+		ip := fmt.Sprintf("%v", k)
+		nodeType := fmt.Sprintf("%v", v)
+		if nodeType == "OpenSearch" || nodeType == "PostgresSQL" {
+			wg.Add(1)
+			go func() {
+				defer wg.Done()
+				producerChan := make(chan bool, 1)
+				runChecksForCertificates(ip, nodeType, producerChan, numberOfNodes)
+			}()
+		}
+		go func() {
+			defer wg.Done()
+			validateNodeReachability(ip, nodeType, reportChan, numberOfNodes)
+		}()
+		go func() {
+			defer wg.Done()
+			runChecksForSystemResources(ip, nodeType, numberOfNodes)
+		}()
+		go func() {
+			defer wg.Done()
+			runChecksForSoftwareVersions(ip, nodeType, numberOfNodes)
+		}()
+	}
+	wg.Wait()
+	close(reportChan)
+	if <-doneChan {
+		fmt.Println("done!!")
+	}
+}
+
+func runChecksForCertificates(ipaddress string, nodeType string, doneChan chan bool, numberOfNodes *numberOfNodes) {
+	var successCount, failedCount int
+	result := validateCertificateFormat(ipaddress, "abc")
+	if !result.Valid {
+		failedCount++
+		result.Report.SummaryInfo.FailedCount = failedCount
+		chanWriter(reportChan, nodeType, result.Report, numberOfNodes)
+	} else {
+		result = validateCertificateExpiry(ipaddress, "abc")
+		if !result.Valid {
+			failedCount++
+			result.Report.SummaryInfo.FailedCount = failedCount
+			chanWriter(reportChan, nodeType, result.Report, numberOfNodes)
+		} else {
+			successCount++
+			report := report{
+				ipaddress:             ipaddress,
+				parameter:             "Certificates",
+				message:               "Certificate validation successful",
+				successfulChecksCount: successCount,
+			}
+			chanWriter(reportChan, nodeType, getReport(report, "Success"), numberOfNodes)
+		}
+	}
+	doneChan <- true
+}
+
+func runChecksForSystemResources(ipaddress string, nodeType string, numberOfNodes *numberOfNodes) {
+	var successCount, failedCount int
+	var errors []string
+	var resolutions []string
+	failed := false
+
+	result := validateFreeDisk(ipaddress, nodeType)
+	if !result.Valid {
+		errors = append(errors, result.Report.StatusMessage.SubMessage...)
+		resolutions = append(resolutions, result.Report.SummaryInfo.ToResolve...)
+		failed = true
+		failedCount++
+	} else if result.Valid && result.Report.StatusMessage.SubMessage != nil {
+		errors = append(errors, result.Report.StatusMessage.SubMessage...)
+		resolutions = append(resolutions, result.Report.SummaryInfo.ToResolve...)
+		successCount++
+	} else if result.Valid {
+		successCount++
+	}
+
+	result = validateCPU(ipaddress, nodeType)
+	if !result.Valid {
+		errors = append(errors, result.Report.StatusMessage.SubMessage...)
+		resolutions = append(resolutions, result.Report.SummaryInfo.ToResolve...)
+		failed = true
+		failedCount++
+	} else if result.Valid && result.Report.StatusMessage.SubMessage != nil {
+		errors = append(errors, result.Report.StatusMessage.SubMessage...)
+		resolutions = append(resolutions, result.Report.SummaryInfo.ToResolve...)
+		successCount++
+	} else if result.Valid {
+		successCount++
+	}
+
+	if failed {
+		report := report{
+			ipaddress:             ipaddress,
+			parameter:             "System Resources",
+			message:               "System Resource Check failed",
+			errors:                errors,
+			resolutions:           resolutions,
+			failedChecksCount:     failedCount,
+			successfulChecksCount: successCount,
+		}
+		chanWriter(reportChan, nodeType, getReport(report, "Failed"), numberOfNodes)
+
+	} else {
+		report := report{
+			ipaddress:             ipaddress,
+			parameter:             "System Resources",
+			message:               "All System Resources are as per the requirement",
+			errors:                errors,
+			resolutions:           resolutions,
+			failedChecksCount:     failedCount,
+			successfulChecksCount: successCount,
+		}
+		chanWriter(reportChan, nodeType, getReport(report, "Success"), numberOfNodes)
+	}
+}
+
+func runChecksForSoftwareVersions(ipaddress string, nodeType string, numberOfNodes *numberOfNodes) {
+	var successCount, failedCount int
+	var errors []string
+	var resolutions []string
+	failed := false
+
+	result := validateOSVersion(ipaddress, nodeType)
+	if !result.Valid {
+		errors = append(errors, result.Report.StatusMessage.SubMessage...)
+		resolutions = append(resolutions, result.Report.SummaryInfo.ToResolve...)
+		failed = true
+		failedCount++
+	} else if result.Valid && result.Report.StatusMessage.SubMessage != nil {
+		errors = append(errors, result.Report.StatusMessage.SubMessage...)
+		resolutions = append(resolutions, result.Report.SummaryInfo.ToResolve...)
+		successCount++
+	} else if result.Valid {
+		successCount++
+	}
+
+	result = validateLinuxCommands(ipaddress, nodeType)
+	if !result.Valid {
+		errors = append(errors, result.Report.StatusMessage.SubMessage...)
+		resolutions = append(resolutions, result.Report.SummaryInfo.ToResolve...)
+		failed = true
+		failedCount++
+	} else if result.Valid && result.Report.StatusMessage.SubMessage != nil {
+		errors = append(errors, result.Report.StatusMessage.SubMessage...)
+		resolutions = append(resolutions, result.Report.SummaryInfo.ToResolve...)
+		successCount++
+	} else if result.Valid {
+		successCount++
+	}
+
+	if failed {
+		report := report{
+			ipaddress:             ipaddress,
+			parameter:             result.Report.Parameter,
+			message:               result.Report.StatusMessage.MainMessage,
+			errors:                errors,
+			resolutions:           resolutions,
+			failedChecksCount:     failedCount,
+			successfulChecksCount: successCount,
+		}
+		chanWriter(reportChan, nodeType, getReport(report, "Failed"), numberOfNodes)
+
+	} else {
+		report := report{
+			ipaddress:             ipaddress,
+			parameter:             result.Report.Parameter,
+			message:               result.Report.StatusMessage.MainMessage,
+			errors:                errors,
+			resolutions:           resolutions,
+			failedChecksCount:     failedCount,
+			successfulChecksCount: successCount,
+		}
+		chanWriter(reportChan, nodeType, getReport(report, "Success"), numberOfNodes)
+	}
+}
+
+func getReport(testReport report, status string) reporting.Info {
+	return reporting.Info{
+		Hostip:    testReport.ipaddress,
+		Parameter: testReport.parameter,
+		Status:    status,
+		StatusMessage: &reporting.StatusMessage{
+			MainMessage: testReport.message,
+			SubMessage:  testReport.errors,
+		},
+		SummaryInfo: &reporting.SummaryInfo{
+			ToResolve:       testReport.resolutions,
+			SuccessfulCount: testReport.successfulChecksCount,
+			FailedCount:     testReport.failedChecksCount,
+		},
+	}
+}
+
+func startReportModule(nodeNumbers *numberOfNodes) {
+	wr := cli.NewWriter(os.Stdout, os.Stderr, os.Stdin)
+	tb := createTables(nodeNumbers)
+	rp := reporting.NewReportingModule(wr, tb)
+	go reporting.VerificationReports(reportChan, rp, nodeInfoMap, doneChan)
+}
+
+func createTables(nodeNumbers *numberOfNodes) map[string]*reporting.Table {
+	automateSummaryTableTitle := fmt.Sprintf("Summary: Automate <Nodes> - %d", nodeNumbers.numberOfAutomateNodes)
+	chefServerSummaryTableTitle := fmt.Sprintf("Summary: Chef Infra Server <Nodes> - %d", nodeNumbers.numberOfChefServerNodes)
+	postgresSQLSummaryTableTitle := fmt.Sprintf("Summary: PostgresSQL <Nodes> - %d", nodeNumbers.numberOfPostgresSQLNodes)
+	openSearchSummaryTableTitle := fmt.Sprintf("Summary: Opensearch <Nodes> - %d", nodeNumbers.numberOfOpenSearchNodes)
+	tb := make(map[string]*reporting.Table)
+	tb["AutomateStatusTable"] = getStatusTable("Automate")
+	tb["AutomateSummaryTable"] = getSummaryTable(automateSummaryTableTitle)
+	tb["ChefServerStatusTable"] = getStatusTable("Chef Infra Server")
+	tb["ChefServerSummaryTable"] = getSummaryTable(chefServerSummaryTableTitle)
+	tb["PostgresSQLStatusTable"] = getStatusTable("PostgresSQL")
+	tb["PostgresSQLSummaryTable"] = getSummaryTable(postgresSQLSummaryTableTitle)
+	tb["OpenSearchStatusTable"] = getStatusTable("OpenSearch")
+	tb["OpenSearchSummaryTable"] = getSummaryTable(openSearchSummaryTableTitle)
+	return tb
+}
+
+func getStatusTable(title string) *reporting.Table {
+	return &reporting.Table{
+		Title:     title,
+		Header:    table.Row{"No.", "Identifier", "Parameter", "Status", "Message"},
+		ColConfig: []table.ColumnConfig{{Number: 1, WidthMax: 5, WidthMin: 5}, {Number: 2, WidthMax: 15, WidthMin: 15}, {Number: 3, WidthMax: 25, WidthMin: 25}, {Number: 4, WidthMax: 15, WidthMin: 15}, {Number: 5, WidthMax: 60, WidthMin: 60}},
+	}
+}
+
+func getSummaryTable(title string) *reporting.Table {
+	return &reporting.Table{
+		Title:     title,
+		Header:    table.Row{"Parameter", "Successful", "Failed", "How to resolve it"},
+		ColConfig: []table.ColumnConfig{{Number: 1, WidthMax: 30, WidthMin: 30}, {Number: 2, WidthMax: 15, WidthMin: 15}, {Number: 3, WidthMax: 15, WidthMin: 15}, {Number: 4, WidthMax: 60, WidthMin: 60}},
+	}
+}
+
+func chanWriter(reportChan chan reporting.VerificationReport, nodeType string, report reporting.Info, nodeNumbers *numberOfNodes) {
+	total := 3 * nodeNumbers.numberOfAutomateNodes
+	if nodeType == "ChefServer" {
+		total = 3 * nodeNumbers.numberOfChefServerNodes
+	} else if nodeType == "OpenSearch" {
+		total = 4 * nodeNumbers.numberOfOpenSearchNodes
+	} else if nodeType == "PostgresSQL" {
+		total = 4 * nodeNumbers.numberOfPostgresSQLNodes
+	}
+	msg := reporting.VerificationReport{
+		TableKey:     nodeType,
+		Report:       report,
+		TotalReports: total,
+	}
+	reportChan <- msg
+}


Test patch:
diff --git a/components/automate-cli/cmd/chef-automate/pre_flight_check_test.go b/components/automate-cli/cmd/chef-automate/pre_flight_check_test.go
new file mode 100644
index 000000000..6dca5d553
--- /dev/null
+++ b/components/automate-cli/cmd/chef-automate/pre_flight_check_test.go
@@ -0,0 +1,151 @@
+package main
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+type ExpectedOutput struct {
+	SSHKeyFile           string
+	SSHPort              string
+	SSHUser              string
+	AutomatePrivateIps   []string
+	ChefServerPrivateIps []string
+}
+
+func TestGetInfraDetailsForDeploymentType(t *testing.T) {
+	type testCaseInfo struct {
+		testCaseDescription string
+		deploymentType      string
+		configPath          string
+		expectedOutput      ExpectedOutput
+		expectedError       bool
+	}
+
+	testCases := []testCaseInfo{
+		{
+			testCaseDescription: "should fetch infra details for existing-infra",
+			deploymentType:      EXISTING_INFRA_MODE,
+			configPath:          "../../pkg/testfiles/onprem/config.toml",
+			expectedOutput:      ExpectedOutput{SSHKeyFile: "/home/ec2-user/A2HA.pem", SSHPort: "22", SSHUser: "ec2-user", AutomatePrivateIps: []string{"192.0.2.0", "192.0.2.1"}, ChefServerPrivateIps: []string{"192.0.2.2"}},
+			expectedError:       false,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.testCaseDescription, func(t *testing.T) {
+			infra, err := getInfraDetailsForDeploymentType(tc.deploymentType, tc.configPath)
+			assert.EqualValues(t, infra.Outputs.ChefServerPrivateIps.Value, tc.expectedOutput.ChefServerPrivateIps)
+			assert.EqualValues(t, infra.Outputs.AutomatePrivateIps.Value, tc.expectedOutput.AutomatePrivateIps)
+			assert.EqualValues(t, infra.Outputs.SSHKeyFile.Value, tc.expectedOutput.SSHKeyFile)
+			assert.EqualValues(t, infra.Outputs.SSHPort.Value, tc.expectedOutput.SSHPort)
+			assert.EqualValues(t, infra.Outputs.SSHUser.Value, tc.expectedOutput.SSHUser)
+			assert.Equal(t, err, nil)
+		})
+	}
+}
+
+func TestConstructAndGetNodeMap(t *testing.T) {
+	preflightCmdFlags.automate = true
+	var infra AutomteHAInfraDetails
+
+	type ExpectedOutput struct {
+		automate    bool
+		chef_server bool
+		frontend    bool
+	}
+
+	type testCaseInfo struct {
+		testCaseDescription string
+		automate            bool
+		chef_server         bool
+		frontend            bool
+		ExpectedOutput      ExpectedOutput
+	}
+
+	testCases := []testCaseInfo{
+		{
+			testCaseDescription: "should construct nodeMap for automate when automate flag is passed",
+			automate:            true,
+			chef_server:         false,
+			frontend:            false,
+			ExpectedOutput: ExpectedOutput{
+				automate:    true,
+				chef_server: false,
+				frontend:    false,
+			},
+		},
+		{
+			testCaseDescription: "should construct nodeMap for chef-server when chef-server flag is passed",
+			automate:            false,
+			chef_server:         true,
+			frontend:            false,
+			ExpectedOutput: ExpectedOutput{
+				automate:    false,
+				chef_server: true,
+				frontend:    false,
+			},
+		},
+		{
+			testCaseDescription: "should construct nodeMap for frontend when frontend flag is passed",
+			automate:            false,
+			chef_server:         false,
+			frontend:            true,
+			ExpectedOutput: ExpectedOutput{
+				automate:    false,
+				chef_server: false,
+				frontend:    true,
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.testCaseDescription, func(t *testing.T) {
+			preflightCmdFlags.automate = tc.automate
+			preflightCmdFlags.chef_server = tc.chef_server
+			preflightCmdFlags.frontend = tc.frontend
+
+			nodeMap := constructAndGetNodeMap(&infra)
+
+			assert.EqualValues(t, nodeMap.Automate.CmdInputs.NodeType, tc.ExpectedOutput.automate)
+			assert.EqualValues(t, nodeMap.ChefServer.CmdInputs.NodeType, tc.ExpectedOutput.chef_server)
+			assert.EqualValues(t, nodeMap.Frontend.CmdInputs.NodeType, tc.ExpectedOutput.frontend)
+		})
+	}
+}
+
+func TestShouldReturnErrorWhenHaDeploymentConfigFlagDonotHaveConfig(t *testing.T) {
+	preflightCmdFlags.haDeploymentConfig = true
+	err := runPreflightCheckCmd(nil, nil)
+	assert.Equal(t, err.Error(), "Config file should be passed with ha-deployment-config flag")
+}
+
+func TestShouldGetInfraDetails(t *testing.T) {
+	type testCaseInfo struct {
+		testCaseDescription string
+		configPath          string
+		expectedOutput      ExpectedOutput
+		expectedError       bool
+	}
+	testCases := []testCaseInfo{
+		{
+			testCaseDescription: "should fetch infra details",
+			configPath:          "../../pkg/testfiles/onprem/config.toml",
+			expectedOutput:      ExpectedOutput{SSHKeyFile: "/home/ec2-user/A2HA.pem", SSHPort: "22", SSHUser: "ec2-user", AutomatePrivateIps: []string{"192.0.2.0", "192.0.2.1"}, ChefServerPrivateIps: []string{"192.0.2.2"}},
+			expectedError:       false,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.testCaseDescription, func(t *testing.T) {
+			infra, err := getInfraDetails(tc.configPath)
+			assert.EqualValues(t, infra.Outputs.ChefServerPrivateIps.Value, tc.expectedOutput.ChefServerPrivateIps)
+			assert.EqualValues(t, infra.Outputs.AutomatePrivateIps.Value, tc.expectedOutput.AutomatePrivateIps)
+			assert.EqualValues(t, infra.Outputs.SSHKeyFile.Value, tc.expectedOutput.SSHKeyFile)
+			assert.EqualValues(t, infra.Outputs.SSHPort.Value, tc.expectedOutput.SSHPort)
+			assert.EqualValues(t, infra.Outputs.SSHUser.Value, tc.expectedOutput.SSHUser)
+			assert.Equal(t, err, nil)
+		})
+	}
+}
diff --git a/components/automate-cli/cmd/chef-automate/verify_test.go b/components/automate-cli/cmd/chef-automate/verify_test.go
new file mode 100644
index 000000000..6cc2ee3f5
--- /dev/null
+++ b/components/automate-cli/cmd/chef-automate/verify_test.go
@@ -0,0 +1,908 @@
+package main
+
+import (
+	"testing"
+
+	verification "github.com/chef/automate/lib/verification"
+	"github.com/pkg/errors"
+	"github.com/spf13/cobra"
+	"github.com/stretchr/testify/assert"
+)
+
+const (
+	configFileName       = "config.toml"
+	parseConfigFileError = "Unable to parse config file"
+)
+
+func TestVerifyCmdFunc(t *testing.T) {
+	type args struct {
+		flagsObj *verifyCmdFlags
+	}
+	tests := []struct {
+		name string
+		args args
+	}{
+		{
+			name: "Test VerifyCmdFunc",
+			args: args{
+				flagsObj: &verifyCmdFlags{
+					file:                      "",
+					haAWSProvision:            false,
+					haAWSManagedProvision:     false,
+					haOnpremDeploy:            false,
+					haOnPremAWSManagedDeploy:  false,
+					haOnPremCustManagedDeploy: false,
+					haAWSDeploy:               false,
+					haAWSManagedDeploy:        false,
+					standaloneDeploy:          false,
+					certificates:              false,
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := verifyCmdFunc(tt.args.flagsObj)
+			err := got(&cobra.Command{}, []string{})
+			assert.Equal(t, nil, err)
+		})
+	}
+}
+
+func TestRunVerifyCmd(t *testing.T) {
+	type args struct {
+		cmd      *cobra.Command
+		args     []string
+		flagsObj *verifyCmdFlags
+	}
+	tests := []struct {
+		name              string
+		args              args
+		A2HARBFileExist   bool
+		ManagedServicesOn bool
+		mockFunc          verification.Verification
+		wantErr           bool
+		err               error
+	}{
+		{
+			name: "Test VerifyHaAWSProvision",
+			args: args{
+				cmd:  &cobra.Command{},
+				args: []string{},
+				flagsObj: &verifyCmdFlags{
+					file:                      "",
+					haAWSProvision:            true,
+					haAWSManagedProvision:     false,
+					haOnpremDeploy:            false,
+					haOnPremAWSManagedDeploy:  false,
+					haOnPremCustManagedDeploy: false,
+					haAWSDeploy:               false,
+					haAWSManagedDeploy:        false,
+					standaloneDeploy:          false,
+					certificates:              false,
+				},
+			},
+			A2HARBFileExist: true,
+			mockFunc: &verification.VerificationMock{
+				VerifyHAAWSProvisionFunc: func(configFile string) error {
+					return nil
+				},
+			},
+			ManagedServicesOn: false,
+			wantErr:           false,
+		},
+		{
+			name: "Test VerifyHaAWSManagedProvision",
+			args: args{
+				cmd:  &cobra.Command{},
+				args: []string{},
+				flagsObj: &verifyCmdFlags{
+					file:                      "",
+					haAWSProvision:            false,
+					haAWSManagedProvision:     true,
+					haOnpremDeploy:            false,
+					haOnPremAWSManagedDeploy:  false,
+					haOnPremCustManagedDeploy: false,
+					haAWSDeploy:               false,
+					haAWSManagedDeploy:        false,
+					standaloneDeploy:          false,
+					certificates:              false,
+				},
+			},
+			A2HARBFileExist: false,
+			mockFunc: &verification.VerificationMock{
+				VerifyHAAWSManagedProvisionFunc: func(configFile string) error {
+					return nil
+				},
+			},
+			ManagedServicesOn: false,
+			wantErr:           false,
+		},
+		{
+			name: "Test VerifyHaOnpremDeploy",
+			args: args{
+				cmd:  &cobra.Command{},
+				args: []string{},
+				flagsObj: &verifyCmdFlags{
+					file:                      "",
+					haAWSProvision:            false,
+					haAWSManagedProvision:     false,
+					haOnpremDeploy:            true,
+					haOnPremAWSManagedDeploy:  false,
+					haOnPremCustManagedDeploy: false,
+					haAWSDeploy:               false,
+					haAWSManagedDeploy:        false,
+					standaloneDeploy:          false,
+					certificates:              false,
+				},
+			},
+			A2HARBFileExist: false,
+			mockFunc: &verification.VerificationMock{
+				VerifyOnPremDeploymentFunc: func(configFile string) error {
+					return nil
+				},
+			},
+			ManagedServicesOn: false,
+			wantErr:           false,
+		},
+		{
+			name: "Test VerifyHaOnPremAWSManagedDeploy",
+			args: args{
+				cmd:  &cobra.Command{},
+				args: []string{},
+				flagsObj: &verifyCmdFlags{
+					file:                      "",
+					haAWSProvision:            false,
+					haAWSManagedProvision:     false,
+					haOnpremDeploy:            false,
+					haOnPremAWSManagedDeploy:  true,
+					haOnPremCustManagedDeploy: false,
+					haAWSDeploy:               false,
+					haAWSManagedDeploy:        false,
+					standaloneDeploy:          false,
+					certificates:              false,
+				},
+			},
+			A2HARBFileExist: false,
+			mockFunc: &verification.VerificationMock{
+				VerifyOnPremAWSManagedDeploymentFunc: func(configFile string) error {
+					return nil
+				},
+			},
+			ManagedServicesOn: false,
+			wantErr:           false,
+		},
+		{
+			name: "Test VerifyHaOnPremCustManagedDeploy",
+			args: args{
+				cmd:  &cobra.Command{},
+				args: []string{configFileName},
+				flagsObj: &verifyCmdFlags{
+					file:                      "",
+					haAWSProvision:            false,
+					haAWSManagedProvision:     false,
+					haOnpremDeploy:            false,
+					haOnPremAWSManagedDeploy:  false,
+					haOnPremCustManagedDeploy: true,
+					haAWSDeploy:               false,
+					haAWSManagedDeploy:        false,
+					standaloneDeploy:          false,
+					certificates:              false,
+				},
+			},
+			A2HARBFileExist: false,
+			mockFunc: &verification.VerificationMock{
+				VerifyOnPremCustManagedDeploymentFunc: func(configFile string) error {
+					return nil
+				},
+			},
+			ManagedServicesOn: false,
+			wantErr:           false,
+		},
+		{
+			name: "Test VerifyHaAWSDeploy",
+			args: args{
+				cmd:  &cobra.Command{},
+				args: []string{},
+				flagsObj: &verifyCmdFlags{
+					file:                      "",
+					haAWSProvision:            false,
+					haAWSManagedProvision:     false,
+					haOnpremDeploy:            false,
+					haOnPremAWSManagedDeploy:  false,
+					haOnPremCustManagedDeploy: false,
+					haAWSDeploy:               true,
+					haAWSManagedDeploy:        false,
+					standaloneDeploy:          false,
+					certificates:              false,
+				},
+			},
+			A2HARBFileExist: true,
+			mockFunc: &verification.VerificationMock{
+				VerifyHAAWSDeploymentFunc: func(configFile string) error {
+					return nil
+				},
+			},
+			ManagedServicesOn: false,
+			wantErr:           false,
+		},
+		{
+			name: "Test VerifyHaAWSManagedDeploy",
+			args: args{
+				cmd:  &cobra.Command{},
+				args: []string{},
+				flagsObj: &verifyCmdFlags{
+					file:                      "",
+					haAWSProvision:            false,
+					haAWSManagedProvision:     false,
+					haOnpremDeploy:            false,
+					haOnPremAWSManagedDeploy:  false,
+					haOnPremCustManagedDeploy: false,
+					haAWSDeploy:               false,
+					haAWSManagedDeploy:        true,
+					standaloneDeploy:          false,
+					certificates:              false,
+				},
+			},
+			A2HARBFileExist: true,
+			mockFunc: &verification.VerificationMock{
+				VerifyHAAWSManagedDeploymentFunc: func(configFile string) error {
+					return nil
+				},
+			},
+			ManagedServicesOn: true,
+			wantErr:           false,
+		},
+		{
+			name: "Test VerifyStandaloneDeploy",
+			args: args{
+				cmd:  &cobra.Command{},
+				args: []string{},
+				flagsObj: &verifyCmdFlags{
+					file:                      "",
+					haAWSProvision:            false,
+					haAWSManagedProvision:     false,
+					haOnpremDeploy:            false,
+					haOnPremAWSManagedDeploy:  false,
+					haOnPremCustManagedDeploy: false,
+					haAWSDeploy:               false,
+					haAWSManagedDeploy:        false,
+					standaloneDeploy:          true,
+					certificates:              false,
+				},
+			},
+			A2HARBFileExist: false,
+			mockFunc: &verification.VerificationMock{
+				VerifyStandaloneDeploymentFunc: func(configFile string) error {
+					return nil
+				},
+			},
+			ManagedServicesOn: false,
+			wantErr:           false,
+		},
+		{
+			name: "Test VerifyCertificates",
+			args: args{
+				cmd:  &cobra.Command{},
+				args: []string{},
+				flagsObj: &verifyCmdFlags{
+					file:                      "",
+					haAWSProvision:            false,
+					haAWSManagedProvision:     false,
+					haOnpremDeploy:            false,
+					haOnPremAWSManagedDeploy:  false,
+					haOnPremCustManagedDeploy: false,
+					haAWSDeploy:               false,
+					haAWSManagedDeploy:        false,
+					standaloneDeploy:          false,
+					certificates:              true,
+				},
+			},
+			A2HARBFileExist: false,
+			mockFunc: &verification.VerificationMock{
+				VerifyCertificatesFunc: func(configFile string) error {
+					return nil
+				},
+			},
+			ManagedServicesOn: false,
+			wantErr:           false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			v := verifyCmdFlow{
+				Verification:      tt.mockFunc,
+				A2HARBFileExist:   tt.A2HARBFileExist,
+				ManagedServicesOn: tt.ManagedServicesOn,
+			}
+
+			err := v.runVerifyCmd(tt.args.cmd, tt.args.args, tt.args.flagsObj)
+
+			if tt.wantErr {
+				assert.EqualError(t, err, tt.err.Error())
+			} else {
+				assert.Equal(t, nil, err)
+			}
+		})
+	}
+}
+
+func TestVerifyHaAWSProvision(t *testing.T) {
+	type fields struct {
+		Verification      verification.Verification
+		A2HARBFileExist   bool
+		ManagedServicesOn bool
+	}
+	type args struct {
+		configPath string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+		err     error
+	}{
+		{
+			name: "Test VerifyHaAWSProvision: verification failed",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyHAAWSProvisionFunc: func(configFile string) error {
+						return errors.New(parseConfigFileError)
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: true,
+			err:     errors.New(parseConfigFileError),
+		},
+		{
+			name: "Test VerifyHaAWSProvision: verification successful",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyHAAWSProvisionFunc: func(configFile string) error {
+						return nil
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			v := &verifyCmdFlow{
+				Verification:      tt.fields.Verification,
+				A2HARBFileExist:   tt.fields.A2HARBFileExist,
+				ManagedServicesOn: tt.fields.ManagedServicesOn,
+			}
+			err := v.verifyHaAWSProvision(tt.args.configPath)
+
+			if tt.wantErr {
+				assert.EqualError(t, err, tt.err.Error())
+			} else {
+				assert.Equal(t, nil, err)
+			}
+		})
+	}
+}
+
+func TestVerifyHaAWSManagedProvision(t *testing.T) {
+	type fields struct {
+		Verification      verification.Verification
+		A2HARBFileExist   bool
+		ManagedServicesOn bool
+	}
+	type args struct {
+		configPath string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+		err     error
+	}{
+		{
+			name: "Test VerifyHaAWSManagedProvision: verification failed",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyHAAWSManagedProvisionFunc: func(configFile string) error {
+						return errors.New(parseConfigFileError)
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: true,
+			err:     errors.New(parseConfigFileError),
+		},
+		{
+			name: "Test VerifyHaAWSManagedProvision: verification successful",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyHAAWSManagedProvisionFunc: func(configFile string) error {
+						return nil
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			v := &verifyCmdFlow{
+				Verification:      tt.fields.Verification,
+				A2HARBFileExist:   tt.fields.A2HARBFileExist,
+				ManagedServicesOn: tt.fields.ManagedServicesOn,
+			}
+			err := v.verifyHaAWSManagedProvision(tt.args.configPath)
+			if tt.wantErr {
+				assert.EqualError(t, err, tt.err.Error())
+			} else {
+				assert.Equal(t, nil, err)
+			}
+		})
+	}
+}
+
+func TestVerifyHaAWSDeploy(t *testing.T) {
+	type fields struct {
+		Verification      verification.Verification
+		A2HARBFileExist   bool
+		ManagedServicesOn bool
+	}
+	type args struct {
+		configPath string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+		err     error
+	}{
+		{
+			name: "Test VerifyHaAWSDeploy: verification successful",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyHAAWSDeploymentFunc: func(configFile string) error {
+						return nil
+					},
+				},
+				A2HARBFileExist:   true,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: false,
+		},
+		{
+			name: "Test VerifyHaAWSDeploy: verification failed",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyHAAWSDeploymentFunc: func(configFile string) error {
+						return errors.New(parseConfigFileError)
+					},
+				},
+				A2HARBFileExist:   true,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: true,
+			err:     errors.New(parseConfigFileError),
+		},
+		{
+			name: "Test VerifyHaAWSDeploy: a2ha.rb file not present",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyHAAWSDeploymentFunc: func(configFile string) error {
+						return nil
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: true,
+			err:     errors.New(errProvisonInfra),
+		},
+		{
+			name: "Test VerifyHaAWSDeploy: Managed services present",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyHAAWSDeploymentFunc: func(configFile string) error {
+						return nil
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: true,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: true,
+			err:     errors.New("This flag will not verify the Managed Services Setup. Please use the --ha-aws-managed-deploy flag."),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			v := &verifyCmdFlow{
+				Verification:      tt.fields.Verification,
+				A2HARBFileExist:   tt.fields.A2HARBFileExist,
+				ManagedServicesOn: tt.fields.ManagedServicesOn,
+			}
+			err := v.verifyHaAWSDeploy(tt.args.configPath)
+			if tt.wantErr {
+				assert.EqualError(t, err, tt.err.Error())
+			} else {
+				assert.Equal(t, nil, err)
+			}
+		})
+	}
+}
+
+func TestVerifyHaAWSManagedDeploy(t *testing.T) {
+	type fields struct {
+		Verification      verification.Verification
+		A2HARBFileExist   bool
+		ManagedServicesOn bool
+	}
+	type args struct {
+		configPath string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+		err     error
+	}{
+		{
+			name: "Test VerifyHaAWSManagedDeploy: verification successful",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyHAAWSManagedDeploymentFunc: func(configFile string) error {
+						return nil
+					},
+				},
+				A2HARBFileExist:   true,
+				ManagedServicesOn: true,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: false,
+		},
+		{
+			name: "Test VerifyHaAWSManagedDeploy: verification failed",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyHAAWSManagedDeploymentFunc: func(configFile string) error {
+						return errors.New(parseConfigFileError)
+					},
+				},
+				A2HARBFileExist:   true,
+				ManagedServicesOn: true,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: true,
+			err:     errors.New(parseConfigFileError),
+		},
+		{
+			name: "Test VerifyHaAWSManagedDeploy: a2ha.rb file not present",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyHAAWSManagedDeploymentFunc: func(configFile string) error {
+						return nil
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: true,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: true,
+			err:     errors.New(errProvisonInfra),
+		},
+		{
+			name: "Test VerifyHaAWSManagedDeploy: Managed services not present",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyHAAWSManagedDeploymentFunc: func(configFile string) error {
+						return nil
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: true,
+			err:     errors.New("Managed Services flag is not set. Cannot verify the config."),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			v := &verifyCmdFlow{
+				Verification:      tt.fields.Verification,
+				A2HARBFileExist:   tt.fields.A2HARBFileExist,
+				ManagedServicesOn: tt.fields.ManagedServicesOn,
+			}
+			err := v.verifyHaAWSManagedDeploy(tt.args.configPath)
+			if tt.wantErr {
+				assert.EqualError(t, err, tt.err.Error())
+			} else {
+				assert.Equal(t, nil, err)
+			}
+		})
+	}
+}
+
+func TestVerifyStandaloneDeploy(t *testing.T) {
+	type fields struct {
+		Verification      verification.Verification
+		A2HARBFileExist   bool
+		ManagedServicesOn bool
+	}
+	type args struct {
+		configPath string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+		err     error
+	}{
+		{
+			name: "Test VerifyStandaloneDeploy: check a2ha.rb file",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyStandaloneDeploymentFunc: func(configFile string) error {
+						return nil
+					},
+				},
+				A2HARBFileExist:   true,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: true,
+			err:     errors.New("Deployment type does not match with the requested flag."),
+		},
+		{
+			name: "Test VerifyStandaloneDeploy: verification failed",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyStandaloneDeploymentFunc: func(configFile string) error {
+						return errors.New(parseConfigFileError)
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: true,
+			err:     errors.New(parseConfigFileError),
+		},
+		{
+			name: "Test VerifyStandaloneDeploy: verification successful",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyStandaloneDeploymentFunc: func(configFile string) error {
+						return nil
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			v := &verifyCmdFlow{
+				Verification:      tt.fields.Verification,
+				A2HARBFileExist:   tt.fields.A2HARBFileExist,
+				ManagedServicesOn: tt.fields.ManagedServicesOn,
+			}
+			err := v.verifyStandaloneDeploy(tt.args.configPath)
+			if tt.wantErr {
+				assert.EqualError(t, err, tt.err.Error())
+			} else {
+				assert.Equal(t, nil, err)
+			}
+		})
+	}
+}
+
+func TestVerifyHaOnpremDeploy(t *testing.T) {
+	type fields struct {
+		Verification      verification.Verification
+		A2HARBFileExist   bool
+		ManagedServicesOn bool
+	}
+	type args struct {
+		configPath string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+		err     error
+	}{
+		{
+			name: "Test VerifyHaOnpremDeploy: verification successful",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyOnPremDeploymentFunc: func(configFile string) error {
+						return nil
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: false,
+		},
+		{
+			name: "Test VerifyHaOnpremDeploy: verification failed",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyOnPremDeploymentFunc: func(configFile string) error {
+						return errors.New(parseConfigFileError)
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: true,
+			err:     errors.New(parseConfigFileError),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			v := &verifyCmdFlow{
+				Verification:      tt.fields.Verification,
+				A2HARBFileExist:   tt.fields.A2HARBFileExist,
+				ManagedServicesOn: tt.fields.ManagedServicesOn,
+			}
+			err := v.verifyHaOnpremDeploy(tt.args.configPath)
+			if tt.wantErr {
+				assert.EqualError(t, err, tt.err.Error())
+			} else {
+				assert.Equal(t, nil, err)
+			}
+		})
+	}
+}
+
+func TestVerifyHaOnPremAWSManagedDeploy(t *testing.T) {
+	type fields struct {
+		Verification      verification.Verification
+		A2HARBFileExist   bool
+		ManagedServicesOn bool
+	}
+	type args struct {
+		configPath string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+		err     error
+	}{
+		{
+			name: "Test VerifyHaOnPremAWSManagedDeploy: verification successful",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyOnPremAWSManagedDeploymentFunc: func(configFile string) error {
+						return nil
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: false,
+		},
+		{
+			name: "Test VerifyHaOnPremAWSManagedDeploy: verification failed",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyOnPremAWSManagedDeploymentFunc: func(configFile string) error {
+						return errors.New(parseConfigFileError)
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: true,
+			err:     errors.New(parseConfigFileError),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			v := &verifyCmdFlow{
+				Verification:      tt.fields.Verification,
+				A2HARBFileExist:   tt.fields.A2HARBFileExist,
+				ManagedServicesOn: tt.fields.ManagedServicesOn,
+			}
+			err := v.verifyHaOnPremAWSManagedDeploy(tt.args.configPath)
+			if tt.wantErr {
+				assert.EqualError(t, err, tt.err.Error())
+			} else {
+				assert.Equal(t, nil, err)
+			}
+		})
+	}
+}
+
+func TestVerifyHaOnPremCustManagedDeploy(t *testing.T) {
+	type fields struct {
+		Verification      verification.Verification
+		A2HARBFileExist   bool
+		ManagedServicesOn bool
+	}
+	type args struct {
+		configPath string
+	}
+	tests := []struct {
+		name    string
+		fields  fields
+		args    args
+		wantErr bool
+		err     error
+	}{
+		{
+			name: "Test VerifyHaOnPremCustManagedDeploy: verification successful",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyOnPremCustManagedDeploymentFunc: func(configFile string) error {
+						return nil
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: false,
+		},
+		{
+			name: "Test VerifyHaOnPremCustManagedDeploy: verification failed",
+			fields: fields{
+				Verification: &verification.VerificationMock{
+					VerifyOnPremCustManagedDeploymentFunc: func(configFile string) error {
+						return errors.New(parseConfigFileError)
+					},
+				},
+				A2HARBFileExist:   false,
+				ManagedServicesOn: false,
+			},
+			args:    args{configPath: configFileName},
+			wantErr: true,
+			err:     errors.New(parseConfigFileError),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			v := &verifyCmdFlow{
+				Verification:      tt.fields.Verification,
+				A2HARBFileExist:   tt.fields.A2HARBFileExist,
+				ManagedServicesOn: tt.fields.ManagedServicesOn,
+			}
+			err := v.verifyHaOnPremCustManagedDeploy(tt.args.configPath)
+			if tt.wantErr {
+				assert.EqualError(t, err, tt.err.Error())
+			} else {
+				assert.Equal(t, nil, err)
+			}
+		})
+	}
+}
diff --git a/components/automate-cli/pkg/testfiles/aws/config.toml b/components/automate-cli/pkg/testfiles/aws/config.toml
index 442f3d9cf..819aef778 100644
--- a/components/automate-cli/pkg/testfiles/aws/config.toml
+++ b/components/automate-cli/pkg/testfiles/aws/config.toml
@@ -11,8 +11,6 @@ ssh_port = "22"
 # Private SSH key file path, which has access to all the instances.
 # Eg.: ssh_key_file = "~/.ssh/A2HA.pem"
 ssh_key_file = "/home/ec2-user/XYZ.pem"
-# Provide Password if needed to run sudo commands.
-#sudo_password = "chefautomate"
 # Eg.: backup_config = "efs" or "s3"
 backup_config = "s3"
 # If s3 is selected for backup_config,
diff --git a/components/automate-cli/pkg/testfiles/onprem/config.toml b/components/automate-cli/pkg/testfiles/onprem/config.toml
index 65f40fc6a..88752be15 100644
--- a/components/automate-cli/pkg/testfiles/onprem/config.toml
+++ b/components/automate-cli/pkg/testfiles/onprem/config.toml
@@ -14,9 +14,6 @@ ssh_key_file = "/home/ec2-user/A2HA.pem"
 # custome ssh port no to connect instances, default will be 22
 # Eg.: ssh_port = "22"
 ssh_port = "22"
-
-# Provide Password if needed to run sudo commands.
-sudo_password = ""
 ## === ===
 
 secrets_key_file = "/hab/a2_deploy_workspace/secrets.key"
diff --git a/components/automate-cluster-ctl/libexec/cluster-test b/components/automate-cluster-ctl/libexec/cluster-test
index 7128d1021..e803f8e03 100755
--- a/components/automate-cluster-ctl/libexec/cluster-test
+++ b/components/automate-cluster-ctl/libexec/cluster-test
@@ -33,6 +33,9 @@ class AutomateClusterTest < AutomateCluster::Command
   def execute
     results = []
 
+    # store the secret envs so we can pass them to the command
+    store_secret_envs
+
     INSPEC_PROFILES.each do |name, profiles|
       next unless service_name.nil? || name == service_name.to_sym
 
@@ -66,6 +69,18 @@ class AutomateClusterTest < AutomateCluster::Command
     [:elasticsearch, :postgresql].include?(name)
   end
 
+  # store the sudo_password from the env variable in the secrets hash
+  def store_secret_envs
+    sudo_password = ENV['sudo_password']
+    # If the sudo_password is set, store it in the secrets hash
+    if sudo_password
+      # Set a new secret
+      secrets.set('sudo_password', sudo_password)
+      # Save the updated secrets store to disk
+      secrets.save(File.expand_path(AutomateCluster::Config.secrets_store_file))
+    end
+  end
+
   # def default_sudo_password
   #   AutomateCluster.secrets['sudo_password']
   # end
diff --git a/lib/config_parser/parser_test.go b/lib/config_parser/parser_test.go
new file mode 100644
index 000000000..8a78c3bf3
--- /dev/null
+++ b/lib/config_parser/parser_test.go
@@ -0,0 +1,250 @@
+package config_parser
+
+import (
+	"errors"
+	"reflect"
+	"testing"
+
+	sc "github.com/chef/automate/api/config/deployment"
+	w "github.com/chef/automate/api/config/shared/wrappers"
+	"github.com/stretchr/testify/assert"
+)
+
+func TestParseAWSAutomateConfig(t *testing.T) {
+	type args struct {
+		configFile string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *HAAwsConfigToml
+		wantErr bool
+		err     error
+	}{
+		{
+			name: "Parse AWS Config successful",
+			args: args{configFile: "./testdata/AWSConfig.toml"},
+			want: &HAAwsConfigToml{Architecture: struct {
+				ConfigInitials struct {
+					SecretsKeyFile              string "toml:\"secrets_key_file\""
+					SecretsStoreFile            string "toml:\"secrets_store_file\""
+					Architecture                string "toml:\"architecture\""
+					WorkspacePath               string "toml:\"workspace_path\""
+					SSHUser                     string "toml:\"ssh_user\""
+					SSHKeyFile                  string "toml:\"ssh_key_file\""
+					SSHPort                     string "toml:\"ssh_port\""
+					SudoPassword                string "toml:\"sudo_password\""
+					LoggingMonitoringManagement string "toml:\"logging_monitoring_management\""
+					NewElk                      string "toml:\"new_elk\""
+					ExistingElkInstanceIP       string "toml:\"existing_elk_instance_ip\""
+					ExistingElkPort             string "toml:\"existing_elk_port\""
+					ExistingElkCert             string "toml:\"existing_elk_cert\""
+					ExistingElkUsername         string "toml:\"existing_elk_username\""
+					ExistingElkPassword         string "toml:\"existing_elk_password\""
+					BackupMount                 string "toml:\"backup_mount\""
+					BackupConfig                string "toml:\"backup_config\""
+					S3BucketName                string "toml:\"s3_bucketName\""
+					HabitatUIDGid               string "toml:\"habitat_uid_gid\""
+				} "toml:\"aws\""
+			}{
+				ConfigInitials: struct {
+					SecretsKeyFile              string "toml:\"secrets_key_file\""
+					SecretsStoreFile            string "toml:\"secrets_store_file\""
+					Architecture                string "toml:\"architecture\""
+					WorkspacePath               string "toml:\"workspace_path\""
+					SSHUser                     string "toml:\"ssh_user\""
+					SSHKeyFile                  string "toml:\"ssh_key_file\""
+					SSHPort                     string "toml:\"ssh_port\""
+					SudoPassword                string "toml:\"sudo_password\""
+					LoggingMonitoringManagement string "toml:\"logging_monitoring_management\""
+					NewElk                      string "toml:\"new_elk\""
+					ExistingElkInstanceIP       string "toml:\"existing_elk_instance_ip\""
+					ExistingElkPort             string "toml:\"existing_elk_port\""
+					ExistingElkCert             string "toml:\"existing_elk_cert\""
+					ExistingElkUsername         string "toml:\"existing_elk_username\""
+					ExistingElkPassword         string "toml:\"existing_elk_password\""
+					BackupMount                 string "toml:\"backup_mount\""
+					BackupConfig                string "toml:\"backup_config\""
+					S3BucketName                string "toml:\"s3_bucketName\""
+					HabitatUIDGid               string "toml:\"habitat_uid_gid\""
+				}{
+					SecretsKeyFile:   "/hab/a2_deploy_workspace/secrets.key",
+					SecretsStoreFile: "/hab/a2_deploy_workspace/secrets.json",
+					Architecture:     "aws",
+					WorkspacePath:    "/hab/a2_deploy_workspace",
+					BackupMount:      "/mnt/automate_backups",
+				},
+			}},
+			wantErr: false,
+			err:     nil,
+		},
+		{
+			name:    "Parse AWs Config file not found",
+			args:    args{configFile: "AWSConfig.toml"},
+			want:    nil,
+			wantErr: true,
+			err:     errors.New("error in reading config toml file: open AWSConfig.toml: no such file or directory"),
+		},
+		{
+			name:    "Parse AWs Config failed",
+			args:    args{configFile: "./testdata/AWSConfigFailure.toml"},
+			want:    nil,
+			wantErr: true,
+			err:     errors.New("error in unmarshalling config toml file: (30, 21): unescaped control character U+000A"),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			cp := &ConfigParserImpl{}
+			got, err := cp.ParseAWSAutomateConfig(tt.args.configFile)
+			if tt.wantErr {
+				assert.Equal(t, tt.err.Error(), err.Error())
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("ConfigParserImpl.ParseAWSAutomateConfig() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestParseOnPremConfig(t *testing.T) {
+	type args struct {
+		configFile string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *HAOnPremConfigToml
+		wantErr bool
+		err     error
+	}{
+		{
+			name: "Parse OnPrem Config successful",
+			args: args{configFile: "./testdata/OnPremConfig.toml"},
+			want: &HAOnPremConfigToml{Architecture: struct {
+				ConfigInitials struct {
+					SecretsKeyFile              string "toml:\"secrets_key_file,omitempty\""
+					SecretsStoreFile            string "toml:\"secrets_store_file,omitempty\""
+					Architecture                string "toml:\"architecture,omitempty\""
+					WorkspacePath               string "toml:\"workspace_path,omitempty\""
+					SSHUser                     string "toml:\"ssh_user,omitempty\""
+					SSHKeyFile                  string "toml:\"ssh_key_file,omitempty\""
+					SSHPort                     string "toml:\"ssh_port,omitempty\""
+					SudoPassword                string "toml:\"sudo_password,omitempty\""
+					LoggingMonitoringManagement string "toml:\"logging_monitoring_management,omitempty\""
+					NewElk                      string "toml:\"new_elk,omitempty\""
+					ExistingElkInstanceIP       string "toml:\"existing_elk_instance_ip,omitempty\""
+					ExistingElkPort             string "toml:\"existing_elk_port,omitempty\""
+					ExistingElkCert             string "toml:\"existing_elk_cert,omitempty\""
+					ExistingElkUsername         string "toml:\"existing_elk_username,omitempty\""
+					ExistingElkPassword         string "toml:\"existing_elk_password,omitempty\""
+					BackupMount                 string "toml:\"backup_mount,omitempty\""
+					HabitatUIDGid               string "toml:\"habitat_uid_gid,omitempty\""
+					BackupConfig                string "toml:\"backup_config,omitempty\""
+				} "toml:\"existing_infra\""
+			}{
+				ConfigInitials: struct {
+					SecretsKeyFile              string "toml:\"secrets_key_file,omitempty\""
+					SecretsStoreFile            string "toml:\"secrets_store_file,omitempty\""
+					Architecture                string "toml:\"architecture,omitempty\""
+					WorkspacePath               string "toml:\"workspace_path,omitempty\""
+					SSHUser                     string "toml:\"ssh_user,omitempty\""
+					SSHKeyFile                  string "toml:\"ssh_key_file,omitempty\""
+					SSHPort                     string "toml:\"ssh_port,omitempty\""
+					SudoPassword                string "toml:\"sudo_password,omitempty\""
+					LoggingMonitoringManagement string "toml:\"logging_monitoring_management,omitempty\""
+					NewElk                      string "toml:\"new_elk,omitempty\""
+					ExistingElkInstanceIP       string "toml:\"existing_elk_instance_ip,omitempty\""
+					ExistingElkPort             string "toml:\"existing_elk_port,omitempty\""
+					ExistingElkCert             string "toml:\"existing_elk_cert,omitempty\""
+					ExistingElkUsername         string "toml:\"existing_elk_username,omitempty\""
+					ExistingElkPassword         string "toml:\"existing_elk_password,omitempty\""
+					BackupMount                 string "toml:\"backup_mount,omitempty\""
+					HabitatUIDGid               string "toml:\"habitat_uid_gid,omitempty\""
+					BackupConfig                string "toml:\"backup_config,omitempty\""
+				}{
+					SecretsKeyFile:   "/hab/a2_deploy_workspace/secrets.key",
+					SecretsStoreFile: "/hab/a2_deploy_workspace/secrets.json",
+					Architecture:     "existing_nodes",
+					WorkspacePath:    "/hab/a2_deploy_workspace",
+					SSHPort:          "22",
+					BackupMount:      "/mnt/automate_backups",
+				},
+			}},
+			wantErr: false,
+			err:     nil,
+		},
+		{
+			name:    "Parse OnPrem Config file not found",
+			args:    args{configFile: "OnPremConfig.toml"},
+			want:    nil,
+			wantErr: true,
+			err:     errors.New("error in reading config toml file: open OnPremConfig.toml: no such file or directory"),
+		},
+		{
+			name:    "Parse OnPrem Config failed",
+			args:    args{configFile: "./testdata/OnPremConfigFailure.toml"},
+			want:    nil,
+			wantErr: true,
+			err:     errors.New("error in unmarshalling config toml file: (10, 21): unescaped control character U+000A"),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			cp := &ConfigParserImpl{}
+			got, err := cp.ParseOnPremConfig(tt.args.configFile)
+			if tt.wantErr {
+				assert.Equal(t, tt.err.Error(), err.Error())
+			}
+			if !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("ConfigParserImpl.ParseOnPremConfig() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestParseStandaloneConfig(t *testing.T) {
+	Cfg := sc.NewAutomateConfig()
+	Cfg.Global.V1.Fqdn = w.String("Public_DNS_name")
+	type args struct {
+		configFile string
+	}
+	tests := []struct {
+		name    string
+		args    args
+		want    *sc.AutomateConfig
+		wantErr bool
+		err     error
+	}{
+		{
+			name: "Parse Standalone Config successful",
+			args: args{
+				configFile: "./testdata/StandaloneConfig.toml",
+			},
+			want:    Cfg,
+			wantErr: false,
+		},
+		{
+			name: "Parse Standalone Config failed",
+			args: args{
+				configFile: "StandaloneConfig.toml",
+			},
+			want:    &sc.AutomateConfig{},
+			wantErr: true,
+			err:     errors.New("Failed to read config file located at StandaloneConfig.toml: open StandaloneConfig.toml: no such file or directory"),
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			cp := &ConfigParserImpl{}
+			got, err := cp.ParseStandaloneConfig(tt.args.configFile)
+			if tt.wantErr {
+				assert.Equal(t, tt.err.Error(), err.Error())
+			} else {
+				assert.Equal(t, tt.want.Global.V1.Fqdn.GetValue(), got.Global.V1.Fqdn.GetValue())
+			}
+
+		})
+	}
+}
diff --git a/lib/config_parser/testdata/AWSConfig.toml b/lib/config_parser/testdata/AWSConfig.toml
new file mode 100644
index 000000000..a644d7720
--- /dev/null
+++ b/lib/config_parser/testdata/AWSConfig.toml
@@ -0,0 +1,37 @@
+# This is a Chef Automate AWS HA mode configuration file. You can run
+# 'chef-automate deploy' with this config file and it should
+# successfully create a new Chef Automate HA instances with default settings.
+
+[architecture.aws]
+## === INPUT NEEDED ===
+# Eg.: ssh_user = "ubuntu"
+ssh_user = ""
+
+# custome ssh port no to connect instances, default will be 22
+# Eg.: ssh_port = "22"
+ssh_port = ""
+
+# Private SSH key file path, which has access to all the instances.
+# Eg.: ssh_key_file = "~/.ssh/A2HA.pem"
+ssh_key_file = ""
+
+# Eg.: backup_config = "efs" or "s3"
+backup_config = ""
+
+#    Note: 1. To create new bucket, make sure to give a unique name
+#          2. User can also add existing bucket 
+#
+# If s3 is selected for backup_config,
+#     uncomment and add the value for following 's3_bucketName' attribute
+
+# s3_bucketName = ""
+## === ===
+
+secrets_key_file = "/hab/a2_deploy_workspace/secrets.key"
+secrets_store_file = "/hab/a2_deploy_workspace/secrets.json"
+architecture = "aws"
+workspace_path = "/hab/a2_deploy_workspace"
+
+# DON'T MODIFY THE BELOW LINE (backup_mount)
+backup_mount = "/mnt/automate_backups"
+
diff --git a/lib/config_parser/testdata/AWSConfigFailure.toml b/lib/config_parser/testdata/AWSConfigFailure.toml
new file mode 100644
index 000000000..d619a0c3f
--- /dev/null
+++ b/lib/config_parser/testdata/AWSConfigFailure.toml
@@ -0,0 +1,37 @@
+# This is a Chef Automate AWS HA mode configuration file. You can run
+# 'chef-automate deploy' with this config file and it should
+# successfully create a new Chef Automate HA instances with default settings.
+
+[architecture.aws]
+## === INPUT NEEDED ===
+# Eg.: ssh_user = "ubuntu"
+ssh_user = ""
+
+# custome ssh port no to connect instances, default will be 22
+# Eg.: ssh_port = "22"
+ssh_port = ""
+
+# Private SSH key file path, which has access to all the instances.
+# Eg.: ssh_key_file = "~/.ssh/A2HA.pem"
+ssh_key_file = ""
+
+# Eg.: backup_config = "efs" or "s3"
+backup_config = ""
+
+#    Note: 1. To create new bucket, make sure to give a unique name
+#          2. User can also add existing bucket 
+#
+# If s3 is selected for backup_config,
+#     uncomment and add the value for following 's3_bucketName' attribute
+
+# s3_bucketName = ""
+## === ===
+
+secrets_key_file = "/hab/a2_deploy_workspace/secrets.key
+secrets_store_file = "/hab/a2_deploy_workspace/secrets.json"
+architecture = "aws"
+workspace_path = "/hab/a2_deploy_workspace"
+
+# DON'T MODIFY THE BELOW LINE (backup_mount)
+backup_mount = "/mnt/automate_backups"
+
diff --git a/lib/config_parser/testdata/OnPremConfig.toml b/lib/config_parser/testdata/OnPremConfig.toml
new file mode 100644
index 000000000..c641c1a18
--- /dev/null
+++ b/lib/config_parser/testdata/OnPremConfig.toml
@@ -0,0 +1,15 @@
+# This is a Chef Automate on-prem HA mode configuration file. You can run
+# 'chef-automate deploy' with this config file, and it should
+# successfully create a new Chef Automate HA instance with default settings.
+[architecture.existing_infra]
+ssh_user = ""
+# private ssh key file path to access instances
+# Eg.: ssh_user = "~/.ssh/A2HA.pem"
+ssh_key_file = ""
+ssh_port = "22"
+secrets_key_file = "/hab/a2_deploy_workspace/secrets.key"
+secrets_store_file = "/hab/a2_deploy_workspace/secrets.json"
+architecture = "existing_nodes"
+# DON'T MODIFY THE BELOW LINE (workspace_path)
+workspace_path = "/hab/a2_deploy_workspace"
+backup_mount = "/mnt/automate_backups"
diff --git a/lib/config_parser/testdata/OnPremConfigFailure.toml b/lib/config_parser/testdata/OnPremConfigFailure.toml
new file mode 100644
index 000000000..8d34f84b8
--- /dev/null
+++ b/lib/config_parser/testdata/OnPremConfigFailure.toml
@@ -0,0 +1,15 @@
+# This is a Chef Automate on-prem HA mode configuration file. You can run
+# 'chef-automate deploy' with this config file, and it should
+# successfully create a new Chef Automate HA instance with default settings.
+[architecture.existing_infra]
+ssh_user = ""
+# private ssh key file path to access instances
+# Eg.: ssh_user = "~/.ssh/A2HA.pem"
+ssh_key_file = ""
+ssh_port = "22"
+secrets_key_file = "/hab/a2_deploy_workspace/secrets.key
+secrets_store_file = "/hab/a2_deploy_workspace/secrets.json"
+architecture = "existing_nodes"
+# DON'T MODIFY THE BELOW LINE (workspace_path)
+workspace_path = "/hab/a2_deploy_workspace"
+backup_mount = "/mnt/automate_backups"
diff --git a/lib/config_parser/testdata/StandaloneConfig.toml b/lib/config_parser/testdata/StandaloneConfig.toml
new file mode 100644
index 000000000..4097767d3
--- /dev/null
+++ b/lib/config_parser/testdata/StandaloneConfig.toml
@@ -0,0 +1,6 @@
+# This is a default Chef Automate configuration file. You can run
+# 'chef-automate deploy' with this config file and it should
+# successfully create a new Chef Automate instance with default settings.
+
+[global.v1]
+fqdn = "Public_DNS_name"
diff --git a/lib/reporting/helperForVerification_test.go b/lib/reporting/helperForVerification_test.go
new file mode 100644
index 000000000..a03e4597a
--- /dev/null
+++ b/lib/reporting/helperForVerification_test.go
@@ -0,0 +1,410 @@
+package reporting
+
+import (
+	"testing"
+
+	"github.com/chef/automate/components/automate-deployment/pkg/cli"
+	"github.com/fatih/color"
+	"github.com/jedib0t/go-pretty/v5/table"
+	"github.com/stretchr/testify/assert"
+)
+
+const (
+	automate     = "Automate"
+	certificate  = "Certificates"
+	toResolveMsg = "1. Add the start and end certificate markers"
+	summaryTable = "AutomateSummaryTable"
+	ip           = "127.0.0.4"
+	ipResult     = "127.0.0.4:"
+)
+
+var tbMap = map[string]*Table{
+	automate: {
+		Title:     automate,
+		Header:    table.Row{"No.", "Identifier", "Parameter", "Status", "Message"},
+		ColConfig: []table.ColumnConfig{{Number: 1, WidthMax: 5, WidthMin: 5}, {Number: 2, WidthMax: 15, WidthMin: 15}, {Number: 3, WidthMax: 25, WidthMin: 25}, {Number: 4, WidthMax: 15, WidthMin: 15}, {Number: 5, WidthMax: 60, WidthMin: 60}},
+	},
+	summaryTable: {
+		Title:     "SUMMARY : Automate",
+		Header:    table.Row{"Parameter", "Successful", "Failed", "How to resolve it"},
+		ColConfig: []table.ColumnConfig{{Number: 1, WidthMax: 30, WidthMin: 30}, {Number: 2, WidthMax: 15, WidthMin: 15}, {Number: 3, WidthMax: 15, WidthMin: 15}, {Number: 4, WidthMax: 65, WidthMin: 65}},
+	},
+}
+
+func getMockReportingModule(wr *cli.Writer) Reporting {
+	return &ReportingModule{
+		writer: wr,
+		tables: tbMap,
+	}
+}
+
+var reportChan = make(chan VerificationReport, 10)
+var nodeInfoMap = make(map[string][]Info)
+var done = make(chan bool, 1)
+
+func TestVerificationReports(t *testing.T) {
+	cw := getMockWriterImpl()
+	type args struct {
+		reportChan  chan VerificationReport
+		reporting   Reporting
+		nodeInfoMap map[string][]Info
+		done        chan bool
+	}
+	test := struct {
+		name string
+		args args
+		want string
+	}{
+
+		name: successStr,
+		args: args{
+			reportChan:  reportChan,
+			reporting:   getMockReportingModule(cw.CliWriter),
+			nodeInfoMap: nodeInfoMap,
+			done:        done,
+		},
+		want: "Automate\n+-------+-----------------+---------------------------+-----------------+--------------------------------------------------------------+\n|   NO. |      IDENTIFIER |                 PARAMETER |          STATUS |                                                      MESSAGE |\n+-------+-----------------+---------------------------+-----------------+--------------------------------------------------------------+\n+-------+-----------------+---------------------------+-----------------+--------------------------------------------------------------+\nSUMMARY : Automate\n+--------------------------------+-----------------+-----------------+-------------------------------------------------------------------+\n|                      PARAMETER |      SUCCESSFUL |          FAILED |                                                 HOW TO RESOLVE IT |\n+--------------------------------+-----------------+-----------------+-------------------------------------------------------------------+\n+--------------------------------+-----------------+-----------------+-------------------------------------------------------------------+\n",
+	}
+
+	report := VerificationReport{
+		TableKey: "",
+		Report: Info{
+			Hostip:        "",
+			Parameter:     "",
+			Status:        "",
+			StatusMessage: &StatusMessage{},
+			SummaryInfo:   &SummaryInfo{},
+		},
+		TotalReports: 0,
+	}
+
+	reportChan <- report
+	reportChan <- report
+	close(reportChan)
+
+	VerificationReports(test.args.reportChan, test.args.reporting, test.args.nodeInfoMap, test.args.done)
+	if <-done {
+		assert.Equal(t, test.want, cw.Output())
+
+	}
+}
+
+func TestCreateStatusTableRows(t *testing.T) {
+	type args struct {
+		index     int
+		rowData   *Info
+		reporting Reporting
+	}
+	tests := []struct {
+		name string
+		args args
+		want []table.Row
+	}{
+		{
+			name: "Status is Success",
+			args: args{
+				index: 1,
+				rowData: &Info{
+					Hostip:    ip,
+					Parameter: certificate,
+					Status:    successStr,
+					StatusMessage: &StatusMessage{
+						MainMessage: "Cerificate validation successful",
+						SubMessage:  []string{"Certificate about to expire <Date>"},
+					},
+					SummaryInfo: &SummaryInfo{},
+				},
+				reporting: getMockReportingModule(getMockWriterImpl().CliWriter),
+			},
+			want: []table.Row{{1, ip, certificate, color.New(color.FgGreen).Sprint("✔ Success"), "Cerificate validation successful"}, {"", "", "", "", color.New(color.FgYellow).Sprint("! [ Warning ] ") + "Certificate about to expire <Date>"}},
+		},
+		{
+			name: "Status is Failed",
+			args: args{
+				index: 1,
+				rowData: &Info{
+					Hostip:    ip,
+					Parameter: certificate,
+					Status:    failedStr,
+					StatusMessage: &StatusMessage{
+						MainMessage: "Certificate validation failed",
+						SubMessage:  []string{"Certificate is not formatted properly"},
+					},
+					SummaryInfo: &SummaryInfo{},
+				},
+				reporting: getMockReportingModule(getMockWriterImpl().CliWriter),
+			},
+			want: []table.Row{{1, color.New(color.FgRed).Sprint(ip), color.New(color.FgRed).Sprint(certificate), color.New(color.FgRed).Sprint("✖ Failed"), color.New(color.FgRed).Sprint("Certificate validation failed")}, {"", "", "", "", color.New(color.FgRed).Sprint("✖ [ Failed ] Certificate is not formatted properly")}},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := createStatusTableRows(tt.args.index, tt.args.rowData, tt.args.reporting)
+			assert.Equal(t, tt.want, got)
+		})
+	}
+}
+
+func TestCreateSummaryTableRowData(t *testing.T) {
+	type args struct {
+		summary map[string]SummaryInfo
+		rowData *Info
+	}
+	tests := []struct {
+		name string
+		args args
+		want map[string]SummaryInfo
+	}{
+		{
+			name: successStr,
+			args: args{
+				summary: map[string]SummaryInfo{},
+				rowData: &Info{
+					Hostip:    ip,
+					Parameter: certificate,
+					Status:    failedStr,
+					StatusMessage: &StatusMessage{
+						MainMessage: "Certificate B validation failed",
+						SubMessage:  []string{"Certificate is not formatted properly"},
+					},
+					SummaryInfo: &SummaryInfo{
+						FailedCount: 1,
+						ToResolve:   []string{"Add the start and end certificate markers"},
+					},
+				},
+			},
+			want: map[string]SummaryInfo{
+				certificate: {
+					SuccessfulCount: 0,
+					FailedCount:     1,
+					ToResolve:       []string{ipResult, toResolveMsg},
+				},
+			},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := createSummaryTableRowData(tt.args.summary, tt.args.rowData)
+			assert.Equal(t, tt.want, got)
+		})
+	}
+}
+
+func TestCreateSummaryTableRows(t *testing.T) {
+	type args struct {
+		rowData   map[string]SummaryInfo
+		reporting Reporting
+	}
+	tests := []struct {
+		name string
+		args args
+		want []table.Row
+	}{
+		{
+			name: "ToResolve steps are present",
+			args: args{
+				rowData: map[string]SummaryInfo{
+					certificate: {
+						SuccessfulCount: 0,
+						FailedCount:     1,
+						ToResolve:       []string{ipResult, toResolveMsg},
+					},
+				},
+				reporting: getMockReportingModule(getMockWriterImpl().CliWriter),
+			},
+			want: []table.Row{{"Certificates", color.New(color.FgGreen).Sprint("0"), color.New(color.FgRed).Sprint("1"), ipResult}, {"", "", "", toResolveMsg}},
+		},
+		{
+			name: "ToResolve steps are not present",
+			args: args{
+				rowData: map[string]SummaryInfo{
+					certificate: {
+						SuccessfulCount: 1,
+						FailedCount:     0,
+						ToResolve:       []string{},
+					},
+				},
+				reporting: getMockReportingModule(getMockWriterImpl().CliWriter),
+			},
+			want: []table.Row{{"Certificates", color.New(color.FgGreen).Sprint("1"), color.New(color.FgRed).Sprint("0"), ""}},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			got := createSummaryTableRows(tt.args.rowData, tt.args.reporting)
+			assert.Equal(t, tt.want, got)
+		})
+	}
+}
+
+func TestShowProgress(t *testing.T) {
+	type args struct {
+		tableProgess map[string]progress
+		lines        int
+	}
+	test := struct {
+		name string
+		args args
+		want int
+	}{
+		name: successStr,
+		args: args{
+			tableProgess: map[string]progress{
+				automate: {
+					currentCount: 2,
+					totalCount:   3,
+				},
+			},
+			lines: 1,
+		},
+		want: 1,
+	}
+
+	got := showProgress(test.args.tableProgess, test.args.lines)
+	assert.Equal(t, test.want, got)
+
+}
+
+func TestUpdateTableTitle(t *testing.T) {
+	type args struct {
+		reporting Reporting
+		nodeInfo  map[string][]Info
+		keyMap    map[string][]string
+	}
+	tests := []struct {
+		name string
+		args args
+		want string
+	}{
+		{
+			name: "Title updated correctly when status is failed",
+			args: args{
+				reporting: getMockReportingModule(getMockWriterImpl().CliWriter),
+				nodeInfo: map[string][]Info{
+					automate: {
+						{
+							Hostip:    ip,
+							Parameter: certificate,
+							Status:    failedStr,
+						},
+					},
+				},
+				keyMap: map[string][]string{
+					automate: {automate, summaryTable},
+				},
+			},
+			want: color.New(color.FgRed).Sprint("✖ Automate"),
+		},
+		{
+			name: "Title updated correctly when status is succes",
+			args: args{
+				reporting: getMockReportingModule(getMockWriterImpl().CliWriter),
+				nodeInfo: map[string][]Info{
+					automate: {
+						{
+							Hostip:    ip,
+							Parameter: certificate,
+							Status:    successStr,
+						},
+					},
+				},
+				keyMap: map[string][]string{
+					automate: {automate, summaryTable},
+				},
+			},
+			want: color.New(color.FgGreen).Sprint("✔ Automate"),
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			oldTitle := tt.args.reporting.GetTable(tt.args.keyMap[automate][0]).Title
+			updateTableTitle(tt.args.reporting, tt.args.nodeInfo, tt.args.keyMap)
+			assert.Equal(t, tt.want, tt.args.reporting.GetTable(tt.args.keyMap[automate][0]).Title)
+			tt.args.reporting.GetTable(tt.args.keyMap[automate][0]).Title = oldTitle
+		})
+	}
+}
+
+func TestCheckFailedStatus(t *testing.T) {
+	type args struct {
+		info []Info
+	}
+	tests := []struct {
+		name string
+		args args
+		want bool
+	}{
+		{
+			name: "Info array contains report with failed status",
+			args: args{
+				info: []Info{
+					{Status: failedStr},
+					{Status: successStr},
+					{Status: successStr},
+				},
+			},
+			want: true,
+		},
+		{
+			name: "Info array does not contains report with failed status",
+			args: args{
+				info: []Info{
+					{Status: successStr},
+					{Status: successStr},
+					{Status: successStr},
+				},
+			},
+			want: false,
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := checkFailedStatus(tt.args.info); got != tt.want {
+				t.Errorf("checkFailedStatus() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestMatchNodeNameWithRespectiveTablesName(t *testing.T) {
+	type args struct {
+		substring string
+		keys      []string
+	}
+	test := struct {
+		name string
+		args args
+		want []string
+	}{
+		name: "Keys containing substring in alphabetical order",
+		args: args{
+			substring: "ab",
+			keys:      []string{"abab", "abc", "bcd", "bcda"},
+		},
+		want: []string{"abab", "abc"},
+	}
+
+	got := matchNodeNameWithRespectiveTablesName(test.args.substring, test.args.keys)
+	assert.Equal(t, test.want, got)
+}
+
+func TestCreateIndexForToResolve(t *testing.T) {
+	type args struct {
+		data []string
+	}
+	test := struct {
+		name string
+		args args
+		want []string
+	}{
+		name: successStr,
+		args: args{
+			data: []string{"Step 1", "Step 2"},
+		},
+		want: []string{"1. Step 1", "2. Step 2"},
+	}
+
+	got := createIndexForToResolve(test.args.data)
+	assert.Equal(t, test.want, got)
+
+}
diff --git a/lib/reporting/reporting_test.go b/lib/reporting/reporting_test.go
new file mode 100644
index 000000000..8eb54ace0
--- /dev/null
+++ b/lib/reporting/reporting_test.go
@@ -0,0 +1,367 @@
+package reporting
+
+import (
+	"reflect"
+	"testing"
+
+	"github.com/chef/automate/components/automate-deployment/pkg/cli"
+	"github.com/chef/automate/lib/majorupgrade_utils"
+	"github.com/fatih/color"
+	"github.com/jedib0t/go-pretty/v5/table"
+	"github.com/stretchr/testify/assert"
+)
+
+const (
+	successStr = "Success"
+	failedStr  = "Failed"
+	waringStr  = "Warning"
+	test1      = "test1"
+	test2      = "test2"
+	header     = "header"
+	header1    = "header1"
+	header2    = "header2"
+	col        = "col"
+	col1       = "col1"
+	col2       = "col2"
+)
+
+type fields struct {
+	writer *cli.Writer
+	tables map[string]*Table
+}
+
+var tableMap = map[string]*Table{
+	test1: {
+		Title:     test1,
+		Rows:      []table.Row{{col}},
+		Header:    table.Row{header},
+		Footer:    table.Row{},
+		ColConfig: []table.ColumnConfig{},
+	},
+	test2: {
+		Title:     test2,
+		Rows:      []table.Row{{col1, col2}},
+		Header:    table.Row{header1, header2},
+		Footer:    table.Row{},
+		ColConfig: []table.ColumnConfig{},
+	},
+}
+
+var module = fields{
+	writer: getMockWriterImpl().CliWriter,
+	tables: tableMap,
+}
+
+func TestNewReportingModule(t *testing.T) {
+	tests := []struct {
+		name string
+		args fields
+		want Reporting
+	}{
+		{
+			name: successStr,
+			args: module,
+			want: nil,
+		},
+	}
+	for _, tt := range tests {
+		NewReportingModule(tt.args.writer, tt.args.tables)
+	}
+}
+
+func TestGetTable(t *testing.T) {
+	tests := []struct {
+		name   string
+		fields fields
+		args   string
+		want   *Table
+	}{
+		{
+			name:   successStr,
+			fields: module,
+			args:   test1,
+			want: &Table{
+				Title:     test1,
+				Rows:      []table.Row{{col}},
+				Header:    table.Row{header},
+				Footer:    table.Row{},
+				ColConfig: []table.ColumnConfig{},
+			},
+		},
+	}
+	for _, tt := range tests {
+		r := &ReportingModule{
+			writer: tt.fields.writer,
+			tables: tt.fields.tables,
+		}
+		got := r.GetTable(tt.args)
+		assert.Equal(t, tt.want, got)
+	}
+}
+
+func TestGetAllTables(t *testing.T) {
+	tests := []struct {
+		name   string
+		fields fields
+		want   map[string]*Table
+	}{
+		{
+			name:   successStr,
+			fields: module,
+			want: map[string]*Table{
+				test1: {
+					Title:     test1,
+					Rows:      []table.Row{{col}},
+					Header:    table.Row{header},
+					Footer:    table.Row{},
+					ColConfig: []table.ColumnConfig{},
+				},
+				test2: {
+					Title:     test2,
+					Rows:      []table.Row{{col1, col2}},
+					Header:    table.Row{header1, header2},
+					Footer:    table.Row{},
+					ColConfig: []table.ColumnConfig{},
+				}},
+		},
+	}
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			r := &ReportingModule{
+				writer: tt.fields.writer,
+				tables: tt.fields.tables,
+			}
+			if got := r.GetAllTables(); !reflect.DeepEqual(got, tt.want) {
+				t.Errorf("ReportingModule.GetAllTables() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
+
+func TestGetAllTableKeys(t *testing.T) {
+	test := struct {
+		name   string
+		fields fields
+		want   []string
+	}{
+
+		name:   successStr,
+		fields: module,
+		want:   []string{test1, test2},
+	}
+
+	r := &ReportingModule{
+		writer: test.fields.writer,
+		tables: test.fields.tables,
+	}
+	got := r.GetAllTableKeys()
+	assert.Equal(t, test.want, got)
+
+}
+
+func TestSetTable(t *testing.T) {
+	testTableMap := map[string]*Table{
+		test1: {
+			Title:     test1,
+			Rows:      []table.Row{{col}},
+			Header:    table.Row{header},
+			Footer:    table.Row{},
+			ColConfig: []table.ColumnConfig{},
+		},
+		test2: {
+			Title:     test2,
+			Rows:      []table.Row{{col1, col2}},
+			Header:    table.Row{header1, header2},
+			Footer:    table.Row{},
+			ColConfig: []table.ColumnConfig{},
+		},
+	}
+	type args struct {
+		key   string
+		table *Table
+	}
+	test := struct {
+		name   string
+		fields fields
+		args   args
+		want   *Table
+	}{
+		name: "Replace old table with given table for given key",
+		fields: fields{
+			writer: getMockWriterImpl().CliWriter,
+			tables: testTableMap,
+		},
+		args: args{
+			key:   test1,
+			table: testTableMap[test2],
+		},
+		want: testTableMap[test2],
+	}
+
+	r := &ReportingModule{
+		writer: test.fields.writer,
+		tables: test.fields.tables,
+	}
+	r.SetTable(test.args.key, test.args.table)
+	assert.EqualValues(t, test.want, r.GetTable(test1))
+}
+
+func TestAppendSpecialCharater(t *testing.T) {
+	type args struct {
+		symbol int
+		str    string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   string
+	}{
+		{
+			name:   "Append x",
+			fields: module,
+			args: args{
+				symbol: Failed,
+				str:    failedStr,
+			},
+			want: "✖ Failed",
+		},
+		{
+			name:   "Append ✔",
+			fields: module,
+			args: args{
+				symbol: Success,
+				str:    successStr,
+			},
+			want: "✔ Success",
+		},
+		{
+			name:   "Append !",
+			fields: module,
+			args: args{
+				symbol: Warning,
+				str:    waringStr,
+			},
+			want: "! Warning",
+		},
+		{
+			name:   "Add [] bracket around text",
+			fields: module,
+			args: args{
+				symbol: SquareBracket,
+				str:    waringStr,
+			},
+			want: "[ Warning ] ",
+		},
+		{
+			name:   "String returned as it is",
+			fields: module,
+			args: args{
+				symbol: 4,
+				str:    waringStr,
+			},
+			want: waringStr,
+		},
+	}
+	for _, tt := range tests {
+		r := &ReportingModule{
+			writer: tt.fields.writer,
+			tables: tt.fields.tables,
+		}
+		got := r.AppendSpecialCharater(tt.args.symbol, tt.args.str)
+		assert.Equal(t, tt.want, got)
+	}
+}
+
+func TestChangeColour(t *testing.T) {
+	type args struct {
+		fgColor int
+		msg     string
+	}
+	tests := []struct {
+		name   string
+		fields fields
+		args   args
+		want   string
+	}{
+		{
+			name:   "Change color of string to red",
+			fields: module,
+			args: args{
+				fgColor: Red,
+				msg:     test1,
+			},
+			want: color.New(color.FgRed).Sprint(test1),
+		},
+		{
+			name:   "Change color of string to green",
+			fields: module,
+			args: args{
+				fgColor: Green,
+				msg:     test1,
+			},
+			want: color.New(color.FgGreen).Sprint(test1),
+		},
+		{
+			name:   "Change color of string to yellow",
+			fields: module,
+			args: args{
+				fgColor: Yellow,
+				msg:     test1,
+			},
+			want: color.New(color.FgYellow).Sprint(test1),
+		},
+		{
+			name:   "Returned string is same as input",
+			fields: module,
+			args: args{
+				fgColor: 4,
+				msg:     test1,
+			},
+			want: test1,
+		},
+	}
+	for _, tt := range tests {
+		r := &ReportingModule{
+			writer: tt.fields.writer,
+			tables: tt.fields.tables,
+		}
+		got := r.ChangeColour(tt.args.fgColor, tt.args.msg)
+		assert.Equal(t, tt.want, got)
+	}
+}
+
+func TestGenerateTableOutputAndPrint(t *testing.T) {
+	cw := getMockWriterImpl()
+	type args struct {
+		tb *Table
+	}
+
+	test := struct {
+		name   string
+		fields fields
+		args   args
+		want   string
+	}{
+		name: "Print  given table",
+		fields: fields{
+			writer: cw.CliWriter,
+			tables: tableMap,
+		},
+		args: args{
+			tb: tableMap[test1],
+		},
+		want: "test1\n+--------+\n| HEADER |\n+--------+\n| col    |\n+--------+\n",
+	}
+
+	r := &ReportingModule{
+		writer: test.fields.writer,
+		tables: test.fields.tables,
+	}
+	r.GenerateTableOutputAndPrint(test.args.tb)
+	assert.Equal(t, test.want, cw.Output())
+}
+
+func getMockWriterImpl() *majorupgrade_utils.CustomWriter {
+	return majorupgrade_utils.NewCustomWriter()
+}