Skip to content

Commit

Permalink
fix: installing same LTS-T opsman version doesn't force-reinstall
Browse files Browse the repository at this point in the history
- Previously when running om vm-lifecycle upgrade-opsman, if
  the version to install had a filename with just a 3-digit
  semver, and it was the same version as what was currently
  installed, om would erroneously conclude the versions were
  different and kick off an "upgrade".
- This was because the OpsMan team changed their filename format
  from X.Y.Z-build.A in OpsMan 2.5.0-3.0.4, to X.Y.Z in
  OpsMan 3.0.5+LTS-T and beyond.  So for 3.0.5+LTS-T onwards, the
  filename said X.Y.Z but the OpsMan endpoint still gave
  X.Y.Z-build.A, and our comparison function would report they
  were different versions.
- Now we're just comparing the core X.Y.Z everywhere, for
  consistency.

[#186712778]
  • Loading branch information
Spimtav committed Jan 10, 2024
1 parent f12a92d commit e1321bf
Show file tree
Hide file tree
Showing 2 changed files with 152 additions and 58 deletions.
22 changes: 9 additions & 13 deletions vmlifecycle/extractopsmansemver/do.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 +10,23 @@ import (
)

var (
extractSemverVersionRegex = regexp.MustCompile(`(\d+)\.(\d+)\.(\d+)(-build\.\d+)?`)
extractOldOpsmanVersionRegex = regexp.MustCompile(`(\d+)\.(\d+)-build\.(\d+)`)
oldOpsmanBuildFormatRegex = regexp.MustCompile(`(\d+)\.(\d+)-build\.(\d+)`)
semverRegex = regexp.MustCompile(`(\d+)\.(\d+)\.(\d+)`)
)

func Do(s string) (semver.Version, error) {
name := regexp.MustCompile(`^\[.*?]`).ReplaceAllString(filepath.Base(s), "")
foundVersion := ""

extractedVersion := extractSemverVersionRegex.FindStringSubmatch(name)
if extractedVersion != nil {
foundVersion = extractedVersion[0]
} else {
extractedVersion = extractOldOpsmanVersionRegex.FindStringSubmatch(name)
if extractedVersion != nil {
foundVersion = strings.Join([]string{extractedVersion[1], extractedVersion[2], extractedVersion[3]}, ".")
}

extractedVersion := semverRegex.FindStringSubmatch(name)
if extractedVersion == nil {
extractedVersion = oldOpsmanBuildFormatRegex.FindStringSubmatch(name)
}

if foundVersion == "" {
if extractedVersion == nil {
return semver.Version{}, errors.New("cannot find version from string")
}

foundVersion := strings.Join([]string{extractedVersion[1], extractedVersion[2], extractedVersion[3]}, ".")

return semver.Make(foundVersion)
}
188 changes: 143 additions & 45 deletions vmlifecycle/vmlifecyclecommands/upgrade_opsman_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,21 +239,19 @@ var _ = Describe("upgradeOpsman", func() {
})

When("the versions are the same", func() {
BeforeEach(func() {
info := map[string]interface{}{
"info": map[string]interface{}{
"version": "2.2-build.296",
},
}
server.AppendHandlers(ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v0/info"),
ghttp.RespondWithJSONEncoded(200, info),
), ensureAvailabilityHandler)
})

When("the --Recreate flag is not passed", func() {
for _, fileNameFixture := range []string{"OpsManager%sonGCP.yml", "[ops-manager,2.2.3]ops-manager-vsphere-%s.ova"} {
It("does not continue the upgrade process and the filename is "+fileNameFixture, func() {
table.DescribeTable("does not continue the upgrade process and the filename is "+fileNameFixture, func(currentVersion string, newerVersion string) {
info := map[string]interface{}{
"info": map[string]interface{}{
"version": currentVersion,
},
}
server.AppendHandlers(ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v0/info"),
ghttp.RespondWithJSONEncoded(200, info),
), ensureAvailabilityHandler)

command, createService, deleteService, _, _ := createUpgradeOpsmanCommand()

command.ImportInstallation.EnvFile = writeFile(createJsonString(map[string]interface{}{
Expand All @@ -264,7 +262,7 @@ var _ = Describe("upgradeOpsman", func() {
"decryption-passphrase": "decryption-passphrase",
}))

fh, err := ioutil.TempFile("", fmt.Sprintf(fileNameFixture, "2.2-build.296"))
fh, err := ioutil.TempFile("", fmt.Sprintf(fileNameFixture, newerVersion))
Expect(err).ToNot(HaveOccurred())
Expect(fh.Close()).ToNot(HaveOccurred())

Expand All @@ -274,31 +272,75 @@ var _ = Describe("upgradeOpsman", func() {
Expect(err).ToNot(HaveOccurred())
Expect(createService.CreateVMCallCount()).To(Equal(0))
Expect(deleteService.DeleteVMCallCount()).To(Equal(0))
})
},
// Same formats
table.Entry("semver", "2.10.4", "2.10.4"),
table.Entry("semver with build", "2.6.1-build.92", "2.6.1-build.92"),
table.Entry("build", "2.3-build.422", "2.3-build.422"),

// Different formats
table.Entry("semver vs semver with build", "2.10.4", "2.10.4-build-75"),
table.Entry("semver vs build", "2.10.4", "2.10-build.4"),
table.Entry("build vs semver with build", "2.6-build.3", "2.6.3-build.642"),

// Different formats reversed
table.Entry("semver with build vs semver", "2.10.4-build-75", "2.10.4"),
table.Entry("build vs semver", "2.10-build.4", "2.10.4"),
table.Entry("semver with build vs build", "2.6.3-build.642", "2.6-build.3"),
)
}
})

When("the --recreate flag is passed", func() {
It("runs the delete, create, and import commands with the filename", func() {
command, createService, deleteService, _, _ := createUpgradeOpsmanCommand()
command.Recreate = true
command.ImportInstallation.EnvFile = writeFile(createJsonString(map[string]interface{}{
"target": server.URL(),
"request-timeout": 1,
"connect-timeout": 1,
"skip-ssl-validation": true,
"decryption-passphrase": "decryption-passphrase",
}))
for _, fileNameFixture := range []string{"OpsManager%sonGCP.yml", "[ops-manager,2.2.3]ops-manager-vsphere-%s.ova"} {
table.DescribeTable("runs the delete, create, and import commands with the filename, and the filename is "+fileNameFixture, func(currentVersion string, newerVersion string) {
info := map[string]interface{}{
"info": map[string]interface{}{
"version": currentVersion,
},
}
server.AppendHandlers(ghttp.CombineHandlers(
ghttp.VerifyRequest("GET", "/api/v0/info"),
ghttp.RespondWithJSONEncoded(200, info),
), ensureAvailabilityHandler)

image, err := ioutil.TempFile("", "OpsManager2.2-build.296onGCP.yml")
Expect(err).ToNot(HaveOccurred())
command.CreateVM.ImageFile = image.Name()
err = command.Execute([]string{})
command, createService, deleteService, _, _ := createUpgradeOpsmanCommand()
command.Recreate = true
command.ImportInstallation.EnvFile = writeFile(createJsonString(map[string]interface{}{
"target": server.URL(),
"request-timeout": 1,
"connect-timeout": 1,
"skip-ssl-validation": true,
"decryption-passphrase": "decryption-passphrase",
}))

Expect(err).ToNot(HaveOccurred())
Expect(deleteService.DeleteVMCallCount()).To(Equal(1))
Expect(createService.CreateVMCallCount()).To(Equal(1))
})
fh, err := ioutil.TempFile("", fmt.Sprintf(fileNameFixture, newerVersion))
Expect(err).ToNot(HaveOccurred())
Expect(fh.Close()).ToNot(HaveOccurred())

command.CreateVM.ImageFile = fh.Name()
err = command.Execute([]string{})

Expect(err).ToNot(HaveOccurred())
Expect(deleteService.DeleteVMCallCount()).To(Equal(1))
Expect(createService.CreateVMCallCount()).To(Equal(1))
},
// Same formats
table.Entry("semver", "2.10.4", "2.10.4"),
table.Entry("semver with build", "2.6.1-build.92", "2.6.1-build.92"),
table.Entry("build", "2.3-build.422", "2.3-build.422"),

// Different formats
table.Entry("semver vs semver with build", "2.10.4", "2.10.4-build-75"),
table.Entry("semver vs build", "2.10.4", "2.10-build.4"),
table.Entry("build vs semver with build", "2.6-build.3", "2.6.3-build.642"),

// Different formats reversed
table.Entry("semver with build vs semver", "2.10.4-build-75", "2.10.4"),
table.Entry("build vs semver", "2.10-build.4", "2.10.4"),
table.Entry("semver with build vs build", "2.6.3-build.642", "2.6-build.3"),
)
}
})
})

Expand Down Expand Up @@ -337,12 +379,40 @@ var _ = Describe("upgradeOpsman", func() {
Expect(err).To(HaveOccurred())
Expect(err.Error()).To(ContainSubstring("downgrading is not supported by Ops Manager"))
},
table.Entry("semver numbers via patch", "2.5.3", "2.5.1"),
table.Entry("semver numbers via minor", "2.5.0", "2.4.3"),
table.Entry("semver numbers that have build numbers", "2.5.0-build.0", "2.4.3-build.0"),
table.Entry("semver numbers compared to a build number", "2.5.1", "2.4-build.193"),
table.Entry("build numbers via patch", "2.4-build.193", "2.4-build.100"),
table.Entry("build numbers via minor", "2.4-build.193", "2.3-build.193"),
// Same formats
table.Entry("semver, via patch", "2.5.3", "2.5.1"),
table.Entry("semver, via minor", "2.5.0", "2.4.3"),
table.Entry("semver, via major", "3.5.3", "2.5.3"),
table.Entry("semver with build, via patch", "2.5.3-build.0", "2.5.1-build.0"),
table.Entry("semver with build, via minor", "2.5.0-build.0", "2.4.3-build.0"),
table.Entry("semver with build, via major", "3.5.3-build.0", "2.5.3-build.0"),
table.Entry("build, via patch", "2.4-build.193", "2.4-build.100"),
table.Entry("build, via minor", "2.4-build.193", "2.3-build.193"),
table.Entry("build, via major", "2.4-build.193", "1.4-build.193"),

// Semver vs. semver with build
table.Entry("semver vs semver with build, via patch", "2.5.3", "2.5.2-build.0"),
table.Entry("semver vs semver with build, via minor", "2.5.3", "2.4.3-build.0"),
table.Entry("semver vs semver with build, via major", "2.5.3", "1.5.3-build.0"),
table.Entry("semver with build vs semver, via patch", "2.5.3-build.0", "2.5.2"),
table.Entry("semver with build vs semver, via minor", "2.5.3-build.0", "2.4.3"),
table.Entry("semver with build vs semver, via major", "2.5.3-build.0", "1.5.3"),

// Semver vs. build
table.Entry("semver vs build, via patch", "2.5.1", "2.5-build.0"),
table.Entry("semver vs build, via minor", "2.5.1", "2.4-build.1"),
table.Entry("semver vs build, via major", "2.5.1", "1.5-build.1"),
table.Entry("build vs semver, via patch", "2.5-build.1", "2.5.0"),
table.Entry("build vs semver, via minor", "2.5-build.1", "2.4.1"),
table.Entry("build vs semver, via major", "2.5-build.1", "1.5.1"),

// Semver with build vs build
table.Entry("semver with build vs build, via patch", "2.5.1-build.103", "2.5-build.0"),
table.Entry("semver with build vs build, via minor", "2.5.1-build.103", "2.4-build.1"),
table.Entry("semver with build vs build, via major", "2.5.1-build.103", "1.5-build.1"),
table.Entry("build vs semver with build, via patch", "2.5-build.1", "2.5.0-build.103"),
table.Entry("build vs semver with build, via minor", "2.5-build.1", "2.4.1-build.103"),
table.Entry("build vs semver with build, via major", "2.5-build.1", "1.5.1-build.103"),
)
}
})
Expand Down Expand Up @@ -383,12 +453,40 @@ var _ = Describe("upgradeOpsman", func() {
Eventually(stderr).Should(gbytes.Say(`--skip-ssl-validation curl`))
Eventually(stderr).Should(gbytes.Say(`--skip-ssl-validation import-installation`))
},
table.Entry("semver numbers via patch", "2.5.3", "2.5.4"),
table.Entry("semver numbers via minor", "2.5.0", "2.6.2"),
table.Entry("semver numbers that have build numbers", "2.5.0-build.0", "2.5.3-build.0"),
table.Entry("semver numbers compared to a build number", "2.5.1", "2.7-build.193"),
table.Entry("build numbers via patch", "2.4-build.193", "2.4-build.200"),
table.Entry("build numbers via minor", "2.4-build.193", "2.5-build.193"),
// Same formats
table.Entry("semver, via patch", "2.5.1", "2.5.3"),
table.Entry("semver, via minor", "2.4.3", "2.5.0"),
table.Entry("semver, via major", "2.5.3", "3.5.3"),
table.Entry("semver with build, via patch", "2.5.1-build.0", "2.5.3-build.0"),
table.Entry("semver with build, via minor", "2.4.3-build.0", "2.5.0-build.0"),
table.Entry("semver with build, via major", "2.5.3-build.0", "3.5.3-build.0"),
table.Entry("build, via patch", "2.4-build.100", "2.4-build.193"),
table.Entry("build, via minor", "2.3-build.193", "2.4-build.193"),
table.Entry("build, via major", "1.4-build.193", "2.4-build.193"),

// Semver vs. semver with build
table.Entry("semver vs semver with build, via patch", "2.5.2-build.0", "2.5.3"),
table.Entry("semver vs semver with build, via minor", "2.4.3-build.0", "2.5.3"),
table.Entry("semver vs semver with build, via major", "1.5.3-build.0", "2.5.3"),
table.Entry("semver with build vs semver, via patch", "2.5.2", "2.5.3-build.0"),
table.Entry("semver with build vs semver, via minor", "2.4.3", "2.5.3-build.0"),
table.Entry("semver with build vs semver, via major", "1.5.3", "2.5.3-build.0"),

// Semver vs. build
table.Entry("semver vs build, via patch", "2.5-build.0", "2.5.1"),
table.Entry("semver vs build, via minor", "2.4-build.1", "2.5.1"),
table.Entry("semver vs build, via major", "1.5-build.1", "2.5.1"),
table.Entry("build vs semver, via patch", "2.5.0", "2.5-build.1"),
table.Entry("build vs semver, via minor", "2.4.1", "2.5-build.1"),
table.Entry("build vs semver, via major", "1.5.1", "2.5-build.1"),

// Semver with build vs build
table.Entry("semver with build vs build, via patch", "2.5-build.0", "2.5.1-build.103"),
table.Entry("semver with build vs build, via minor", "2.4-build.1", "2.5.1-build.103"),
table.Entry("semver with build vs build, via major", "1.5-build.1", "2.5.1-build.103"),
table.Entry("build vs semver with build, via patch", "2.5.0-build.103", "2.5-build.1"),
table.Entry("build vs semver with build, via minor", "2.4.1-build.103", "2.5-build.1"),
table.Entry("build vs semver with build, via major", "1.5.1-build.103", "2.5-build.1"),
)
}

Expand Down

0 comments on commit e1321bf

Please sign in to comment.