Skip to content

Commit

Permalink
Resolve release markers
Browse files Browse the repository at this point in the history
  • Loading branch information
adilGhaffarDev committed Sep 20, 2023
1 parent 46412f0 commit 4ac1964
Show file tree
Hide file tree
Showing 4 changed files with 216 additions and 24 deletions.
1 change: 1 addition & 0 deletions test/e2e/cluster_upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ func ClusterUpgradeConformanceSpec(ctx context.Context, inputGetter func() Clust
Expect(ctx).NotTo(BeNil(), "ctx is required for %s spec", specName)
input = inputGetter()
Expect(input.E2EConfig).ToNot(BeNil(), "Invalid argument. input.E2EConfig can't be nil when calling %s spec", specName)
Expect(input.E2EConfig.ResolveReleases()).To(Succeed(), "Failed to resolve release markers in e2e test config file")
Expect(input.ClusterctlConfigPath).To(BeAnExistingFile(), "Invalid argument. input.ClusterctlConfigPath must be an existing file when calling %s spec", specName)
Expect(input.BootstrapClusterProxy).ToNot(BeNil(), "Invalid argument. input.BootstrapClusterProxy can't be nil when calling %s spec", specName)
Expect(os.MkdirAll(input.ArtifactFolder, 0750)).To(Succeed(), "Invalid argument. input.ArtifactFolder can't be created for %s spec", specName)
Expand Down
48 changes: 24 additions & 24 deletions test/e2e/config/docker.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -35,26 +35,26 @@ providers:
- name: cluster-api
type: CoreProvider
versions:
- name: v1.0.5 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.0.5/core-components.yaml"
- name: "{go://sigs.k8s.io/cluster-api@v1.0}" # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/{go://sigs.k8s.io/cluster-api@v1.0}/core-components.yaml"
type: "url"
contract: v1beta1
replacements:
- old: --metrics-addr=127.0.0.1:8080
new: --metrics-addr=:8080
files:
- sourcePath: "../data/shared/v1.0/metadata.yaml"
- name: v1.4.5 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.4.5/core-components.yaml"
- name: "{go://sigs.k8s.io/cluster-api@v1.4}" # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/{go://sigs.k8s.io/cluster-api@v1.4}/core-components.yaml"
type: "url"
contract: v1beta1
replacements:
- old: --metrics-addr=127.0.0.1:8080
new: --metrics-addr=:8080
files:
- sourcePath: "../data/shared/v1.4/metadata.yaml"
- name: v1.5.0 # latest published release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.5.0/core-components.yaml"
- name: "{go://sigs.k8s.io/cluster-api@v1.5}" # latest published release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/{go://sigs.k8s.io/cluster-api@v1.5}/core-components.yaml"
type: "url"
contract: v1beta1
replacements:
Expand All @@ -73,26 +73,26 @@ providers:
- name: kubeadm
type: BootstrapProvider
versions:
- name: v1.0.5 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.0.5/bootstrap-components.yaml"
- name: "{go://sigs.k8s.io/cluster-api@v1.0}" # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/{go://sigs.k8s.io/cluster-api@v1.0}/bootstrap-components.yaml"
type: "url"
contract: v1beta1
replacements:
- old: --metrics-addr=127.0.0.1:8080
new: --metrics-addr=:8080
files:
- sourcePath: "../data/shared/v1.0/metadata.yaml"
- name: v1.4.5 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.4.5/bootstrap-components.yaml"
- name: "{go://sigs.k8s.io/cluster-api@v1.4}" # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/{go://sigs.k8s.io/cluster-api@v1.4}/bootstrap-components.yaml"
type: "url"
contract: v1beta1
replacements:
- old: --metrics-addr=127.0.0.1:8080
new: --metrics-addr=:8080
files:
- sourcePath: "../data/shared/v1.4/metadata.yaml"
- name: v1.5.0 # latest published release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.5.0/bootstrap-components.yaml"
- name: "{go://sigs.k8s.io/cluster-api@v1.5}" # latest published release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/{go://sigs.k8s.io/cluster-api@v1.5}/bootstrap-components.yaml"
type: "url"
contract: v1beta1
replacements:
Expand All @@ -111,26 +111,26 @@ providers:
- name: kubeadm
type: ControlPlaneProvider
versions:
- name: v1.0.5 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.0.5/control-plane-components.yaml"
- name: "{go://sigs.k8s.io/cluster-api@v1.0}" # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/{go://sigs.k8s.io/cluster-api@v1.0}/control-plane-components.yaml"
type: "url"
contract: v1beta1
replacements:
- old: --metrics-addr=127.0.0.1:8080
new: --metrics-addr=:8080
files:
- sourcePath: "../data/shared/v1.0/metadata.yaml"
- name: v1.4.5 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.4.5/control-plane-components.yaml"
- name: "{go://sigs.k8s.io/cluster-api@v1.4}" # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/{go://sigs.k8s.io/cluster-api@v1.4}/control-plane-components.yaml"
type: "url"
contract: v1beta1
replacements:
- old: --metrics-addr=127.0.0.1:8080
new: --metrics-addr=:8080
files:
- sourcePath: "../data/shared/v1.4/metadata.yaml"
- name: v1.5.0 # latest published release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.5.0/control-plane-components.yaml"
- name: "{go://sigs.k8s.io/cluster-api@v1.5}" # latest published release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/{go://sigs.k8s.io/cluster-api@v1.5}/control-plane-components.yaml"
type: "url"
contract: v1beta1
replacements:
Expand All @@ -149,8 +149,8 @@ providers:
- name: docker
type: InfrastructureProvider
versions:
- name: v1.0.5 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.0.5/infrastructure-components-development.yaml"
- name: "{go://sigs.k8s.io/cluster-api@v1.0}" # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/{go://sigs.k8s.io/cluster-api@v1.0}/infrastructure-components-development.yaml"
type: "url"
contract: v1beta1
replacements:
Expand All @@ -159,8 +159,8 @@ providers:
files:
- sourcePath: "../data/shared/v1.0/metadata.yaml"
- sourcePath: "../data/infrastructure-docker/v1.0/cluster-template.yaml"
- name: v1.4.5 # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.4.5/infrastructure-components-development.yaml"
- name: "{go://sigs.k8s.io/cluster-api@v1.4}" # supported release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/{go://sigs.k8s.io/cluster-api@v1.4}/infrastructure-components-development.yaml"
type: "url"
contract: v1beta1
replacements:
Expand All @@ -171,8 +171,8 @@ providers:
- sourcePath: "../data/infrastructure-docker/v1.4/cluster-template.yaml"
- sourcePath: "../data/infrastructure-docker/v1.4/cluster-template-topology.yaml"
- sourcePath: "../data/infrastructure-docker/v1.4/clusterclass-quick-start.yaml"
- name: v1.5.0 # latest published release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/v1.5.0/infrastructure-components-development.yaml"
- name: "{go://sigs.k8s.io/cluster-api@v1.5}" # latest published release in the v1beta1 series; this is used for v1beta1 --> main clusterctl upgrades test only.
value: "https://github.com/kubernetes-sigs/cluster-api/releases/download/{go://sigs.k8s.io/cluster-api@v1.5}/infrastructure-components-development.yaml"
type: "url"
contract: v1beta1
replacements:
Expand Down
80 changes: 80 additions & 0 deletions test/framework/clusterctl/e2e_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import (
"strings"
"time"

"github.com/blang/semver/v4"
. "github.com/onsi/gomega"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/util/version"
Expand All @@ -37,6 +38,7 @@ import (

clusterctlv1 "sigs.k8s.io/cluster-api/cmd/clusterctl/api/v1alpha3"
clusterctlconfig "sigs.k8s.io/cluster-api/cmd/clusterctl/client/config"
"sigs.k8s.io/cluster-api/internal/goproxy"
"sigs.k8s.io/cluster-api/util"
)

Expand All @@ -57,6 +59,7 @@ func LoadE2EConfig(_ context.Context, input LoadE2EConfigInput) *E2EConfig {
config := &E2EConfig{}
Expect(yaml.Unmarshal(configData, config)).To(Succeed(), "Failed to convert the e2e test config file to yaml")

Expect(config.ResolveReleases()).To(Succeed(), "Failed to resolve release markers in e2e test config file")
config.Defaults()
config.AbsPaths(filepath.Dir(input.ConfigPath))

Expand Down Expand Up @@ -245,6 +248,83 @@ type Files struct {
TargetName string `json:"targetName,omitempty"`
}

// ResolveReleases converts release markers to release version.
func (c *E2EConfig) ResolveReleases() error {
scheme, host, err := goproxy.GetSchemeAndHost(os.Getenv("GOPROXY"))
if err != nil {
return err
}
if scheme == "" || host == "" {
return fmt.Errorf("releasemarker does not support disabling the go proxy: GOPROXY=%q", os.Getenv("GOPROXY"))
}
goproxyClient := goproxy.NewClient(scheme, host)
for i := range c.Providers {
provider := &c.Providers[i]
for j := range provider.Versions {
version := &provider.Versions[j]
if version.Type == "url" {
releaseMarker := strings.TrimLeft(strings.TrimRight(version.Name, "}"), "{")
if !strings.EqualFold(version.Name, releaseMarker) {
ver, err := resolveReleaseMarker(releaseMarker, goproxyClient)
if err != nil {
return fmt.Errorf("failed resolving release path %s with error: %v", version.Name, err)
}
ver = "v" + ver
version.Value = strings.Replace(version.Value, version.Name, ver, 1)
version.Name = ver
}
}
}
}
return nil
}

// resolveReleaseMarker resolves releaseMarker string to verion string e.g.
// - Resolves "go://sigs.k8s.io/cluster-api@v1.0" to the latest stable patch release of v1.0.
// - Resolves "go://sigs.k8s.io/cluster-api@latest-v1.0" to the latest patch release of v.1.0 including rc and pre releases.
func resolveReleaseMarker(releaseMarker string, goproxyClient *goproxy.Client) (string, error) {
parts := strings.Split(releaseMarker, ":")
if len(parts) <= 1 {
return "", errors.Errorf("Invalid release url")
}

gomoduleParts := strings.Split(parts[1], "@")
if len(gomoduleParts) < 2 {
return "", errors.Errorf("Invalid release url, go module or version missing")
}
gomodule := gomoduleParts[0]
version := strings.ReplaceAll(gomoduleParts[1], "v", "")
includePrereleases := false
if strings.HasPrefix(version, "latest-") {
includePrereleases = true
}
version = strings.TrimPrefix(version, "latest-")

minSemVersion, err := semver.Parse(version + ".0")
if err != nil {
return "", err
}
maxSemVersion := minSemVersion
maxSemVersion.Minor++

parsedTags, err := goproxyClient.GetVersions(context.Background(), gomodule)

if err != nil {
return "", err
}

var picked semver.Version
for i, tag := range parsedTags {
if !includePrereleases && len(tag.Pre) > 0 {
continue
}
if tag.LT(maxSemVersion) && tag.Minor <= minSemVersion.Minor {
picked = parsedTags[i]
}
}
return picked.String(), nil
}

// Defaults assigns default values to the object. More specifically:
// - ManagementClusterName gets a default name if empty.
// - Providers version gets type KustomizeSource if not otherwise specified.
Expand Down
111 changes: 111 additions & 0 deletions test/framework/clusterctl/e2e_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
Copyright 2021 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package clusterctl

import (
"fmt"
"net/http"
"net/http/httptest"
"net/url"
"testing"

. "github.com/onsi/gomega"
"sigs.k8s.io/cluster-api/internal/goproxy"
)

func Test_resolveReleaseMarker(t *testing.T) {

clientGoproxy, muxGoproxy, teardownGoproxy := newFakeGoproxy()
defer teardownGoproxy()

// setup an handler with fake releases
muxGoproxy.HandleFunc("/github.com/o/r1/@v/list", func(w http.ResponseWriter, r *http.Request) {
testMethod(t, r, "GET")
fmt.Fprint(w, "v1.2.0\n")
fmt.Fprint(w, "v1.2.1-rc.0\n")

})
tests := []struct {
name string
releaseMarker string
want string
wantErr bool
}{
{
"Invalid url",
"github.com/o/doesntexist",
"",
true,
},
{
"Get stable release",
//"go://sigs.k8s.io/cluster-api@v1.0",
"go://github.com/o/r1@v1.2",
"1.2.0",
false,
},
{
"Get latest release",
//"go://sigs.k8s.io/cluster-api@v1.0",
"go://github.com/o/r1@latest-v1.2",
"1.2.1-rc.0",
false,
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
g := NewWithT(t)

got, err := resolveReleaseMarker(tt.releaseMarker, clientGoproxy)
if tt.wantErr {
g.Expect(err).To(HaveOccurred())
return
}
g.Expect(err).ToNot(HaveOccurred())

g.Expect(got).To(BeEquivalentTo(tt.want))
})
}

}

func testMethod(t *testing.T, r *http.Request, want string) {
t.Helper()

if got := r.Method; got != want {
t.Errorf("Request method: %v, want %v", got, want)
}
}

// newFakeGoproxy sets up a test HTTP server along with a github.Client that is
// configured to talk to that test server. Tests should register handlers on
// mux which provide mock responses for the API method being tested.
func newFakeGoproxy() (client *goproxy.Client, mux *http.ServeMux, teardown func()) {
// mux is the HTTP request multiplexer used with the test server.
mux = http.NewServeMux()

apiHandler := http.NewServeMux()
apiHandler.Handle("/", mux)

// server is a test HTTP server used to provide mock API responses.
server := httptest.NewServer(apiHandler)

// client is the GitHub client being tested and is configured to use test server.
url, _ := url.Parse(server.URL + "/")
return goproxy.NewClient(url.Scheme, url.Host), mux, server.Close
}

0 comments on commit 4ac1964

Please sign in to comment.