Skip to content

Commit 2334927

Browse files
furkatgofurov7alexander-demicevsalasberryfin
committed
Update chart upgrade suite for system chart controller migration
This commit refactors and updates the chart-upgrade test suite as part of the system chart controller migration, and includes several related fixes and improvements: - Re-structure chart-upgrade Ginkgo setup - Use preloaded images for chart-upgrade tests instead of pulling from GHCR - Fixes ClusterctlConfig for CAPD registry override - chart-upgrade tests cluster provisioning using Kubernetes v1.33 Signed-off-by: Furkat Gofurov <[email protected]> Co-authored-by: Alexandr Demicev <[email protected]> Co-authored-by: Carlos Salas <[email protected]>
1 parent ef284d1 commit 2334927

File tree

11 files changed

+725
-260
lines changed

11 files changed

+725
-260
lines changed

scripts/build-local-rancher-charts.sh

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,34 @@ RANCHER_CHART_DEV_VERSION=${RANCHER_CHART_DEV_VERSION}
2121
RANCHER_CHARTS_BASE_BRANCH=${RANCHER_CHARTS_BASE_BRANCH}
2222
CHART_RELEASE_DIR=${CHART_RELEASE_DIR}
2323
HELM=${HELM}
24+
# Optional: Override image repository and tag in the chart (useful for e2e tests with preloaded images)
25+
TURTLES_IMAGE_OVERRIDE_REPO=${TURTLES_IMAGE_OVERRIDE_REPO:-}
26+
TURTLES_IMAGE_OVERRIDE_TAG=${TURTLES_IMAGE_OVERRIDE_TAG:-}
2427

