Skip to content

Commit

Permalink
PMM-13534: Use platform address for version service (#3306)
Browse files Browse the repository at this point in the history
* improve error handling for empty version list

* drop unneeded check

* use debug messages and fix formatting

* Allow nil in latest tests

There is a possibility of nil (when we don't have any tag available).
This updates the test to allow such cases and only check if latest is
not nil

* support staging and prod version lists

* update version URL

* trigger rebuild

---------

Co-authored-by: Alex Demidoff <[email protected]>
Co-authored-by: Nurlan Moldomurov <[email protected]>
  • Loading branch information
3 people authored Nov 18, 2024
1 parent 417d80b commit 7d61381
Show file tree
Hide file tree
Showing 7 changed files with 55 additions and 35 deletions.
2 changes: 0 additions & 2 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,11 @@ services:
- REVIEWDOG_GITHUB_API_TOKEN=${REVIEWDOG_GITHUB_API_TOKEN}
- PMM_RELEASE_PATH=/root/go/bin
- PMM_ENABLE_ACCESS_CONTROL=${PMM_ENABLE_ACCESS_CONTROL:-0}
- PMM_DEV_VERSION_SERVICE_URL=${PMM_DEV_VERSION_SERVICE_URL}
- PMM_WATCHTOWER_HOST=${PMM_WATCHTOWER_HOST:-http://watchtower:8080}
- PMM_WATCHTOWER_TOKEN=${PMM_WATCHTOWER_TOKEN:-INSECURE_TOKEN}
- PMM_RELEASE_VERSION=3.0.0-alpha
# - PMM_DISTRIBUTION_METHOD=${PMM_DISTRIBUTION_METHOD:-docker}
# - PMM_DEV_UPDATE_DOCKER_IMAGE=${PMM_DEV_UPDATE_DOCKER_IMAGE:-}
# - PMM_DEV_VERSION_SERVICE_URL=http://localhost:11000
# - PMM_DEV_PERCONA_PLATFORM_ADDRESS=https://check.localhost
# - PMM_DEV_PERCONA_PLATFORM_INSECURE=1
# - PMM_DEV_PERCONA_PLATFORM_PUBLIC_KEY=<public key>
Expand Down
2 changes: 1 addition & 1 deletion docs/process/v2_to_v3_environment_variables.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@ Below is a list of affected variables and their new names.
| `PERCONA_TEST_TELEMETRY_HOST` | `PMM_DEV_TELEMETRY_HOST` | |
| `PERCONA_TEST_TELEMETRY_INTERVAL` | `PMM_DEV_TELEMETRY_INTERVAL` | |
| `PERCONA_TEST_TELEMETRY_RETRY_BACKOFF` | `PMM_DEV_TELEMETRY_RETRY_BACKOFF` | |
| `PERCONA_TEST_VERSION_SERVICE_URL` | `PMM_DEV_VERSION_SERVICE_URL` | |
| `PERCONA_TEST_VERSION_SERVICE_URL` | | Removed in PMM v3, use `PMM_DEV_PERCONA_PLATFORM_ADDRESS` |
1 change: 0 additions & 1 deletion managed/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,6 @@ go test -timeout=30s -p 1 ./...
| Variable | Description | Default |
|------------------------------------------|---------------------------------------------------------------------------------------------------------------------|------------------------------------------|
| PMM_DEV_ADVISOR_STARLARK_ALLOW_RECURSION | Allows recursive functions in checks scripts | false |
| PMM_DEV_VERSION_SERVICE_URL | Sets versions service URL | https://check.percona.com/versions/v1 |
| PMM_DEV_ADVISOR_CHECKS_FILE | Specifies path to local checks file and disables downlading checks files from Percona Platform | none |
| PMM_ADVISOR_CHECKS_DISABLE_START_DELAY | Disables checks service startup delay | false |
| PMM_DEV_TELEMETRY_INTERVAL | Sets telemetry reporting interval | 24h |
Expand Down
5 changes: 4 additions & 1 deletion managed/services/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,7 +336,10 @@ func (s *Server) StartUpdate(ctx context.Context, req *serverv1.StartUpdateReque
_, latest, err := s.updater.latest(ctx)
if err != nil {

Check failure on line 337 in managed/services/server/server.go

View workflow job for this annotation

GitHub Actions / Checks

ifElseChain: rewrite if-else to switch statement (gocritic)

Check failure on line 337 in managed/services/server/server.go

View workflow job for this annotation

GitHub Actions / Checks

ifElseChain: rewrite if-else to switch statement (gocritic)
s.l.WithError(err).Error("Failed to get latest version")
newImage = defaultLatestPMMImage
return nil, status.Error(codes.Unavailable, "Failed to get latest version")
} else if latest == nil {
s.l.Info("No new version to update to.")
return nil, status.Error(codes.FailedPrecondition, "No new version to update to.")
} else {
newImage = latest.DockerImage
}
Expand Down
45 changes: 25 additions & 20 deletions managed/services/server/updater.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,16 @@ import (
"google.golang.org/grpc/codes"
grpcstatus "google.golang.org/grpc/status"

"github.com/percona/pmm/managed/utils/envvars"
"github.com/percona/pmm/version"
)

// defaultLatestPMMImage is the default image name to use when the latest version cannot be determined.
const (
defaultLatestPMMImage = "perconalab/pmm-server:3-dev-latest"
pmmUpdatePerformLog = "/srv/logs/pmm-update-perform-init.log"
defaultVersionServiceAddress = "https://check-dev.percona.com"
updateCheckInterval = 24 * time.Hour
updateCheckResultFresh = updateCheckInterval + 10*time.Minute
updateDefaultTimeout = 30 * time.Second
envfilePath = "/home/pmm/update/pmm-server.env"
pmmUpdatePerformLog = "/srv/logs/pmm-update-perform-init.log"
updateCheckInterval = 24 * time.Hour
updateCheckResultFresh = updateCheckInterval + 10*time.Minute
updateDefaultTimeout = 30 * time.Second
envfilePath = "/home/pmm/update/pmm-server.env"
)

var fileName = "/etc/pmm-server-update-version.json"
Expand Down Expand Up @@ -202,11 +200,15 @@ func (up *Updater) ForceCheckUpdates(ctx context.Context) error {

// LastCheckUpdatesResult returns the result of the last update check.
func (up *Updater) LastCheckUpdatesResult(ctx context.Context) (*version.UpdateCheckResult, time.Time) {
var latest version.DockerVersionInfo
installed := up.InstalledPMMVersion()
latest, lastCheckTime := up.checkResult(ctx)
vi, lastCheckTime := up.checkResult(ctx)
if vi != nil {
latest = *vi
}
return &version.UpdateCheckResult{
Installed: installed,
Latest: *latest,
Latest: latest,
UpdateAvailable: latest.DockerImage != "",
LatestNewsURL: "https://per.co.na/pmm/" + latest.Version.String(),
}, lastCheckTime
Expand Down Expand Up @@ -281,11 +283,12 @@ type ReleaseNotesResponse struct {
// If the current version is the latest minor version, it returns the next major version as the latest.
// If the current version is the latest version, it returns the current version as the latest.
func (up *Updater) latestAvailableFromVersionService(ctx context.Context) ([]*version.DockerVersionInfo, *version.DockerVersionInfo, error) {
versionServiceUrl := os.Getenv("PMM_DEV_VERSION_SERVICE_URL")
if versionServiceUrl == "" {
versionServiceUrl = defaultVersionServiceAddress
versionServiceURL, err := envvars.GetPlatformAddress()
if err != nil {
up.l.WithError(err).Error("Failed to get version service address")
return nil, nil, errors.Wrap(err, "failed to get version service address")
}
u := versionServiceUrl + "/metadata/v1/pmm-server"
u := versionServiceURL + "/metadata/v2/pmm-server"
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
if err != nil {
up.l.WithError(err).Error("Failed to create request")
Expand All @@ -305,11 +308,12 @@ func (up *Updater) latestAvailableFromVersionService(ctx context.Context) ([]*ve
}

if len(metadataResponse.Versions) != 0 {
up.l.Infof("Found %d versions", len(metadataResponse.Versions))
up.l.Debugf("Found %d versions", len(metadataResponse.Versions))
updates, next := up.next(*up.currentVersion(), metadataResponse.Versions)
return updates, next, err
}
return nil, nil, errors.New("no tags found")
up.l.Debug("No new PMM version available")
return nil, nil, nil
}

func (up *Updater) parseDockerTag(tag string) ([]*version.DockerVersionInfo, *version.DockerVersionInfo, error) {
Expand Down Expand Up @@ -535,11 +539,12 @@ func (up *Updater) getReleaseNotesText(ctx context.Context, version version.Pars
return releaseNotes, nil
}

versionServiceUrl := os.Getenv("PMM_DEV_VERSION_SERVICE_URL")
if versionServiceUrl == "" {
versionServiceUrl = defaultVersionServiceAddress
versionServiceURL, err := envvars.GetPlatformAddress()
if err != nil {
up.l.WithError(err).Error("Failed to get version service address")
return "", errors.Wrap(err, "failed to get version service address")
}
u := versionServiceUrl + "/release-notes/v1/pmm/" + versionString
u := versionServiceURL + "/release-notes/v1/pmm/" + versionString
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u, nil)
if err != nil {
up.l.WithError(err).Error("Failed to create request")
Expand Down
27 changes: 22 additions & 5 deletions managed/services/server/updater_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

"github.com/percona/pmm/managed/utils/envvars"
"github.com/percona/pmm/version"
)

Expand Down Expand Up @@ -270,11 +271,27 @@ func TestUpdater(t *testing.T) {
t.Run("TestLatest", func(t *testing.T) {
version.Version = "2.41.0"
u := NewUpdater(watchtowerURL, gRPCMessageMaxSize)
_, latest, err := u.latest(context.Background())
require.NoError(t, err)
assert.NotNil(t, latest)
assert.True(t, strings.HasPrefix(latest.Version.String(), "2.") || strings.HasPrefix(latest.Version.String(), "3."),
"latest version of PMM should have either a '2.' or '3.' prefix")

t.Run("LatestFromProduction", func(t *testing.T) {
_, latest, err := u.latest(context.Background())
require.NoError(t, err)
if latest != nil {
assert.True(t, strings.HasPrefix(latest.Version.String(), "3."),
"latest version of PMM should start with a '3.' prefix")
}
})
t.Run("LatestFromStaging", func(t *testing.T) {
versionServiceURL, err := envvars.GetPlatformAddress() // defaults to production
require.NoError(t, err)
defer func() {
t.Setenv(envvars.EnvPlatformAddress, versionServiceURL)
}()
t.Setenv(envvars.EnvPlatformAddress, "https://check-dev.percona.com")
_, latest, err := u.latest(context.Background())
require.NoError(t, err)
assert.True(t, strings.HasPrefix(latest.Version.String(), "3."),
"latest version of PMM should start with a '3.' prefix")
})
})

t.Run("TestParseFile", func(t *testing.T) {
Expand Down
8 changes: 3 additions & 5 deletions managed/utils/envvars/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,14 @@ import (

const (
defaultPlatformAddress = "https://check.percona.com"
envPlatformAddress = "PMM_DEV_PERCONA_PLATFORM_ADDRESS"
envPlatformInsecure = "PMM_DEV_PERCONA_PLATFORM_INSECURE"
envPlatformPublicKey = "PMM_DEV_PERCONA_PLATFORM_PUBLIC_KEY"
evnInterfaceToBind = "PMM_INTERFACE_TO_BIND"
envEnableAccessControl = "PMM_ENABLE_ACCESS_CONTROL"
envPlatformAPITimeout = "PMM_DEV_PERCONA_PLATFORM_API_TIMEOUT"
defaultPlatformAPITimeout = 30 * time.Second
// EnvPlatformAddress is the environment variable name used to store the URL for Percona Platform.
EnvPlatformAddress = "PMM_DEV_PERCONA_PLATFORM_ADDRESS"
// ENVvmAgentPrefix is the prefix for environment variables related to the VM agent.
ENVvmAgentPrefix = "VMAGENT_"
)
Expand Down Expand Up @@ -96,9 +97,6 @@ func ParseEnvVars(envs []string) (*models.ChangeSettingsParams, []error, []strin
case "PMM_DEBUG", "PMM_TRACE":
// skip cross-component environment variables that are already handled by kingpin
continue
case "PMM_DEV_VERSION_SERVICE_URL":
// skip pmm-managed environment variables that are already handled by kingpin
continue
case "PMM_CLICKHOUSE_DATABASE", "PMM_CLICKHOUSE_ADDR":
// skip env variables for external clickhouse
continue
Expand Down Expand Up @@ -293,7 +291,7 @@ func GetPlatformAPITimeout(l *logrus.Entry) time.Duration {
// GetPlatformAddress returns Percona Platform address env variable value if it's present and valid.
// Otherwise returns default Percona Platform address.
func GetPlatformAddress() (string, error) {
address := os.Getenv(envPlatformAddress)
address := os.Getenv(EnvPlatformAddress)
if address == "" {
logrus.Infof("Using default Percona Platform address %q.", defaultPlatformAddress)
return defaultPlatformAddress, nil
Expand Down

0 comments on commit 7d61381

Please sign in to comment.