Skip to content

Commit c6cac04

Browse files
authored
Merge pull request #8318 from fabriziopandini/add-soft-ownership-from-clusters-to-clusterresourcesetbinding
🐛 Add soft ownership from clusters to ClusterResourceSetBinding
2 parents eb8a970 + 4847063 commit c6cac04

File tree

3 files changed

+177
-37
lines changed

3 files changed

+177
-37
lines changed

cmd/clusterctl/client/cluster/objectgraph.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import (
3737
)
3838

3939
const clusterTopologyNameKey = "cluster.spec.topology.class"
40+
const clusterResourceSetBindingClusterNameKey = "clusterresourcesetbinding.spec.clustername"
4041

4142
type empty struct{}
4243

@@ -146,6 +147,17 @@ func (n *node) captureAdditionalInformation(obj *unstructured.Unstructured) erro
146147
}
147148
}
148149

150+
// If the node is a ClusterResourceSetBinding capture the name of the cluster it is referencing to.
151+
if n.identity.GroupVersionKind().GroupKind() == addonsv1.GroupVersion.WithKind("ClusterResourceSetBinding").GroupKind() {
152+
binding := &addonsv1.ClusterResourceSetBinding{}
153+
if err := localScheme.Convert(obj, binding, nil); err != nil {
154+
return errors.Wrapf(err, "failed to convert object %s to ClusterResourceSetBinding", n.identityStr())
155+
}
156+
if n.additionalInfo == nil {
157+
n.additionalInfo = map[string]interface{}{}
158+
}
159+
n.additionalInfo[clusterResourceSetBindingClusterNameKey] = binding.Spec.ClusterName
160+
}
149161
return nil
150162
}
151163

@@ -504,6 +516,17 @@ func (o *objectGraph) getClusterClasses() []*node {
504516
return clusterClasses
505517
}
506518