2528
# Cleanup
2629
rm -rf $RANCHER_CHARTS_REPO_DIR
2730
mkdir -p $RANCHER_CHARTS_REPO_DIR
2831
# Build and copy Turtles chart into Rancher Charts local repo
29-
git clone -b $RANCHER_CHARTS_BASE_BRANCH git@github.com:rancher/charts.git $RANCHER_CHARTS_REPO_DIR
32+
git clone -b $RANCHER_CHARTS_BASE_BRANCH https://github.com/rancher/charts.git $RANCHER_CHARTS_REPO_DIR
3033
mkdir -p $RANCHER_CHARTS_REPO_DIR/charts/rancher-turtles/$RANCHER_CHART_DEV_VERSION
3134
cp -r $CHART_RELEASE_DIR/* $RANCHER_CHARTS_REPO_DIR/charts/rancher-turtles/$RANCHER_CHART_DEV_VERSION
3235
# Populate Chart.yaml with correct version
3336
yq -i '.version = "'$RANCHER_CHART_DEV_VERSION'"' $RANCHER_CHARTS_REPO_DIR/charts/rancher-turtles/$RANCHER_CHART_DEV_VERSION/Chart.yaml
3437
yq -i '.appVersion = "dev"' $RANCHER_CHARTS_REPO_DIR/charts/rancher-turtles/$RANCHER_CHART_DEV_VERSION/Chart.yaml
3538
yq -i '.urls[0] += "assets/rancher-turtles/rancher-turtles-'$RANCHER_CHART_DEV_VERSION'.tgz"' $RANCHER_CHARTS_REPO_DIR/charts/rancher-turtles/$RANCHER_CHART_DEV_VERSION/Chart.yaml
39+
# Optionally override image repository and tag if environment variables are set (e.g., for e2e tests with preloaded images)
40+
if [ -n "$TURTLES_IMAGE_OVERRIDE_REPO" ] && [ -n "$TURTLES_IMAGE_OVERRIDE_TAG" ]; then
41+
yq -i '.image.repository = "'$TURTLES_IMAGE_OVERRIDE_REPO'"' $RANCHER_CHARTS_REPO_DIR/charts/rancher-turtles/$RANCHER_CHART_DEV_VERSION/values.yaml
42+
yq -i '.image.tag = "'$TURTLES_IMAGE_OVERRIDE_TAG'"' $RANCHER_CHARTS_REPO_DIR/charts/rancher-turtles/$RANCHER_CHART_DEV_VERSION/values.yaml
43+
fi
3644
# Populate release.yaml and index.yaml
3745
yq -i '.rancher-turtles += "'$RANCHER_CHART_DEV_VERSION'"' $RANCHER_CHARTS_REPO_DIR/release.yaml
3846
index_entry=$(yq -o=j -I=0 $RANCHER_CHARTS_REPO_DIR/charts/rancher-turtles/$RANCHER_CHART_DEV_VERSION/Chart.yaml)
3947
yq -i '.entries.rancher-turtles += '"$index_entry"'' $RANCHER_CHARTS_REPO_DIR/index.yaml
4048
# Package the chart
4149
$HELM package $RANCHER_CHARTS_REPO_DIR/charts/rancher-turtles/$RANCHER_CHART_DEV_VERSION --app-version=dev --version=$RANCHER_CHART_DEV_VERSION --destination=$RANCHER_CHARTS_REPO_DIR/assets/rancher-turtles
4250
# Commit all changes
51+
git -C $RANCHER_CHARTS_REPO_DIR config user.email "[email protected]"
52+
git -C $RANCHER_CHARTS_REPO_DIR config user.name "Rancher Turtles CI"
4353
git -C $RANCHER_CHARTS_REPO_DIR add .
4454
git -C $RANCHER_CHARTS_REPO_DIR commit -m "Added test chart $RANCHER_CHART_DEV_VERSION"

scripts/migrate-providers-ownership.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -113,4 +113,4 @@ for item in "${EXTRA_ADOPTS[@]}"; do
113113
adopt_capiprovider "$name" "$namespace"
114114
done
115115

116-
echo "Migration completed"
116+
echo "Migration completed"

test/e2e/const.go

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,10 +145,11 @@ var (
145145
)
146146

147147
const (
148-
RancherTurtlesNamespace = "rancher-turtles-system"
149-
RancherNamespace = "cattle-system"
150-
NginxIngressNamespace = "ingress-nginx"
151-
NginxIngressDeployment = "ingress-nginx-controller"
148+
RancherTurtlesNamespace = "rancher-turtles-system"
149+
NewRancherTurtlesNamespace = "cattle-turtles-system"
150+
RancherNamespace = "cattle-system"
151+
NginxIngressNamespace = "ingress-nginx"
152+
NginxIngressDeployment = "ingress-nginx-controller"
152153
)
153154

154155
type ManagementClusterEnvironmentType string

test/e2e/suites/chart-upgrade/chart_upgrade_test.go

Lines changed: 144 additions & 206 deletions
Large diffs are not rendered by default.

test/e2e/suites/chart-upgrade/suite_test.go

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,28 @@ var (
4545
// hostName is the host name for the Rancher Manager server.
4646
hostName string
4747

48+
// giteaResult stores the result of Gitea deployment
49+
giteaResult *testenv.DeployGiteaResult
50+
51+
// chartsResult stores the result of building and pushing charts to Gitea
52+
chartsResult *testenv.BuildAndPushRancherChartsToGiteaResult
53+
4854
ctx = context.Background()
4955

5056
setupClusterResult *testenv.SetupTestClusterResult
5157
bootstrapClusterProxy capiframework.ClusterProxy
5258
)
5359

60+
// setupData is the data structure shared between SynchronizedBeforeSuite parallel runs
61+
type setupData struct {
62+
e2e.Setup
63+
GitAddress string
64+
ChartRepoURL string
65+
ChartRepoHTTPURL string
66+
ChartBranch string
67+
ChartVersion string
68+
}
69+
5470
func TestE2E(t *testing.T) {
5571
RegisterFailHandler(Fail)
5672

@@ -64,8 +80,9 @@ var _ = SynchronizedBeforeSuite(
6480
e2eConfig := e2e.LoadE2EConfig()
6581
e2eConfig.ManagementClusterName = e2eConfig.ManagementClusterName + "-chart-upgrade"
6682
setupClusterResult = testenv.SetupTestCluster(ctx, testenv.SetupTestClusterInput{
67-
E2EConfig: e2eConfig,
68-
Scheme: e2e.InitScheme(),
83+
E2EConfig: e2eConfig,
84+
Scheme: e2e.InitScheme(),
85+
KubernetesVersion: "v1.33.0",
6986
})
7087

7188
testenv.RancherDeployIngress(ctx, testenv.RancherDeployIngressInput{
@@ -74,26 +91,57 @@ var _ = SynchronizedBeforeSuite(
7491
DefaultIngressClassPatch: e2e.IngressClassPatch,
7592
})
7693

77-
rancherHookResult := testenv.DeployRancher(ctx, testenv.DeployRancherInput{
94+
By("Deploying Gitea for chart repository")
95+
giteaResult = testenv.DeployGitea(ctx, testenv.DeployGiteaInput{
7896
BootstrapClusterProxy: setupClusterResult.BootstrapClusterProxy,
79-
RancherHost: hostName,
80-
RancherPatches: [][]byte{e2e.RancherSettingPatch},
97+
ValuesFile: e2e.GiteaValues,
98+
CustomIngressConfig: e2e.GiteaIngress,
99+
})
100+
101+
By("Building and pushing Rancher charts to Gitea for later upgrade")
102+
chartsResult = testenv.BuildAndPushRancherChartsToGitea(ctx, testenv.BuildAndPushRancherChartsToGiteaInput{
103+
BootstrapClusterProxy: setupClusterResult.BootstrapClusterProxy,
104+
RootDir: e2eConfig.GetVariableOrEmpty("ROOT_DIR"),
105+
RancherChartsRepoDir: e2eConfig.GetVariableOrEmpty(e2e.ArtifactsFolderVar) + "/rancher-charts",
106+
RancherChartsBaseBranch: "dev-v2.13",
107+
GiteaServerAddress: giteaResult.GitAddress,
108+
GiteaRepoName: "charts",
109+
// Use preloaded e2e image from kind cluster
110+
TurtlesImageRepo: "ghcr.io/rancher/turtles-e2e",
111+
TurtlesImageTag: "v0.0.1",
112+
// ChartVersion will be auto-populated from RANCHER_CHART_DEV_VERSION env var or Makefile default
81113
})
82114

83-
data, err := json.Marshal(e2e.Setup{
84-
ClusterName: setupClusterResult.ClusterName,
85-
KubeconfigPath: setupClusterResult.KubeconfigPath,
86-
RancherHostname: rancherHookResult.Hostname,
115+
data, err := json.Marshal(setupData{
116+
Setup: e2e.Setup{
117+
ClusterName: setupClusterResult.ClusterName,
118+
KubeconfigPath: setupClusterResult.KubeconfigPath,
119+
},
120+
GitAddress: giteaResult.GitAddress,
121+
ChartRepoURL: chartsResult.ChartRepoURL,
122+
ChartRepoHTTPURL: chartsResult.ChartRepoHTTPURL,
123+
ChartBranch: chartsResult.Branch,
124+
ChartVersion: chartsResult.ChartVersion,
87125
})
88126
Expect(err).ToNot(HaveOccurred())
89127
return data
90128
},
91129
func(sharedData []byte) {
92-
setup := e2e.Setup{}
130+
setup := setupData{}
93131
Expect(json.Unmarshal(sharedData, &setup)).To(Succeed())
94132

95133
e2eConfig = e2e.LoadE2EConfig()
96-
hostName = setup.RancherHostname
134+
135+
giteaResult = &testenv.DeployGiteaResult{
136+
GitAddress: setup.GitAddress,
137+
}
138+
139+
chartsResult = &testenv.BuildAndPushRancherChartsToGiteaResult{
140+
ChartRepoURL: setup.ChartRepoURL,
141+
ChartRepoHTTPURL: setup.ChartRepoHTTPURL,
142+
Branch: setup.ChartBranch,
143+
ChartVersion: setup.ChartVersion,
144+
}
97145

98146
bootstrapClusterProxy = capiframework.NewClusterProxy(setup.ClusterName, setup.KubeconfigPath, e2e.InitScheme(), capiframework.WithMachineLogCollector(capiframework.DockerLogCollector{}))
99147
Expect(bootstrapClusterProxy).ToNot(BeNil(), "cluster proxy should not be nil")
@@ -115,7 +163,8 @@ var _ = SynchronizedAfterSuite(
115163
return
116164
}
117165

118-
testenv.UninstallRancherTurtles(ctx, testenv.UninstallRancherTurtlesInput{
166+
By("Uninstalling Gitea")
167+
testenv.UninstallGitea(ctx, testenv.UninstallGiteaInput{
119168
BootstrapClusterProxy: setupClusterResult.BootstrapClusterProxy,
120169
})
121170

test/e2e/suites/import-gitops/suite_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,9 @@ var _ = SynchronizedBeforeSuite(
8080
})
8181

8282
testenv.DeployRancherTurtlesProviders(ctx, testenv.DeployRancherTurtlesProvidersInput{
83-
BootstrapClusterProxy: setupClusterResult.BootstrapClusterProxy,
83+
BootstrapClusterProxy: setupClusterResult.BootstrapClusterProxy,
84+
UseLegacyCAPINamespace: false,
85+
RancherTurtlesNamespace: e2e.RancherTurtlesNamespace,
8486
})
8587

8688
data, err := json.Marshal(e2e.Setup{

test/framework/git_helper.go

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import (
2727
. "github.com/onsi/gomega"
2828

2929
"github.com/go-git/go-git/v5"
30+
"github.com/go-git/go-git/v5/config"
3031
"github.com/go-git/go-git/v5/plumbing/object"
3132
"github.com/go-git/go-git/v5/plumbing/transport/http"
3233
)
@@ -145,6 +146,114 @@ func GitCommitAndPush(ctx context.Context, input GitCommitAndPushInput) {
145146
}, input.GitPushWait...).Should(Succeed(), "Failed to connect to workload cluster using CAPI kubeconfig")
146147
}
147148

149+
// GitSetRemoteInput is the input to GitSetRemote.
150+
type GitSetRemoteInput struct {
151+
// RepoLocation is the directory where the repository is located.
152+
RepoLocation string
153+
154+
// RemoteName is the name of the remote (e.g., "origin").
155+
RemoteName string `envDefault:"origin"`
156+
157+
// RemoteURL is the URL for the remote repository.
158+
RemoteURL string
159+
160+
// Username is the username for authentication (optional).
161+
Username string `env:"GITEA_USER_NAME"`
162+
163+
// Password is the password for authentication (optional).
164+
Password string `env:"GITEA_USER_PWD"`
165+
}
166+
167+
// GitSetRemote sets or updates the remote URL for a git repository.
168+
// If credentials are provided, they will be embedded in the URL.
169+
func GitSetRemote(ctx context.Context, input GitSetRemoteInput) {
170+
Expect(Parse(&input)).To(Succeed(), "Failed to parse environment variables")
171+
172+
Expect(ctx).NotTo(BeNil(), "ctx is required for GitSetRemote")
173+
Expect(input.RepoLocation).ToNot(BeEmpty(), "Invalid argument. input.RepoLocation can't be empty when calling GitSetRemote")
174+
Expect(input.RemoteName).ToNot(BeEmpty(), "Invalid argument. input.RemoteName can't be empty when calling GitSetRemote")
175+
Expect(input.RemoteURL).ToNot(BeEmpty(), "Invalid argument. input.RemoteURL can't be empty when calling GitSetRemote")
176+
177+
repo, err := git.PlainOpen(input.RepoLocation)
178+
Expect(err).ShouldNot(HaveOccurred(), "Failed opening the repo at %s", input.RepoLocation)
179+
180+
// Try to delete the remote if it exists
181+
_ = repo.DeleteRemote(input.RemoteName)
182+
183+
// Construct the remote URL with credentials if provided
184+
remoteURL := input.RemoteURL
185+
if input.Username != "" && input.Password != "" {
186+
// Parse URL to inject credentials
187+
if strings.HasPrefix(remoteURL, "http://") {
188+
remoteURL = fmt.Sprintf("http://%s:%s@%s", input.Username, input.Password, strings.TrimPrefix(remoteURL, "http://"))
189+
} else if strings.HasPrefix(remoteURL, "https://") {
190+
remoteURL = fmt.Sprintf("https://%s:%s@%s", input.Username, input.Password, strings.TrimPrefix(remoteURL, "https://"))
191+
}
192+
}
193+
194+
// Create the new remote
195+
_, err = repo.CreateRemote(&config.RemoteConfig{
196+
Name: input.RemoteName,
197+
URLs: []string{remoteURL},
198+
})
199+
Expect(err).ShouldNot(HaveOccurred(), "Failed creating remote %s with URL %s", input.RemoteName, input.RemoteURL)
200+
}
201+
202+
// GitPushInput is the input to GitPush.
203+
type GitPushInput struct {
204+
// RepoLocation is the directory where the repository is located.
205+
RepoLocation string
206+
207+
// RemoteName is the name of the remote to push to.
208+
RemoteName string `envDefault:"origin"`
209+
210+
// RefSpec is the refspec to push (e.g., "refs/heads/main:refs/heads/main").
211+
// If empty, the default git push behavior is used (push current branch to upstream).
212+
RefSpec string
213+
214+
// Username is the username for authentication (optional).
215+
Username string `env:"GITEA_USER_NAME"`
216+
217+
// Password is the password for authentication (optional).
218+
Password string `env:"GITEA_USER_PWD"`
219+
220+
// Force indicates whether to force push.
221+
Force bool
222+
}
223+
224+
// GitPush pushes changes to the remote repository.
225+
func GitPush(ctx context.Context, input GitPushInput) {
226+
Expect(Parse(&input)).To(Succeed(), "Failed to parse environment variables")
227+
228+
Expect(ctx).NotTo(BeNil(), "ctx is required for GitPush")
229+
Expect(input.RepoLocation).ToNot(BeEmpty(), "Invalid argument. input.RepoLocation can't be empty when calling GitPush")
230+
Expect(input.RemoteName).ToNot(BeEmpty(), "Invalid argument. input.RemoteName can't be empty when calling GitPush")
231+
232+
repo, err := git.PlainOpen(input.RepoLocation)
233+
Expect(err).ShouldNot(HaveOccurred(), "Failed opening the repo at %s", input.RepoLocation)
234+
235+
pushOptions := &git.PushOptions{
236+
RemoteName: input.RemoteName,
237+
Force: input.Force,
238+
}
239+
240+
// If a refspec is provided, use it. Otherwise, push will use the default behavior
241+
// (push current branch to upstream)
242+
if input.RefSpec != "" {
243+
pushOptions.RefSpecs = []config.RefSpec{config.RefSpec(input.RefSpec)}
244+
}
245+
246+
if input.Username != "" {
247+
pushOptions.Auth = &http.BasicAuth{
248+
Username: input.Username,
249+
Password: input.Password,
250+
}
251+
}
252+
253+
err = repo.Push(pushOptions)
254+
Expect(err).ShouldNot(HaveOccurred(), "Failed pushing to remote %s", input.RemoteName)
255+
}
256+
148257
// defaultToCurrentGitRepo retrieves the repository URL and the current branch
149258
func defaultToCurrentGitRepo(input *FleetCreateGitRepoInput) {
150259
if input.Repo != "" {

test/testenv/gitea.go

Lines changed: 19 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -259,33 +259,25 @@ func DeployGitea(ctx context.Context, input DeployGiteaInput) *DeployGiteaResult
259259
return result
260260
}
261261

262-
By("Waiting for Gitea endpoint to be available")
263-
url := fmt.Sprintf("%s/api/v1/version", result.GitAddress)
264-
Eventually(func() error {
265-
resp, err := http.Get(url)
266-
if err != nil {
267-
return err
268-
}
269-
defer resp.Body.Close()
270-
271-
if resp.StatusCode != http.StatusOK {
272-
return fmt.Errorf("expected status OK, got %v", resp.Status)
273-
}
274-
275-
return nil
276-
}, input.ServiceWaitInterval...).Should(Succeed())
277-
278-
By("Creating gitea secret")
279-
turtlesframework.CreateSecret(ctx, turtlesframework.CreateSecretInput{
280-
Creator: input.BootstrapClusterProxy.GetClient(),
281-
Name: input.AuthSecretName,
282-
Namespace: turtlesframework.FleetLocalNamespace,
283-
Type: corev1.SecretTypeBasicAuth,
284-
Data: map[string]string{
285-
"username": input.Username,
286-
"password": input.Password,
287-
},
288-
})
262+
// Only check HTTP endpoint for environments where it's accessible from the test runner
263+
// In isolated-kind, the service uses NodePort but is only accessible from within Docker network
264+
if input.EnvironmentType != e2e.ManagementClusterEnvironmentIsolatedKind {
265+
By("Waiting for Gitea endpoint to be available")
266+
url := fmt.Sprintf("%s/api/v1/version", result.GitAddress)
267+
Eventually(func() error {
268+
resp, err := http.Get(url)
269+
if err != nil {
270+
return err
271+
}
272+
defer resp.Body.Close()
273+
274+
if resp.StatusCode != http.StatusOK {
275+
return fmt.Errorf("expected status OK, got %v", resp.Status)
276+
}
277+
278+
return nil
279+
}, input.ServiceWaitInterval...).Should(Succeed())
280+
}
289281

290282
return result
291283
}

0 commit comments

Comments
 (0)