Repository: chef/automate
Pull request #8251 (2023-10-10 11:21:09)

Removing duplicate IPs for 5 node cluster
### :nut_and_bolt: Description: What code changed, and why?
As an Automate HA user, when I use 5 node cluster, it shows the error as follow:
![image](https://github.com/chef/automate/assets/54614142/80c1af86-e53c-4232-8dcc-29554cc6c444)

This is because the IPs are repeated and and `systemd-service create` is executing twice at the same time. 

In this PR, the duplicate IP are removed so the verify will run without errors. 
Screenshot: https://progresssoftware.sharepoint.com/:i:/s/ChefCoreC/EcPSQyX-U11Es7dcKyucnl4BwTLEuKg9zOgVt5UN0BX6Aw?e=ql9ieM

### :chains: Related Resources
Jira: https://chefio.atlassian.net/browse/CHEF-6207

### :+1: Definition of Done

### :athletic_shoe: How to Build and Test the Change

### :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
For 5 node cluster (or minimum node cluster)
https://progresssoftware.sharepoint.com/:i:/s/ChefCoreC/EcPSQyX-U11Es7dcKyucnl4BwTLEuKg9zOgVt5UN0BX6Aw?e=ql9ieM


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


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | e60760c8961a858e3cff75f8a20557507ace950d |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/chef-automate/deploys/652533a8abc3820007c487ab |
sonarqube-for-infrastructure-prod[bot]: **SonarQube Quality Gate**

[![Quality Gate passed](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonar.progress.com/dashboard?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251)

[![Bug](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/common/bug-16px.png 'Bug')](https://sonar.progress.com/project/issues?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251&resolved=false&types=BUG) [![A](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/RatingBadge/A-16px.png 'A')](https://sonar.progress.com/project/issues?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251&resolved=false&types=BUG) [0 Bugs](https://sonar.progress.com/project/issues?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251&resolved=false&types=BUG)  
[![Vulnerability](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/common/vulnerability-16px.png 'Vulnerability')](https://sonar.progress.com/project/issues?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251&resolved=false&types=VULNERABILITY) [![A](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/RatingBadge/A-16px.png 'A')](https://sonar.progress.com/project/issues?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonar.progress.com/project/issues?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/common/security_hotspot-16px.png 'Security Hotspot')](https://sonar.progress.com/security_hotspots?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251) [![A](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/RatingBadge/A-16px.png 'A')](https://sonar.progress.com/security_hotspots?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251) [0 Security Hotspots](https://sonar.progress.com/security_hotspots?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251)  
[![Code Smell](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/common/code_smell-16px.png 'Code Smell')](https://sonar.progress.com/project/issues?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251&resolved=false&types=CODE_SMELL) [![A](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/RatingBadge/A-16px.png 'A')](https://sonar.progress.com/project/issues?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonar.progress.com/project/issues?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251&resolved=false&types=CODE_SMELL)

[![100.0%](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/CoverageChart/100-16px.png '100.0%')](https://sonar.progress.com/component_measures?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251&metric=new_coverage&view=list) [100.0% Coverage](https://sonar.progress.com/component_measures?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251&metric=new_coverage&view=list)  
[![0.0%](https://raw.githubusercontent.com/SonarSource/sonarqube-static-resources/master/v97/checks/Duplications/3-16px.png '0.0%')](https://sonar.progress.com/component_measures?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonar.progress.com/component_measures?id=chef_automate_AYeOVEbqJ4YHsO5MtKWC&pullRequest=8251&metric=new_duplicated_lines_density&view=list)



Patch:
diff --git a/components/automate-cli/cmd/chef-automate/verify.go b/components/automate-cli/cmd/chef-automate/verify.go
index 19b00fcc0..f605adb01 100644
--- a/components/automate-cli/cmd/chef-automate/verify.go
+++ b/components/automate-cli/cmd/chef-automate/verify.go
@@ -18,6 +18,7 @@ import (
 	"github.com/chef/automate/components/automate-cli/pkg/verifyserver/server"
 	"github.com/chef/automate/components/automate-cli/pkg/verifysystemdcreate"
 	"github.com/chef/automate/components/automate-deployment/pkg/cli"
+	"github.com/chef/automate/lib/arrayutils"
 	"github.com/chef/automate/lib/config"
 	"github.com/chef/automate/lib/httputils"
 	"github.com/chef/automate/lib/logger"
@@ -484,8 +485,11 @@ func (v *verifyCmdFlow) runVerifyServiceForRemote(batchCheckConfig models.Config
 			return nil, err
 		}
 
+		// Remove duplicates
+		hostIpWihtoutDuplicates := arrayutils.RemoveStringDuplicates(hostIPs)
+
 		// Starting automate-verify service on remote nodes
-		err = v.startServiceOnRemoteNodes(destFileName, sshConfig, hostIPs)
+		err = v.startServiceOnRemoteNodes(destFileName, sshConfig, hostIpWihtoutDuplicates)
 		if err != nil {
 			return nil, err
 		}
diff --git a/lib/arrayutils/remove_duplicate.go b/lib/arrayutils/remove_duplicate.go
new file mode 100644
index 000000000..291dcadde
--- /dev/null
+++ b/lib/arrayutils/remove_duplicate.go
@@ -0,0 +1,21 @@
+package arrayutils
+
+func RemoveStringDuplicates(inputArray []string) []string {
+	arrayWithoutDuplicate := []string{}
+	for _, item := range inputArray {
+		if !contains(arrayWithoutDuplicate, item) {
+			arrayWithoutDuplicate = append(arrayWithoutDuplicate, item)
+		}
+	}
+	return arrayWithoutDuplicate
+}
+
+func contains(arrayWithoutDuplicate []string, item string) bool {
+	index := -1
+	for i := range arrayWithoutDuplicate {
+		if item == arrayWithoutDuplicate[i] {
+			index = i
+		}
+	}
+	return index >= 0
+}


Test patch:
diff --git a/lib/arrayutils/remove_duplicate_test.go b/lib/arrayutils/remove_duplicate_test.go
new file mode 100644
index 000000000..525b24597
--- /dev/null
+++ b/lib/arrayutils/remove_duplicate_test.go
@@ -0,0 +1,51 @@
+package arrayutils_test
+
+import (
+	"testing"
+
+	"github.com/bmizerany/assert"
+	"github.com/chef/automate/lib/arrayutils"
+)
+
+func TestRemoveStringDuplicates(t *testing.T) {
+
+	testCases := []struct {
+		title         string
+		inputArray    []string
+		expectedArray []string
+		wantErr       bool
+		expectedErr   error
+	}{
+		{
+			title:         "Have duplicate value",
+			inputArray:    []string{"0.0.0.0", "0.0.0.0", "0.0.0.1"},
+			expectedArray: []string{"0.0.0.0", "0.0.0.1"},
+			wantErr:       false,
+			expectedErr:   nil,
+		},
+		{
+			title:         "Have no duplicate value",
+			inputArray:    []string{"0.0.0.0", "0.0.0.1"},
+			expectedArray: []string{"0.0.0.0", "0.0.0.1"},
+			wantErr:       false,
+			expectedErr:   nil,
+		},
+		{
+			title:         "empty array",
+			inputArray:    []string{},
+			expectedArray: []string{},
+			wantErr:       false,
+			expectedErr:   nil,
+		},
+	}
+	for _, testCase := range testCases {
+		t.Run(testCase.title, func(t *testing.T) {
+			output := arrayutils.RemoveStringDuplicates(testCase.inputArray)
+			if !testCase.wantErr {
+				// assert.Error(t, err)
+				assert.Equal(t, testCase.expectedArray, output)
+			}
+		})
+	}
+
+}