Skip to content

Commit

Permalink
OCM-4624 | feat: add cache for checking version mirror
Browse files Browse the repository at this point in the history
  • Loading branch information
ciaranRoche committed Apr 17, 2024
1 parent dd63b70 commit 934406d
Show file tree
Hide file tree
Showing 46 changed files with 2,104 additions and 1,702 deletions.
4 changes: 2 additions & 2 deletions cmd/download/rosa/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ import (

"github.com/spf13/cobra"

"github.com/openshift/rosa/cmd/verify/rosa"
helper "github.com/openshift/rosa/pkg/helper/download"
rprtr "github.com/openshift/rosa/pkg/reporter"
"github.com/openshift/rosa/pkg/version"
)

var Cmd = &cobra.Command{
Expand All @@ -47,7 +47,7 @@ func run(_ *cobra.Command, _ []string) {

filename := fmt.Sprintf("rosa-%s.%s", platform, extension)

downloadURL := fmt.Sprintf("%s%s", rosa.DownloadLatestMirrorFolder, filename)
downloadURL := fmt.Sprintf("%s%s", version.DownloadLatestMirrorFolder, filename)

reporter.Infof("Downloading %s to your current directory", downloadURL)

Expand Down
2 changes: 1 addition & 1 deletion cmd/rosa/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ func init() {
root.AddCommand(uninstall.Cmd)
root.AddCommand(upgrade.Cmd)
root.AddCommand(verify.Cmd)
root.AddCommand(version.Cmd)
root.AddCommand(version.NewRosaVersionCommand())
root.AddCommand(whoami.Cmd)
root.AddCommand(hibernate.GenerateCommand())
root.AddCommand(resume.GenerateCommand())
Expand Down
2 changes: 1 addition & 1 deletion cmd/verify/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,5 +38,5 @@ func init() {
Cmd.AddCommand(oc.Cmd)
Cmd.AddCommand(permissions.Cmd)
Cmd.AddCommand(quota.Cmd)
Cmd.AddCommand(rosa.Cmd)
Cmd.AddCommand(rosa.NewVerifyRosaCommand())
}
153 changes: 60 additions & 93 deletions cmd/verify/rosa/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,123 +17,90 @@ limitations under the License.
package rosa

import (
"net/http"
"os"
"strings"
context "context"
"fmt"

"github.com/PuerkitoBio/goquery"
"github.com/hashicorp/go-version"
"github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"github.com/zgalor/weberr"

"github.com/openshift/rosa/pkg/info"
"github.com/openshift/rosa/pkg/logging"
"github.com/openshift/rosa/pkg/reporter"
"github.com/openshift/rosa/pkg/rosa"
"github.com/openshift/rosa/pkg/version"
)

var Cmd = &cobra.Command{
Use: "rosa-client",
Aliases: []string{"rosa"},
Short: "Verify ROSA client tools",
Long: "Verify that the ROSA client tools is installed and compatible.",
Example: ` # Verify rosa client tools
rosa verify rosa`,
Run: run,
Args: cobra.NoArgs,
}
var aliases = []string{"rosa"}

const (
DownloadLatestMirrorFolder = "https://mirror.openshift.com/pub/openshift-v4/clients/rosa/latest/"
baseReleasesFolder = "https://mirror.openshift.com/pub/openshift-v4/clients/rosa/"
ConsoleLatestFolder = "https://console.redhat.com/openshift/downloads#tool-rosa"
use = "rosa-client"
short = "Verify ROSA client tools"
long = "Verify that the ROSA client tools is installed and compatible."
example = ` # Verify rosa client tools
rosa verify rosa`
)

func run(_ *cobra.Command, _ []string) {
rprtr := reporter.CreateReporter()

currVersion, err := version.NewVersion(info.Version)
if err != nil {
rprtr.Errorf("There was a problem retrieving current version: %s", err)
os.Exit(1)
}
latestVersionFromMirror, err := retrieveLatestVersionFromMirror()
if err != nil {
rprtr.Errorf("There was a problem retrieving latest version from mirror: %s", err)
os.Exit(1)
}
if currVersion.LessThan(latestVersionFromMirror) {
rprtr.Infof(
"There is a newer release version '%s', please consider updating: %s",
latestVersionFromMirror, ConsoleLatestFolder,
)
} else if rprtr.IsTerminal() {
rprtr.Infof("Your ROSA CLI is up to date.")
func NewVerifyRosaCommand() *cobra.Command {
return &cobra.Command{
Use: use,
Short: short,
Long: long,
Example: example,
Aliases: aliases,
Args: cobra.NoArgs,
Run: rosa.DefaultRunner(rosa.DefaultRuntime(), VerifyRosaRunner()),
}
os.Exit(0)
}

func retrievePossibleVersionsFromMirror() ([]string, error) {
logger := logging.NewLogger()
transport := http.DefaultTransport
if logger.IsLevelEnabled(logrus.DebugLevel) {
dumper, err := logging.NewRoundTripper().Logger(logger).Next(transport).Build()
func VerifyRosaRunner() rosa.CommandRunner {
return func(_ context.Context, _ *rosa.Runtime, _ *cobra.Command, _ []string) error {
options, err := NewVerifyRosaOptions()
if err != nil {
return nil, err
return fmt.Errorf("failed to create rosa options: %v", err)
}
transport = dumper
return options.Verify()
}
client := &http.Client{Transport: transport}
}

resp, err := client.Get(baseReleasesFolder)
if err != nil {
return []string{}, weberr.Wrapf(err, "Error setting up request for latest released rosa cli")
}
defer resp.Body.Close()
if resp.StatusCode < http.StatusOK || resp.StatusCode > 299 {
return []string{},
weberr.Errorf("Error while requesting latest released rosa cli: %d %s", resp.StatusCode, resp.Status)
}
doc, err := goquery.NewDocumentFromReader(resp.Body)
//go:generate mockgen -source=cmd.go -package=rosa -destination=./cmd_mock.go
type VerifyRosa interface {
Verify() error
}

var _ VerifyRosa = &VerifyRosaOptions{}

func NewVerifyRosaOptions() (VerifyRosa, error) {
v, err := version.NewRosaVersion()
if err != nil {
return []string{}, weberr.Wrapf(err, "Error parsing response body")
return nil, err
}
possibleVersions := []string{}
doc.Find(".file").Each(func(i int, s *goquery.Selection) {
s.Find("a").Each(func(j int, ss *goquery.Selection) {
if version, ok := ss.Attr("href"); ok {
version = strings.TrimSpace(version)
version = strings.TrimRight(version, "/")
if version != "latest" {
possibleVersions = append(possibleVersions, version)
}
}
})
})
logger.Debugf("Versions available for download: %v", possibleVersions)
return possibleVersions, nil

rpt := reporter.CreateReporter()

return &VerifyRosaOptions{
rosaVersion: v,
reporter: rpt,
}, nil
}

func retrieveLatestVersionFromMirror() (*version.Version, error) {
possibleVersions, err := retrievePossibleVersionsFromMirror()
type VerifyRosaOptions struct {
rosaVersion version.RosaVersion
reporter *reporter.Object
}

func (o *VerifyRosaOptions) Verify() error {
latestVersion, isLatest, err := o.rosaVersion.IsLatest(info.Version)
if err != nil {
return nil, weberr.Wrapf(err, "There was a problem retrieving possible versions from mirror.")
}
if len(possibleVersions) == 0 {
return nil, weberr.Errorf("No versions available in mirror %s", baseReleasesFolder)
return fmt.Errorf("there was a problem verifying if version is latest: %v", err)
}
latestVersion, err := version.NewVersion(possibleVersions[0])
if err != nil {
return nil, weberr.Wrapf(err, "There was a problem retrieving latest version.")

if !isLatest {
o.reporter.Infof(
"There is a newer release version '%s', please consider updating: %s",
latestVersion, version.ConsoleLatestFolder)
return nil
}
for _, ver := range possibleVersions[1:] {
curVersion, err := version.NewVersion(ver)
if err != nil {
continue
}
if curVersion.GreaterThan(latestVersion) {
latestVersion = curVersion
}

if o.reporter.IsTerminal() {
o.reporter.Infof("Your ROSA CLI is up to date.")
}
return latestVersion, nil
return nil
}
53 changes: 53 additions & 0 deletions cmd/verify/rosa/cmd_mock.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions cmd/verify/rosa/cmd_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package rosa

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestRosaVerify(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "ROSA Verify Suite")
}
68 changes: 68 additions & 0 deletions cmd/verify/rosa/cmd_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package rosa

import (
"fmt"

"go.uber.org/mock/gomock"

goVer "github.com/hashicorp/go-version"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

"github.com/openshift/rosa/pkg/version"
)

var _ = Describe("VerifyRosaOptions", func() {
var ctrl *gomock.Controller

BeforeEach(func() {
ctrl = gomock.NewController(GinkgoT())
})

AfterEach(func() {
ctrl.Finish()
})

Context("NewVerifyRosaOptions", func() {
It("should create VerifyRosaOptions successfully", func() {
versionMock := version.NewMockRosaVersion(ctrl)
versionMock.EXPECT().IsLatest(gomock.Any()).Return(
nil, false, fmt.Errorf("failed to check latest version"))

opts := &VerifyRosaOptions{
rosaVersion: versionMock,
}

err := opts.Verify()
Expect(err).ToNot(BeNil())
Expect(err.Error()).To(Equal(
"there was a problem verifying if version is latest: failed to check latest version"))

})

It("should return no error if version is up to date", func() {
versionMock := version.NewMockRosaVersion(ctrl)
versionMock.EXPECT().IsLatest(gomock.Any()).Return(&goVer.Version{}, true, nil).AnyTimes()

opts := &VerifyRosaOptions{
rosaVersion: versionMock,
}

err := opts.Verify()
Expect(err).To(BeNil())
})
})
})

var _ = Describe("NewVerifyRosaCommand", func() {
When("NewVerifyRosa succeeds", func() {
It("should return a valid command", func() {
cmd := NewVerifyRosaCommand()
Expect(cmd).ToNot(BeNil())
Expect(cmd.Use).To(Equal("rosa-client"))
Expect(cmd.Aliases).To(Equal([]string{"rosa"}))
Expect(cmd.Short).To(Equal("Verify ROSA client tools"))
Expect(cmd.Long).To(Equal("Verify that the ROSA client tools is installed and compatible."))
})
})
})
Loading

0 comments on commit 934406d

Please sign in to comment.