Repository: rancher/fleet
Pull request #2882 (2024-09-19 14:17:13)

Copy SafeConcat from wrangler
Extend our existing name package. 


Patch:
diff --git a/dev/setup-rancher-clusters b/dev/setup-rancher-clusters
index 71df345c..d9d24e76 100755
--- a/dev/setup-rancher-clusters
+++ b/dev/setup-rancher-clusters
@@ -1,6 +1,6 @@
 #!/bin/bash
 
-set -euxo pipefail
+set -eux
 
 if [ ! -d ./.github/scripts ]; then
   echo "please change the current directory to the fleet repo checkout"
@@ -12,13 +12,10 @@ upstream_ctx="${FLEET_E2E_CLUSTER-k3d-upstream}"
 downstream_ctx="${FLEET_E2E_CLUSTER_DOWNSTREAM-k3d-downstream}"
 rancherpassword="${RANCHER_PASSWORD-rancherpassword}"
 
-# helm repo add rancher-latest https://releases.rancher.com/server-charts/latest
-# helm repo update rancher-latest
-helm repo update
-
 version="${1-}"
+channel="${2-latest}" # latest or alpha
 if [ -z "$version" ]; then
-  version=$(curl -s https://api.github.com/repos/rancher/rancher/releases | jq -r "sort_by(.tag_name) | [ .[] | select(.draft | not) ] | .[-1].tag_name")
+  version=$(curl -SsLf "https://releases.rancher.com/server-charts/$channel/index.yaml" | yq -r '.entries | to_entries | .[].value[] | .version' | sort -V | tail -1)
 fi
 
 kubectl config use-context "$upstream_ctx"
@@ -27,13 +24,14 @@ kubectl apply -f https://github.com/jetstack/cert-manager/releases/download/v1.5
 kubectl wait --for=condition=Available deployment --timeout=2m -n cert-manager --all
 
 # set CATTLE_SERVER_URL and CATTLE_BOOTSTRAP_PASSWORD to get rancher out of "bootstrap" mode
-helm upgrade rancher rancher-latest/rancher --version "$version" \
+helm upgrade rancher "https://releases.rancher.com/server-charts/${channel}/rancher-${version#v}.tgz" \
   --devel \
   --install --wait \
   --create-namespace \
   --namespace cattle-system \
   --set replicas=1 \
   --set hostname="$public_hostname" \
+  --set agentTLSMode=system-store \
   --set bootstrapPassword=admin \
   --set "extraEnv[0].name=CATTLE_SERVER_URL" \
   --set "extraEnv[0].value=https://$public_hostname" \
diff --git a/internal/bundlereader/read.go b/internal/bundlereader/read.go
index ae40cbab..1b669473 100644
--- a/internal/bundlereader/read.go
+++ b/internal/bundlereader/read.go
@@ -14,10 +14,9 @@ import (
 	"strconv"
 
 	"github.com/rancher/fleet/internal/fleetyaml"
+	"github.com/rancher/fleet/internal/names"
 	fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
 
-	name1 "github.com/rancher/wrangler/v3/pkg/name"
-
 	"github.com/sirupsen/logrus"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	"sigs.k8s.io/yaml"
@@ -163,7 +162,7 @@ func read(ctx context.Context, name, baseDir string, bundleSpecReader io.Reader,
 
 		scans = append(scans, &fleet.ImageScan{
 			ObjectMeta: metav1.ObjectMeta{
-				Name: name1.SafeConcatName("imagescan", name, strconv.Itoa(i)),
+				Name: names.SafeConcatName("imagescan", name, strconv.Itoa(i)),
 			},
 			Spec: scan.ImageScanSpec,
 		})
diff --git a/internal/cmd/agent/deployer/applied/applied.go b/internal/cmd/agent/deployer/applied/applied.go
index c727092f..43f2e7ea 100644
--- a/internal/cmd/agent/deployer/applied/applied.go
+++ b/internal/cmd/agent/deployer/applied/applied.go
@@ -4,9 +4,9 @@ import (
 	"strings"
 
 	"github.com/rancher/fleet/internal/config"
+	"github.com/rancher/fleet/internal/names"
 
 	"github.com/rancher/wrangler/v3/pkg/apply"
-	"github.com/rancher/wrangler/v3/pkg/name"
 
 	"k8s.io/apimachinery/pkg/runtime"
 	"k8s.io/client-go/rest"
@@ -23,12 +23,12 @@ func GetSetID(bundleID, labelPrefix, labelSuffix string) string {
 		if labelSuffix == "" {
 			return config.AgentBootstrapConfigName
 		}
-		return name.SafeConcatName(config.AgentBootstrapConfigName, labelSuffix)
+		return names.SafeConcatName(config.AgentBootstrapConfigName, labelSuffix)
 	}
 	if labelSuffix != "" {
-		return name.SafeConcatName(labelPrefix, bundleID, labelSuffix)
+		return names.SafeConcatName(labelPrefix, bundleID, labelSuffix)
 	}
-	return name.SafeConcatName(labelPrefix, bundleID)
+	return names.SafeConcatName(labelPrefix, bundleID)
 }
 
 // GetLabelsAndAnnotations returns the labels and annotations, like
diff --git a/internal/cmd/cli/apply/apply.go b/internal/cmd/cli/apply/apply.go
index 14ce2e09..5c55c600 100644
--- a/internal/cmd/cli/apply/apply.go
+++ b/internal/cmd/cli/apply/apply.go
@@ -18,7 +18,7 @@ import (
 	"github.com/rancher/fleet/internal/client"
 	"github.com/rancher/fleet/internal/fleetyaml"
 	"github.com/rancher/fleet/internal/manifest"
-	name2 "github.com/rancher/fleet/internal/name"
+	"github.com/rancher/fleet/internal/names"
 	"github.com/rancher/fleet/internal/ociwrapper"
 	fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
 
@@ -216,7 +216,7 @@ func Dir(ctx context.Context, client Getter, name, baseDir string, opts *Options
 	// The bundleID is a valid helm release name, it's used as a default if a release name is not specified in helm options.
 	// It's also used to create the bundle name.
 	bundleID := filepath.Join(name, baseDir)
-	bundleID = name2.HelmReleaseName(bundleID)
+	bundleID = names.HelmReleaseName(bundleID)
 
 	bundle, scans, err := readBundle(ctx, bundleID, baseDir, opts)
 	if err != nil {
diff --git a/internal/cmd/controller/agentmanagement/agent/manifest.go b/internal/cmd/controller/agentmanagement/agent/manifest.go
index 96dc99f5..766c66b8 100644
--- a/internal/cmd/controller/agentmanagement/agent/manifest.go
+++ b/internal/cmd/controller/agentmanagement/agent/manifest.go
@@ -8,7 +8,7 @@ import (
 	"github.com/sirupsen/logrus"
 
 	"github.com/rancher/fleet/internal/config"
-	"github.com/rancher/wrangler/v3/pkg/name"
+	"github.com/rancher/fleet/internal/names"
 
 	appsv1 "k8s.io/api/apps/v1"
 	corev1 "k8s.io/api/core/v1"
@@ -61,7 +61,7 @@ func Manifest(namespace string, agentScope string, opts ManifestOptions) []runti
 	clusterRole := []runtime.Object{
 		&rbacv1.ClusterRole{
 			ObjectMeta: metav1.ObjectMeta{
-				Name: name.SafeConcatName(admin.Namespace, admin.Name, "role"),
+				Name: names.SafeConcatName(admin.Namespace, admin.Name, "role"),
 			},
 			Rules: []rbacv1.PolicyRule{
 				{
@@ -77,7 +77,7 @@ func Manifest(namespace string, agentScope string, opts ManifestOptions) []runti
 		},
 		&rbacv1.ClusterRoleBinding{
 			ObjectMeta: metav1.ObjectMeta{
-				Name: name.SafeConcatName(admin.Namespace, admin.Name, "role", "binding"),
+				Name: names.SafeConcatName(admin.Namespace, admin.Name, "role", "binding"),
 			},
 			Subjects: []rbacv1.Subject{
 				{
@@ -89,7 +89,7 @@ func Manifest(namespace string, agentScope string, opts ManifestOptions) []runti
 			RoleRef: rbacv1.RoleRef{
 				APIGroup: rbacv1.GroupName,
 				Kind:     "ClusterRole",
-				Name:     name.SafeConcatName(admin.Namespace, admin.Name, "role"),
+				Name:     names.SafeConcatName(admin.Namespace, admin.Name, "role"),
 			},
 		},
 	}
diff --git a/internal/cmd/controller/agentmanagement/controllers/cluster/controller.go b/internal/cmd/controller/agentmanagement/controllers/cluster/controller.go
index d8ccba36..b395c26c 100644
--- a/internal/cmd/controller/agentmanagement/controllers/cluster/controller.go
+++ b/internal/cmd/controller/agentmanagement/controllers/cluster/controller.go
@@ -6,13 +6,12 @@ import (
 
 	"github.com/sirupsen/logrus"
 
-	fname "github.com/rancher/fleet/internal/name"
+	"github.com/rancher/fleet/internal/names"
 	fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
 	fleetcontrollers "github.com/rancher/fleet/pkg/generated/controllers/fleet.cattle.io/v1alpha1"
 
 	corecontrollers "github.com/rancher/wrangler/v3/pkg/generated/controllers/core/v1"
 	"github.com/rancher/wrangler/v3/pkg/kv"
-	"github.com/rancher/wrangler/v3/pkg/name"
 	"github.com/rancher/wrangler/v3/pkg/relatedresource"
 
 	v1 "k8s.io/api/core/v1"
@@ -100,10 +99,10 @@ func (h *handler) findClusters(namespaces corecontrollers.NamespaceCache) relate
 // for a given cluster name, e.g.:
 // "cluster-fleet-local-cluster-294db1acfa77-d9ccf852678f"
 func clusterNamespace(clusterNamespace, clusterName string) string {
-	return name.SafeConcatName("cluster",
+	return names.SafeConcatName("cluster",
 		clusterNamespace,
 		clusterName,
-		fname.KeyHash(clusterNamespace+"::"+clusterName))
+		names.KeyHash(clusterNamespace+"::"+clusterName))
 }
 
 func (h *handler) OnClusterChanged(cluster *fleet.Cluster, status fleet.ClusterStatus) (fleet.ClusterStatus, error) {
diff --git a/internal/cmd/controller/agentmanagement/controllers/cluster/import.go b/internal/cmd/controller/agentmanagement/controllers/cluster/import.go
index 1df456a6..9e2201b2 100644
--- a/internal/cmd/controller/agentmanagement/controllers/cluster/import.go
+++ b/internal/cmd/controller/agentmanagement/controllers/cluster/import.go
@@ -18,13 +18,13 @@ import (
 	"github.com/rancher/fleet/internal/cmd/controller/agentmanagement/controllers/manageagent"
 	fleetns "github.com/rancher/fleet/internal/cmd/controller/namespace"
 	"github.com/rancher/fleet/internal/config"
+	"github.com/rancher/fleet/internal/names"
 	fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
 	"github.com/rancher/fleet/pkg/durations"
 	fleetcontrollers "github.com/rancher/fleet/pkg/generated/controllers/fleet.cattle.io/v1alpha1"
 
 	"github.com/rancher/wrangler/v3/pkg/apply"
 	corecontrollers "github.com/rancher/wrangler/v3/pkg/generated/controllers/core/v1"
-	"github.com/rancher/wrangler/v3/pkg/name"
 	"github.com/rancher/wrangler/v3/pkg/randomtoken"
 	"github.com/rancher/wrangler/v3/pkg/yaml"
 
@@ -179,7 +179,7 @@ func (i *importHandler) OnChange(key string, cluster *fleet.Cluster) (_ *fleet.C
 }
 
 func (i *importHandler) deleteOldAgentBundle(cluster *fleet.Cluster) error {
-	if err := i.bundleClient.Delete(cluster.Namespace, name.SafeConcatName(manageagent.AgentBundleName, cluster.Name), nil); err != nil {
+	if err := i.bundleClient.Delete(cluster.Namespace, names.SafeConcatName(manageagent.AgentBundleName, cluster.Name), nil); err != nil {
 		return err
 	}
 	i.namespaceController.Enqueue(cluster.Namespace)
@@ -271,7 +271,7 @@ func (i *importHandler) importCluster(cluster *fleet.Cluster, status fleet.Clust
 	setID := applied.GetSetID(config.AgentBootstrapConfigName, "", cluster.Spec.AgentNamespace)
 	apply = apply.WithDynamicLookup().WithSetID(setID).WithNoDeleteGVK(fleetns.GVK())
 
-	tokenName := name.SafeConcatName(ImportTokenPrefix + cluster.Name)
+	tokenName := names.SafeConcatName(ImportTokenPrefix + cluster.Name)
 	token, err := i.tokens.Get(cluster.Namespace, tokenName)
 	if err != nil {
 		// ignore error
diff --git a/internal/cmd/controller/agentmanagement/controllers/clusterregistration/controller.go b/internal/cmd/controller/agentmanagement/controllers/clusterregistration/controller.go
index 9ad062d8..29955336 100644
--- a/internal/cmd/controller/agentmanagement/controllers/clusterregistration/controller.go
+++ b/internal/cmd/controller/agentmanagement/controllers/clusterregistration/controller.go
@@ -14,7 +14,7 @@ import (
 	"github.com/rancher/fleet/internal/cmd/controller/agentmanagement/controllers/resources"
 	secretutil "github.com/rancher/fleet/internal/cmd/controller/agentmanagement/secret"
 	"github.com/rancher/fleet/internal/config"
-	fname "github.com/rancher/fleet/internal/name"
+	"github.com/rancher/fleet/internal/names"
 	"github.com/rancher/fleet/internal/registration"
 	fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
 	"github.com/rancher/fleet/pkg/durations"
@@ -24,7 +24,6 @@ import (
 	corecontrollers "github.com/rancher/wrangler/v3/pkg/generated/controllers/core/v1"
 	rbaccontrollers "github.com/rancher/wrangler/v3/pkg/generated/controllers/rbac/v1"
 	"github.com/rancher/wrangler/v3/pkg/generic"
-	"github.com/rancher/wrangler/v3/pkg/name"
 	"github.com/rancher/wrangler/v3/pkg/relatedresource"
 
 	v1 "k8s.io/api/core/v1"
@@ -198,7 +197,7 @@ func (h *handler) OnChange(request *fleet.ClusterRegistration, status fleet.Clus
 		}
 	}
 
-	saName := name.SafeConcatName(request.Name, string(request.UID))
+	saName := names.SafeConcatName(request.Name, string(request.UID))
 	sa, err := h.serviceAccountCache.Get(cluster.Status.Namespace, saName)
 	if err != nil && apierrors.IsNotFound(err) {
 		// create request service account if missing
@@ -312,7 +311,7 @@ func (h *handler) OnChange(request *fleet.ClusterRegistration, status fleet.Clus
 		// starts
 		&rbacv1.ClusterRoleBinding{
 			ObjectMeta: metav1.ObjectMeta{
-				Name: name.SafeConcatName(request.Name, "content"),
+				Name: names.SafeConcatName(request.Name, "content"),
 				Labels: map[string]string{
 					fleet.ManagedLabel: "true",
 				},
@@ -349,7 +348,7 @@ func (h *handler) createOrGetCluster(request *fleet.ClusterRegistration) (*fleet
 		return nil, err
 	}
 
-	clusterName := name.SafeConcatName("cluster", fname.KeyHash(request.Spec.ClientID))
+	clusterName := names.SafeConcatName("cluster", names.KeyHash(request.Spec.ClientID))
 	if cluster, err := h.clusterCache.Get(request.Namespace, clusterName); !apierrors.IsNotFound(err) {
 		if cluster.Spec.ClientID != request.Spec.ClientID {
 			// This would happen with a hash collision
diff --git a/internal/cmd/controller/agentmanagement/controllers/clusterregistrationtoken/handler.go b/internal/cmd/controller/agentmanagement/controllers/clusterregistrationtoken/handler.go
index 2108a0d0..d62b1fe0 100644
--- a/internal/cmd/controller/agentmanagement/controllers/clusterregistrationtoken/handler.go
+++ b/internal/cmd/controller/agentmanagement/controllers/clusterregistrationtoken/handler.go
@@ -11,12 +11,12 @@ import (
 
 	secretutil "github.com/rancher/fleet/internal/cmd/controller/agentmanagement/secret"
 	"github.com/rancher/fleet/internal/config"
+	"github.com/rancher/fleet/internal/names"
 	fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
 	fleetcontrollers "github.com/rancher/fleet/pkg/generated/controllers/fleet.cattle.io/v1alpha1"
 
 	"github.com/rancher/wrangler/v3/pkg/apply"
 	corecontrollers "github.com/rancher/wrangler/v3/pkg/generated/controllers/core/v1"
-	"github.com/rancher/wrangler/v3/pkg/name"
 	"github.com/rancher/wrangler/v3/pkg/relatedresource"
 
 	corev1 "k8s.io/api/core/v1"
@@ -75,7 +75,7 @@ func (h *handler) OnChange(token *fleet.ClusterRegistrationToken, status fleet.C
 	logrus.Debugf("Cluster registration token '%s/%s', creating import service account, roles and secret", token.Namespace, token.Name)
 
 	var (
-		saName  = name.SafeConcatName(token.Name, string(token.UID))
+		saName  = names.SafeConcatName(token.Name, string(token.UID))
 		secrets []runtime.Object
 	)
 	status.SecretName = ""
@@ -144,7 +144,7 @@ func (h *handler) OnChange(token *fleet.ClusterRegistrationToken, status fleet.C
 		},
 		&rbacv1.Role{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:      name.SafeConcatName(saName, "role"),
+				Name:      names.SafeConcatName(saName, "role"),
 				Namespace: token.Namespace,
 				Labels: map[string]string{
 					fleet.ManagedLabel: "true",
@@ -160,7 +160,7 @@ func (h *handler) OnChange(token *fleet.ClusterRegistrationToken, status fleet.C
 		},
 		&rbacv1.RoleBinding{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:      name.SafeConcatName(saName, "to", "role"),
+				Name:      names.SafeConcatName(saName, "to", "role"),
 				Namespace: token.Namespace,
 				Labels: map[string]string{
 					fleet.ManagedLabel: "true",
@@ -176,12 +176,12 @@ func (h *handler) OnChange(token *fleet.ClusterRegistrationToken, status fleet.C
 			RoleRef: rbacv1.RoleRef{
 				APIGroup: rbacv1.GroupName,
 				Kind:     "Role",
-				Name:     name.SafeConcatName(saName, "role"),
+				Name:     names.SafeConcatName(saName, "role"),
 			},
 		},
 		&rbacv1.Role{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:      name.SafeConcatName(saName, "creds"),
+				Name:      names.SafeConcatName(saName, "creds"),
 				Namespace: h.systemRegistrationNamespace,
 			},
 			Rules: []rbacv1.PolicyRule{
@@ -194,7 +194,7 @@ func (h *handler) OnChange(token *fleet.ClusterRegistrationToken, status fleet.C
 		},
 		&rbacv1.RoleBinding{
 			ObjectMeta: metav1.ObjectMeta{
-				Name:      name.SafeConcatName(saName, "creds"),
+				Name:      names.SafeConcatName(saName, "creds"),
 				Namespace: h.systemRegistrationNamespace,
 			},
 			Subjects: []rbacv1.Subject{
@@ -207,7 +207,7 @@ func (h *handler) OnChange(token *fleet.ClusterRegistrationToken, status fleet.C
 			RoleRef: rbacv1.RoleRef{
 				APIGroup: rbacv1.GroupName,
 				Kind:     "Role",
-				Name:     name.SafeConcatName(saName, "creds"),
+				Name:     names.SafeConcatName(saName, "creds"),
 			},
 		},
 	}, secrets...), status, nil
diff --git a/internal/cmd/controller/agentmanagement/controllers/manageagent/manageagent.go b/internal/cmd/controller/agentmanagement/controllers/manageagent/manageagent.go
index e6c3b838..b89d1622 100644
--- a/internal/cmd/controller/agentmanagement/controllers/manageagent/manageagent.go
+++ b/internal/cmd/controller/agentmanagement/controllers/manageagent/manageagent.go
@@ -16,12 +16,12 @@ import (
 
 	"github.com/rancher/fleet/internal/cmd/controller/agentmanagement/agent"
 	"github.com/rancher/fleet/internal/config"
+	"github.com/rancher/fleet/internal/names"
 	fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
 	fleetcontrollers "github.com/rancher/fleet/pkg/generated/controllers/fleet.cattle.io/v1alpha1"
 
 	"github.com/rancher/wrangler/v3/pkg/apply"
 	corecontrollers "github.com/rancher/wrangler/v3/pkg/generated/controllers/core/v1"
-	"github.com/rancher/wrangler/v3/pkg/name"
 	"github.com/rancher/wrangler/v3/pkg/relatedresource"
 	"github.com/rancher/wrangler/v3/pkg/yaml"
 
@@ -202,7 +202,7 @@ func (h *handler) updateClusterStatus(cluster *fleet.Cluster, status fleet.Clust
 
 func (h *handler) resolveNS(namespace, _ string, obj runtime.Object) ([]relatedresource.Key, error) {
 	if cluster, ok := obj.(*fleet.Cluster); ok {
-		if _, err := h.bundleCache.Get(namespace, name.SafeConcatName(AgentBundleName, cluster.Name)); err != nil {
+		if _, err := h.bundleCache.Get(namespace, names.SafeConcatName(AgentBundleName, cluster.Name)); err != nil {
 			return []relatedresource.Key{{Name: namespace}}, nil
 		}
 	}
@@ -280,7 +280,7 @@ func (h *handler) newAgentBundle(ns string, cluster *fleet.Cluster) (runtime.Obj
 
 	return &fleet.Bundle{
 		ObjectMeta: metav1.ObjectMeta{
-			Name:      name.SafeConcatName(AgentBundleName, cluster.Name),
+			Name:      names.SafeConcatName(AgentBundleName, cluster.Name),
 			Namespace: ns,
 		},
 		Spec: fleet.BundleSpec{
diff --git a/internal/cmd/controller/gitops/reconciler/gitjob_controller.go b/internal/cmd/controller/gitops/reconciler/gitjob_controller.go
index 773e1b13..54709c3f 100644
--- a/internal/cmd/controller/gitops/reconciler/gitjob_controller.go
+++ b/internal/cmd/controller/gitops/reconciler/gitjob_controller.go
@@ -17,13 +17,13 @@ import (
 	"github.com/rancher/fleet/internal/cmd/controller/grutil"
 	"github.com/rancher/fleet/internal/cmd/controller/imagescan"
 	"github.com/rancher/fleet/internal/metrics"
+	"github.com/rancher/fleet/internal/names"
 	"github.com/rancher/fleet/internal/ociwrapper"
 	v1alpha1 "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
 	fleetevent "github.com/rancher/fleet/pkg/event"
 	"github.com/rancher/fleet/pkg/sharding"
 
 	"github.com/rancher/wrangler/v3/pkg/condition"
-	"github.com/rancher/wrangler/v3/pkg/name"
 
 	batchv1 "k8s.io/api/batch/v1"
 	corev1 "k8s.io/api/core/v1"
@@ -351,7 +351,7 @@ func (r *GitJobReconciler) addGitRepoFinalizer(ctx context.Context, nsName types
 
 func (r *GitJobReconciler) createJobRBAC(ctx context.Context, gitrepo *v1alpha1.GitRepo) error {
 	// No update needed, values are the same. So we ignore AlreadyExists.
-	saName := name.SafeConcatName("git", gitrepo.Name)
+	saName := names.SafeConcatName("git", gitrepo.Name)
 	sa := grutil.NewServiceAccount(gitrepo.Namespace, saName)
 	if err := controllerutil.SetControllerReference(gitrepo, sa, r.Scheme); err != nil {
 		return err
@@ -487,7 +487,7 @@ func generationChanged(r *v1alpha1.GitRepo) bool {
 }
 
 func jobName(obj *v1alpha1.GitRepo) string {
-	return name.SafeConcatName(obj.Name, name.Hex(obj.Spec.Repo+obj.Status.Commit, 5))
+	return names.SafeConcatName(obj.Name, names.Hex(obj.Spec.Repo+obj.Status.Commit, 5))
 }
 
 func caBundleName(obj *v1alpha1.GitRepo) string {
@@ -644,7 +644,7 @@ func (r *GitJobReconciler) newJobSpec(ctx context.Context, gitrepo *v1alpha1.Git
 		}
 	}
 
-	saName := name.SafeConcatName("git", gitrepo.Name)
+	saName := names.SafeConcatName("git", gitrepo.Name)
 	logger := log.FromContext(ctx)
 	args, envs := argsAndEnvs(gitrepo, logger.V(1).Enabled())
 
diff --git a/internal/cmd/controller/grutil/targetsyaml.go b/internal/cmd/controller/grutil/targetsyaml.go
index bd11739a..894abd9d 100644
--- a/internal/cmd/controller/grutil/targetsyaml.go
+++ b/internal/cmd/controller/grutil/targetsyaml.go
@@ -3,11 +3,9 @@ package grutil
 import (
 	"encoding/json"
 
-	fname "github.com/rancher/fleet/internal/name"
+	"github.com/rancher/fleet/internal/names"
 	fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
 
-	"github.com/rancher/wrangler/v3/pkg/name"
-
 	corev1 "k8s.io/api/core/v1"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 )
@@ -33,10 +31,10 @@ func NewTargetsConfigMap(repo *fleet.GitRepo) (*corev1.ConfigMap, error) {
 		return nil, err
 	}
 
-	hash := fname.KeyHash(string(data))
+	hash := names.KeyHash(string(data))
 	return &corev1.ConfigMap{
 		ObjectMeta: metav1.ObjectMeta{
-			Name:      name.SafeConcatName(repo.Name, "config", hash),
+			Name:      names.SafeConcatName(repo.Name, "config", hash),
 			Namespace: repo.Namespace,
 		},
 		BinaryData: map[string][]byte{
diff --git a/internal/helmdeployer/deployer.go b/internal/helmdeployer/deployer.go
index 1ad85ca5..6a46990c 100644
--- a/internal/helmdeployer/deployer.go
+++ b/internal/helmdeployer/deployer.go
@@ -12,7 +12,7 @@ import (
 	"helm.sh/helm/v3/pkg/storage"
 	"helm.sh/helm/v3/pkg/storage/driver"
 
-	name2 "github.com/rancher/fleet/internal/name"
+	"github.com/rancher/fleet/internal/names"
 	fleet "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
 
 	"k8s.io/apimachinery/pkg/runtime"
@@ -119,7 +119,7 @@ func (h *Helm) getOpts(bundleID string, options fleet.BundleDeploymentOptions) (
 	// releaseName has a limit of 53 in helm https://github.com/helm/helm/blob/main/pkg/action/install.go#L58
 	// fleet apply already produces valid names, but we need to make sure
 	// that bundles from other sources are valid
-	return timeout, ns, name2.HelmReleaseName(bundleID)
+	return timeout, ns, names.HelmReleaseName(bundleID)
 }
 
 func (h *Helm) getCfg(ctx context.Context, namespace, serviceAccountName string) (action.Configuration, error) {
diff --git a/internal/name/keyhash.go b/internal/names/keyhash.go
similarity index 95%
rename from internal/name/keyhash.go
rename to internal/names/keyhash.go
index c6dfa6fc..2abac59f 100644
--- a/internal/name/keyhash.go
+++ b/internal/names/keyhash.go
@@ -1,4 +1,4 @@
-package name
+package names
 
 import (
 	"crypto/sha256"
diff --git a/internal/name/name.go b/internal/names/name.go
similarity index 96%
rename from internal/name/name.go
rename to internal/names/name.go
index 69cd248c..1c6bfc11 100644
--- a/internal/name/name.go
+++ b/internal/names/name.go
@@ -1,5 +1,5 @@
-// Package name provides functions for truncating and hashing strings and for generating valid k8s resource names.
-package name
+// Package names provides functions for truncating and hashing strings and for generating valid k8s resource names.
+package names
 
 import (
 	"crypto/md5" // nolint:gosec // Non-crypto use
diff --git a/internal/names/safeconcat.go b/internal/names/safeconcat.go
new file mode 100644
index 00000000..8b83386f
--- /dev/null
+++ b/internal/names/safeconcat.go
@@ -0,0 +1,25 @@
+package names
+
+import (
+	"crypto/sha256"
+	"encoding/hex"
+	"strings"
+)
+
+// SafeConcatName concatenates the given strings and ensures the returned name is under 64 characters
+// by cutting the string off at 57 characters and setting the last 6 with an encoded version of the concatenated string.
+func SafeConcatName(name ...string) string {
+	fullPath := strings.Join(name, "-")
+	if len(fullPath) < 64 {
+		return fullPath
+	}
+	digest := sha256.Sum256([]byte(fullPath))
+	// since we cut the string in the middle, the last char may not be compatible with what is expected in k8s
+	// we are checking and if necessary removing the last char
+	c := fullPath[56]
+	if 'a' <= c && c <= 'z' || '0' <= c && c <= '9' {
+		return fullPath[0:57] + "-" + hex.EncodeToString(digest[0:])[0:5]
+	}
+
+	return fullPath[0:56] + "-" + hex.EncodeToString(digest[0:])[0:6]
+}


Test patch:
diff --git a/.github/workflows/e2e-ci.yml b/.github/workflows/e2e-ci.yml
index 1748e0fb..e7695565 100644
--- a/.github/workflows/e2e-ci.yml
+++ b/.github/workflows/e2e-ci.yml
@@ -136,15 +136,6 @@ jobs:
           ginkgo --github-output --label-filter='oci-registry' e2e/single-cluster
 
           e2e/testenv/infra/infra teardown
-      -
-        name: Acceptance Tests for Examples
-        if: >
-          matrix.test_type.name == 'default' &&
-          github.event_name == 'schedule'
-        env:
-          FLEET_E2E_NS: fleet-local
-        run: |
-          ginkgo --github-output e2e/acceptance/single-cluster-examples
       -
         name: Fleet Tests Requiring Github Secrets
         # These tests can't run for PRs, because PRs don't have access to the secrets
diff --git a/e2e/testenv/fail.go b/e2e/testenv/fail.go
index 6b2e2b50..9050b4ae 100644
--- a/e2e/testenv/fail.go
+++ b/e2e/testenv/fail.go
@@ -24,14 +24,14 @@ func FailAndGather(message string, callerSkip ...int) {
 
 	ginkgo.GinkgoWriter.Printf("💬 Gathering cluster info for '%s' to '%s'...\n", ginkgo.CurrentSpecReport().FullText(), pwd)
 	cmd := exec.Command("crust-gather", "collect",
-		"--exclude-namespace=kube-system", "--exclude-kind=Lease", "--duration=5s",
-		"-f", path)
+		"--exclude-namespace=kube-system", "--exclude-kind=Lease", "--duration=10s",
+		"-verror", "-f", path)
 	cmd.Stdout = ginkgo.GinkgoWriter
 	cmd.Stderr = ginkgo.GinkgoWriter
-	err := cmd.Run()
-	if err != nil {
-		ginkgo.GinkgoWriter.Printf("⛔ failed to gather cluster info: %v", err)
-	}
+	// Outputting errors, but don't care about error code as crust-gather
+	// often runs into a "deadline" error. Data collection is successful
+	// nevertheless.
+	_ = cmd.Run()
 
 	ginkgo.Fail(message, callerSkip...)
 }
diff --git a/integrationtests/gitcloner/clone_test.go b/integrationtests/gitcloner/clone_test.go
index 5c91d220..0974840b 100644
--- a/integrationtests/gitcloner/clone_test.go
+++ b/integrationtests/gitcloner/clone_test.go
@@ -44,7 +44,8 @@ const (
 	gogsHTTPSPort = "3000"
 	gogsSSHPort   = "22"
 	testRepoName  = "test-repo"
-	timeout       = 120 * time.Second
+	timeout       = 240 * time.Second
+	interval      = 10 * time.Second
 )
 
 var (
@@ -370,7 +371,6 @@ func createGogsContainerWithHTTPS() (testcontainers.Container, error) {
 		ContainerRequest: req,
 		Started:          true,
 	})
-
 	if err != nil {
 		return nil, err
 	}
@@ -378,34 +378,34 @@ func createGogsContainerWithHTTPS() (testcontainers.Container, error) {
 	// create ca bundle and certs needed for https
 	_, _, err = container.Exec(context.Background(), []string{"./gogs", "cert", "-ca=true", "-duration=8760h0m0s", "-host=localhost"})
 	if err != nil {
-		return nil, err
+		return container, err
 	}
 	_, _, err = container.Exec(context.Background(), []string{"chown", "git:git", "cert.pem", "key.pem"})
 	if err != nil {
-		return nil, err
+		return container, err
 	}
 	caReader, err := container.CopyFileFromContainer(context.Background(), "/app/gogs/cert.pem")
 	if err != nil {
-		return nil, err
+		return container, err
 	}
 	gogsCABundle, err = io.ReadAll(caReader)
 	if err != nil {
-		return nil, err
+		return container, err
 	}
 
 	// restart gogs container to make sure https certs are picked
 	err = container.Stop(context.Background(), &[]time.Duration{timeout}[0])
 	if err != nil {
-		return nil, err
+		return container, err
 	}
 	err = container.Start(context.Background())
 	if err != nil {
-		return nil, err
+		return container, err
 	}
 
 	url, err := getHTTPSURL(context.Background(), container)
 	if err != nil {
-		return nil, err
+		return container, err
 	}
 
 	// create access token, we need to wait until the https server is available. We can't check this in testcontainers.WaitFor
@@ -417,9 +417,20 @@ func createGogsContainerWithHTTPS() (testcontainers.Container, error) {
 
 		// only continue if it's a TLS connection
 		addr := strings.Replace(url, "https://", "", 1)
-		_, err := tls.Dial("tcp", addr, conf)
-		if err != nil {
-			return err
+		if _, err := tls.Dial("tcp", addr, conf); err != nil {
+			GinkgoWriter.Printf("error dialing: %v", err)
+			orgErr := err
+
+			// debug the connection
+			conn, err := tls.Dial("tcp", addr, nil)
+			if err != nil {
+				GinkgoWriter.Printf("error dialing without tls: %v", err)
+				return orgErr
+			}
+			body, _ := io.ReadAll(conn)
+			GinkgoWriter.Printf("tcp connection response: %s", body)
+
+			return orgErr
 		}
 
 		tr := &http.Transport{TLSClientConfig: conf}
@@ -429,13 +440,14 @@ func createGogsContainerWithHTTPS() (testcontainers.Container, error) {
 			Name: "test",
 		})
 		if err != nil {
+			GinkgoWriter.Printf("error creating access token: %v", err)
 			return err
 		}
 		gogsClient = gogs.NewClient(url, token.Sha1)
 		gogsClient.SetHTTPClient(httpClient)
 
 		return nil
-	}, timeout, "10s").ShouldNot(HaveOccurred())
+	}, timeout, interval).ShouldNot(HaveOccurred())
 
 	return container, nil
 }
diff --git a/integrationtests/gitjob/controller/controller_test.go b/integrationtests/gitjob/controller/controller_test.go
index 470ee07d..8e63ca50 100644
--- a/integrationtests/gitjob/controller/controller_test.go
+++ b/integrationtests/gitjob/controller/controller_test.go
@@ -22,9 +22,9 @@ import (
 	"sigs.k8s.io/controller-runtime/pkg/client"
 
 	"github.com/rancher/wrangler/v3/pkg/genericcondition"
-	"github.com/rancher/wrangler/v3/pkg/name"
 
 	"github.com/rancher/fleet/integrationtests/utils"
+	"github.com/rancher/fleet/internal/names"
 	v1alpha1 "github.com/rancher/fleet/pkg/apis/fleet.cattle.io/v1alpha1"
 )
 
@@ -86,7 +86,7 @@ var _ = Describe("GitJob controller", func() {
 				if err != nil {
 					return err
 				}
-				jobName = name.SafeConcatName(gitRepoName, name.Hex(repo+commit, 5))
+				jobName = names.SafeConcatName(gitRepoName, names.Hex(repo+commit, 5))
 				return k8sClient.Get(ctx, types.NamespacedName{Name: jobName, Namespace: gitRepoNamespace}, &job)
 			}).Should(Not(HaveOccurred()))
 
@@ -101,7 +101,7 @@ var _ = Describe("GitJob controller", func() {
 
 			// it should create RBAC resources for that gitRepo
 			Eventually(func(g Gomega) {
-				saName := name.SafeConcatName("git", gitRepo.Name)
+				saName := names.SafeConcatName("git", gitRepo.Name)
 				ns := types.NamespacedName{Name: saName, Namespace: gitRepo.Namespace}
 
 				var sa corev1.ServiceAccount
@@ -316,7 +316,7 @@ var _ = Describe("GitJob controller", func() {
 				By("verifying that the job is deleted if Spec.Generation changed")
 				Expect(simulateIncreaseGitRepoGeneration(gitRepo)).ToNot(HaveOccurred())
 				Eventually(func() bool {
-					jobName = name.SafeConcatName(gitRepoName, name.Hex(repo+commit, 5))
+					jobName = names.SafeConcatName(gitRepoName, names.Hex(repo+commit, 5))
 					return errors.IsNotFound(k8sClient.Get(ctx, types.NamespacedName{Name: jobName, Namespace: gitRepoNamespace}, &job))
 				}).Should(BeTrue())
 			})
@@ -337,7 +337,7 @@ var _ = Describe("GitJob controller", func() {
 
 			By("creating a Job")
 			Eventually(func() error {
-				jobName := name.SafeConcatName(gitRepoName, name.Hex(repo+commit, 5))
+				jobName := names.SafeConcatName(gitRepoName, names.Hex(repo+commit, 5))
 				return k8sClient.Get(ctx, types.NamespacedName{Name: jobName, Namespace: gitRepoNamespace}, &job)
 			}).Should(Not(HaveOccurred()))
 		})
@@ -350,7 +350,7 @@ var _ = Describe("GitJob controller", func() {
 				const newCommit = "9ca3a0adbbba32"
 				expectedCommit = newCommit
 				Eventually(func() error {
-					jobName := name.SafeConcatName(gitRepoName, name.Hex(repo+newCommit, 5))
+					jobName := names.SafeConcatName(gitRepoName, names.Hex(repo+newCommit, 5))
 					return k8sClient.Get(ctx, types.NamespacedName{Name: jobName, Namespace: gitRepoNamespace}, &job)
 				}).Should(Not(HaveOccurred()))
 			})
@@ -370,7 +370,7 @@ var _ = Describe("GitJob controller", func() {
 			gitRepo = createGitRepo(gitRepoName)
 			Expect(k8sClient.Create(ctx, &gitRepo)).ToNot(HaveOccurred())
 			Eventually(func() error {
-				jobName = name.SafeConcatName(gitRepoName, name.Hex(repo+commit, 5))
+				jobName = names.SafeConcatName(gitRepoName, names.Hex(repo+commit, 5))
 				return k8sClient.Get(ctx, types.NamespacedName{Name: jobName, Namespace: gitRepoNamespace}, &job)
 			}).Should(Not(HaveOccurred()))
 			// store the generation value to compare against later
@@ -443,7 +443,7 @@ var _ = Describe("GitJob controller", func() {
 			gitRepo = createGitRepo(gitRepoName)
 			Expect(k8sClient.Create(ctx, &gitRepo)).ToNot(HaveOccurred())
 			Eventually(func() error {
-				jobName = name.SafeConcatName(gitRepoName, name.Hex(repo+commit, 5))
+				jobName = names.SafeConcatName(gitRepoName, names.Hex(repo+commit, 5))
 				return k8sClient.Get(ctx, types.NamespacedName{Name: jobName, Namespace: gitRepoNamespace}, &job)
 			}).Should(Not(HaveOccurred()))
 
@@ -488,7 +488,7 @@ var _ = Describe("GitJob controller", func() {
 
 			By("Creating a job")
 			Eventually(func() error {
-				jobName := name.SafeConcatName(gitRepoName, name.Hex(repo+stableCommit, 5))
+				jobName := names.SafeConcatName(gitRepoName, names.Hex(repo+stableCommit, 5))
 				return k8sClient.Get(ctx, types.NamespacedName{Name: jobName, Namespace: gitRepoNamespace}, &job)
 			}).Should(Not(HaveOccurred()))
 		})
@@ -558,7 +558,7 @@ var _ = Describe("GitJob controller", func() {
 
 			It("doesn't create RBAC resources", func() {
 				Consistently(func() bool {
-					saName := name.SafeConcatName("git", gitRepo.Name)
+					saName := names.SafeConcatName("git", gitRepo.Name)
 					ns := types.NamespacedName{Name: saName, Namespace: gitRepo.Namespace}
 
 					if err := k8sClient.Get(ctx, ns, &corev1.ServiceAccount{}); !errors.IsNotFound(err) {
@@ -576,7 +576,7 @@ var _ = Describe("GitJob controller", func() {
 
 			It("doesn't create the job", func() {
 				Consistently(func() bool {
-					jobName := name.SafeConcatName(gitRepoName, name.Hex(repo+commit, 5))
+					jobName := names.SafeConcatName(gitRepoName, names.Hex(repo+commit, 5))
 					newJob := &batchv1.Job{}
 					err := k8sClient.Get(ctx, types.NamespacedName{Name: jobName, Namespace: gitRepo.Namespace}, newJob)
 					return errors.IsNotFound(err)
@@ -597,7 +597,7 @@ var _ = Describe("GitJob controller", func() {
 
 			It("doesn't create RBAC resources", func() {
 				Consistently(func() bool {
-					saName := name.SafeConcatName("git", gitRepo.Name)
+					saName := names.SafeConcatName("git", gitRepo.Name)
 					ns := types.NamespacedName{Name: saName, Namespace: gitRepo.Namespace}
 
 					if err := k8sClient.Get(ctx, ns, &corev1.ServiceAccount{}); !errors.IsNotFound(err) {
@@ -615,7 +615,7 @@ var _ = Describe("GitJob controller", func() {
 
 			It("doesn't create the job", func() {
 				Consistently(func() bool {
-					jobName := name.SafeConcatName(gitRepoName, name.Hex(repo+commit, 5))
+					jobName := names.SafeConcatName(gitRepoName, names.Hex(repo+commit, 5))
 					newJob := &batchv1.Job{}
 					err := k8sClient.Get(ctx, types.NamespacedName{Name: jobName, Namespace: gitRepo.Namespace}, newJob)
 					return errors.IsNotFound(err)
diff --git a/internal/name/name_test.go b/internal/names/name_test.go
similarity index 93%
rename from internal/name/name_test.go
rename to internal/names/name_test.go
index c6b1dcab..fbdf23a1 100644
--- a/internal/name/name_test.go
+++ b/internal/names/name_test.go
@@ -1,9 +1,9 @@
-package name_test
+package names_test
 
 import (
 	"fmt"
 
-	"github.com/rancher/fleet/internal/name"
+	"github.com/rancher/fleet/internal/names"
 
 	. "github.com/onsi/ginkgo/v2"
 	. "github.com/onsi/gomega"
@@ -36,7 +36,7 @@ var _ = Describe("Name", func() {
 
 		It("matches expected results", func() {
 			for _, t := range tests {
-				r := name.Limit(t.arg, t.n)
+				r := names.Limit(t.arg, t.n)
 				Expect(r).To(Equal(t.result), fmt.Sprintf("%#v", t))
 			}
 		})
@@ -58,7 +58,7 @@ var _ = Describe("Name", func() {
 
 		It("matches expected results", func() {
 			for _, t := range tests {
-				r := name.HelmReleaseName(t.arg)
+				r := names.HelmReleaseName(t.arg)
 				Expect(r).To(Equal(t.result), fmt.Sprintf("%#v", t))
 			}
 		})
diff --git a/internal/names/safeconcat_test.go b/internal/names/safeconcat_test.go
new file mode 100644
index 00000000..5bbdee62
--- /dev/null
+++ b/internal/names/safeconcat_test.go
@@ -0,0 +1,64 @@
+package names
+
+import (
+	"testing"
+)
+
+const (
+	string32 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+	string63 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+	string64 = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+)
+
+func TestSafeConcatName(t *testing.T) {
+	t.Parallel()
+	tests := []struct {
+		name   string
+		input  []string
+		output string
+	}{
+		{
+			name:   "empty input",
+			output: "",
+		},
+		{
+			name:   "single string",
+			input:  []string{string63},
+			output: string63,
+		},
+		{
+			name:   "single long string",
+			input:  []string{string64},
+			output: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-ffe05",
+		},
+		{
+			name:   "concatenate strings",
+			input:  []string{"first", "second", "third"},
+			output: "first-second-third",
+		},
+		{
+			name:   "concatenate past 64 characters",
+			input:  []string{string32, string32},
+			output: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-aaaaaaaaaaaaaaaaaaaaaaaa-da5ed",
+		},
+		{
+			name:   "last character after truncation is not alphanumeric",
+			input:  []string{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-aaaaaaa"},
+			output: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-768c62",
+		},
+		{
+			name:   "last characters after truncation aren't alphanumeric",
+			input:  []string{"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--aaaaaaa"},
+			output: "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa--9e8cfe",
+		},
+	}
+	for _, tt := range tests {
+		tt := tt
+		t.Run(tt.name, func(t *testing.T) {
+			t.Parallel()
+			if got := SafeConcatName(tt.input...); got != tt.output {
+				t.Errorf("SafeConcatName() = %v, want %v", got, tt.output)
+			}
+		})
+	}
+}
diff --git a/internal/name/suite_test.go b/internal/names/suite_test.go
similarity index 90%
rename from internal/name/suite_test.go
rename to internal/names/suite_test.go
index 7db1aa7d..e8243f7f 100644
--- a/internal/name/suite_test.go
+++ b/internal/names/suite_test.go
@@ -1,4 +1,4 @@
-package name_test
+package names_test
 
 import (
 	"testing"