519+
// getClusterResourceSetBinding returns the list of ClusterResourceSetBinding existing in the object graph.
520+
func (o *objectGraph) getClusterResourceSetBinding() []*node {
521+
crs := []*node{}
522+
for _, node := range o.uidToNode {
523+
if node.identity.GroupVersionKind().GroupKind() == addonsv1.GroupVersion.WithKind("ClusterResourceSetBinding").GroupKind() {
524+
crs = append(crs, node)
525+
}
526+
}
527+
return crs
528+
}
529+
507530
// getClusters returns the list of Secrets existing in the object graph.
508531
func (o *objectGraph) getSecrets() []*node {
509532
secrets := []*node{}
@@ -588,7 +611,7 @@ func (o *objectGraph) setSoftOwnership() {
588611
// Cluster that uses a ClusterClass are soft owned by that ClusterClass.
589612
for _, clusterClass := range clusterClasses {
590613
for _, cluster := range clusters {
591-
// if the cluster uses a managed topoloy and uses the clusterclass
614+
// if the cluster uses a managed topology and uses the clusterclass
592615
// set the clusterclass as a soft owner of the cluster.
593616
if className, ok := cluster.additionalInfo[clusterTopologyNameKey]; ok {
594617
if className == clusterClass.identity.Name && clusterClass.identity.Namespace == cluster.identity.Namespace {
@@ -597,6 +620,21 @@ func (o *objectGraph) setSoftOwnership() {
597620
}
598621
}
599622
}
623+
624+
crsBindings := o.getClusterResourceSetBinding()
625+
// ClusterResourceSetBinding that refers to a Cluster are soft owned by that Cluster.
626+
for _, binding := range crsBindings {
627+
clusterName, ok := binding.additionalInfo[clusterResourceSetBindingClusterNameKey]
628+
if !ok {
629+
continue
630+
}
631+
632+
for _, cluster := range clusters {
633+
if clusterName == cluster.identity.Name && binding.identity.Namespace == cluster.identity.Namespace {
634+
binding.addSoftOwner(cluster)
635+
}
636+
}
637+
}
600638
}
601639

602640
// setTenants identifies all the nodes linked to a parent with forceMoveHierarchy = true (e.g. Clusters or ClusterResourceSet)

cmd/clusterctl/client/cluster/objectgraph_test.go

Lines changed: 137 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1120,6 +1120,8 @@ var objectGraphsTests = []struct {
11201120
"addons.cluster.x-k8s.io/v1beta1, Kind=ClusterResourceSetBinding, ns1/cluster1": {
11211121
owners: []string{
11221122
"addons.cluster.x-k8s.io/v1beta1, Kind=ClusterResourceSet, ns1/crs1",
1123+
},
1124+
softOwners: []string{
11231125
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1",
11241126
},
11251127
},
@@ -1201,12 +1203,16 @@ var objectGraphsTests = []struct {
12011203
"addons.cluster.x-k8s.io/v1beta1, Kind=ClusterResourceSetBinding, ns1/cluster1": {
12021204
owners: []string{
12031205
"addons.cluster.x-k8s.io/v1beta1, Kind=ClusterResourceSet, ns1/crs1",
1206+
},
1207+
softOwners: []string{
12041208
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1",
12051209
},
12061210
},
12071211
"addons.cluster.x-k8s.io/v1beta1, Kind=ClusterResourceSetBinding, ns1/cluster2": {
12081212
owners: []string{
12091213
"addons.cluster.x-k8s.io/v1beta1, Kind=ClusterResourceSet, ns1/crs1",
1214+
},
1215+
softOwners: []string{
12101216
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster2",
12111217
},
12121218
},
@@ -1887,32 +1893,148 @@ func Test_objectGraph_setSoftOwnership(t *testing.T) {
18871893
objs []client.Object
18881894
}
18891895
tests := []struct {
1890-
name string
1891-
fields fields
1892-
wantSecrets map[string][]string
1896+
name string
1897+
fields fields
1898+
want wantGraph
18931899
}{
18941900
{
18951901
name: "A cluster with a soft owned secret",
18961902
fields: fields{
1897-
objs: test.NewFakeCluster("ns1", "foo").Objs(),
1903+
objs: test.NewFakeCluster("ns1", "cluster1").Objs(),
18981904
},
1899-
wantSecrets: map[string][]string{ // wantSecrets is a map[node UID] --> list of soft owner UIDs
1900-
"/v1, Kind=Secret, ns1/foo-ca": { // the ca secret has no explicit OwnerRef to the cluster, so it should be identified as a soft ownership
1901-
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/foo",
1905+
want: wantGraph{
1906+
nodes: map[string]wantGraphItem{
1907+
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1": {
1908+
forceMove: true,
1909+
forceMoveHierarchy: true,
1910+
},
1911+
"infrastructure.cluster.x-k8s.io/v1beta1, Kind=GenericInfrastructureCluster, ns1/cluster1": {
1912+
owners: []string{
1913+
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1",
1914+
},
1915+
},
1916+
"/v1, Kind=Secret, ns1/cluster1-ca": { // the ca secret has no explicit OwnerRef to the cluster, so it should be identified as a soft ownership
1917+
softOwners: []string{
1918+
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1",
1919+
},
1920+
},
1921+
"/v1, Kind=Secret, ns1/cluster1-kubeconfig": { // the kubeconfig secret has explicit OwnerRef to the cluster, so it should NOT be identified as a soft ownership
1922+
owners: []string{
1923+
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1",
1924+
},
1925+
},
19021926
},
1903-
"/v1, Kind=Secret, ns1/foo-kubeconfig": {}, // the kubeconfig secret has explicit OwnerRef to the cluster, so it should NOT be identified as a soft ownership
19041927
},
19051928
},
19061929
{
1907-
name: "A cluster with a soft owned secret (cluster name with - in the middle)",
1930+
name: "A ClusterClass with a soft owned Cluster",
19081931
fields: fields{
1909-
objs: test.NewFakeCluster("ns1", "foo-bar").Objs(),
1932+
objs: func() []client.Object {
1933+
objs := test.NewFakeClusterClass("ns1", "class1").Objs()
1934+
objs = append(objs, test.NewFakeCluster("ns1", "cluster1").WithTopologyClass("class1").Objs()...)
1935+
1936+
return objs
1937+
}(),
19101938
},
1911-
wantSecrets: map[string][]string{ // wantSecrets is a map[node UID] --> list of soft owner UIDs
1912-
"/v1, Kind=Secret, ns1/foo-bar-ca": { // the ca secret has no explicit OwnerRef to the cluster, so it should be identified as a soft ownership
1913-
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/foo-bar",
1939+
want: wantGraph{
1940+
nodes: map[string]wantGraphItem{
1941+
"cluster.x-k8s.io/v1beta1, Kind=ClusterClass, ns1/class1": {
1942+
forceMove: true,
1943+
forceMoveHierarchy: true,
1944+
},
1945+
"infrastructure.cluster.x-k8s.io/v1beta1, Kind=GenericInfrastructureClusterTemplate, ns1/class1": {
1946+
owners: []string{
1947+
"cluster.x-k8s.io/v1beta1, Kind=ClusterClass, ns1/class1",
1948+
},
1949+
},
1950+
"controlplane.cluster.x-k8s.io/v1beta1, Kind=GenericControlPlaneTemplate, ns1/class1": {
1951+
owners: []string{
1952+
"cluster.x-k8s.io/v1beta1, Kind=ClusterClass, ns1/class1",
1953+
},
1954+
},
1955+
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1": {
1956+
forceMove: true,
1957+
forceMoveHierarchy: true,
1958+
softOwners: []string{
1959+
"cluster.x-k8s.io/v1beta1, Kind=ClusterClass, ns1/class1", // NB. this cluster is not linked to the clusterclass through owner ref, but it is detected as soft ownership
1960+
},
1961+
},
1962+
"infrastructure.cluster.x-k8s.io/v1beta1, Kind=GenericInfrastructureCluster, ns1/cluster1": {
1963+
owners: []string{
1964+
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1",
1965+
},
1966+
},
1967+
"/v1, Kind=Secret, ns1/cluster1-ca": {
1968+
softOwners: []string{
1969+
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1", // NB. this secret is not linked to the cluster through owner ref, but it is detected as soft ownership
1970+
},
1971+
},
1972+
"/v1, Kind=Secret, ns1/cluster1-kubeconfig": {
1973+
owners: []string{
1974+
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1",
1975+
},
1976+
},
1977+
},
1978+
},
1979+
},
1980+
{
1981+
name: "A Cluster with a soft owned ClusterResourceSetBinding",
1982+
fields: fields{
1983+
objs: func() []client.Object {
1984+
objs := test.NewFakeCluster("ns1", "cluster1").Objs()
1985+
objs = append(objs, test.NewFakeClusterResourceSet("ns1", "crs1").
1986+
WithSecret("resource-s1").
1987+
WithConfigMap("resource-c1").
1988+
ApplyToCluster(test.SelectClusterObj(objs, "ns1", "cluster1")).
1989+
Objs()...)
1990+
1991+
return objs
1992+
}(),
1993+
},
1994+
want: wantGraph{
1995+
nodes: map[string]wantGraphItem{
1996+
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1": {
1997+
forceMove: true,
1998+
forceMoveHierarchy: true,
1999+
},
2000+
"infrastructure.cluster.x-k8s.io/v1beta1, Kind=GenericInfrastructureCluster, ns1/cluster1": {
2001+
owners: []string{
2002+
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1",
2003+
},
2004+
},
2005+
"/v1, Kind=Secret, ns1/cluster1-ca": {
2006+
softOwners: []string{
2007+
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1", // NB. this secret is not linked to the cluster through owner ref, but it is detected as soft ownership
2008+
},
2009+
},
2010+
"/v1, Kind=Secret, ns1/cluster1-kubeconfig": {
2011+
owners: []string{
2012+
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1",
2013+
},
2014+
},
2015+
"addons.cluster.x-k8s.io/v1beta1, Kind=ClusterResourceSet, ns1/crs1": {
2016+
forceMove: true,
2017+
forceMoveHierarchy: true,
2018+
},
2019+
"addons.cluster.x-k8s.io/v1beta1, Kind=ClusterResourceSetBinding, ns1/cluster1": {
2020+
owners: []string{
2021+
"addons.cluster.x-k8s.io/v1beta1, Kind=ClusterResourceSet, ns1/crs1",
2022+
},
2023+
softOwners: []string{
2024+
"cluster.x-k8s.io/v1beta1, Kind=Cluster, ns1/cluster1", // NB. this ClusterResourceSetBinding is not linked to the cluster through owner ref, but it is detected as soft ownership
2025+
},
2026+
},
2027+
"/v1, Kind=Secret, ns1/resource-s1": {
2028+
owners: []string{
2029+
"addons.cluster.x-k8s.io/v1beta1, Kind=ClusterResourceSet, ns1/crs1",
2030+
},
2031+
},
2032+
"/v1, Kind=ConfigMap, ns1/resource-c1": {
2033+
owners: []string{
2034+
"addons.cluster.x-k8s.io/v1beta1, Kind=ClusterResourceSet, ns1/crs1",
2035+
},
2036+
},
19142037
},
1915-
"/v1, Kind=Secret, ns1/foo-bar-kubeconfig": {}, // the kubeconfig secret has explicit OwnerRef to the cluster, so it should NOT be identified as a soft ownership
19162038
},
19172039
},
19182040
}
@@ -1925,20 +2047,7 @@ func Test_objectGraph_setSoftOwnership(t *testing.T) {
19252047

19262048
graph.setSoftOwnership()
19272049

1928-
gotSecrets := graph.getSecrets()
1929-
g.Expect(gotSecrets).To(HaveLen(len(tt.wantSecrets)))
1930-
1931-
for _, secret := range gotSecrets {
1932-
wantObjects, ok := tt.wantSecrets[string(secret.identity.UID)]
1933-
g.Expect(ok).To(BeTrue())
1934-
1935-
gotObjects := []string{}
1936-
for softOwners := range secret.softOwners {
1937-
gotObjects = append(gotObjects, string(softOwners.identity.UID))
1938-
}
1939-
1940-
g.Expect(gotObjects).To(ConsistOf(wantObjects))
1941-
}
2050+
assertGraph(t, graph, tt.want)
19422051
})
19432052
}
19442053
}

cmd/clusterctl/internal/test/fake_objects.go

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1099,6 +1099,7 @@ func (f *FakeClusterResourceSet) Objs() []client.Object {
10991099
Namespace: cluster.Namespace,
11001100
},
11011101
Spec: addonsv1.ClusterResourceSetBindingSpec{
1102+
ClusterName: cluster.Name,
11021103
Bindings: []*addonsv1.ResourceSetBinding{
11031104
{
11041105
ClusterResourceSetName: crs.Name,
@@ -1119,14 +1120,6 @@ func (f *FakeClusterResourceSet) Objs() []client.Object {
11191120

11201121
objs = append(objs, binding)
11211122

1122-
// binding are owned by the Cluster / ownership set by the ClusterResourceSet controller
1123-
binding.SetOwnerReferences(append(binding.OwnerReferences, metav1.OwnerReference{
1124-
APIVersion: cluster.APIVersion,
1125-
Kind: cluster.Kind,
1126-
Name: cluster.Name,
1127-
UID: cluster.UID,
1128-
}))
1129-
11301123
resourceSetBinding := addonsv1.ResourceSetBinding{
11311124
ClusterResourceSetName: crs.Name,
11321125
Resources: []addonsv1.ResourceBinding{},

0 commit comments

Comments
 (0)