diff --git a/go.mod b/go.mod index 85ccc85a3..33dc9974d 100644 --- a/go.mod +++ b/go.mod @@ -29,7 +29,7 @@ require ( k8s.io/klog/v2 v2.130.1 k8s.io/kube-openapi v0.0.0-20240703190633-0aa61b46e8c2 kmodules.xyz/apiversion v0.2.0 - kmodules.xyz/client-go v0.30.38 + kmodules.xyz/client-go v0.30.39 kmodules.xyz/crd-schema-fuzz v0.29.1 kmodules.xyz/go-containerregistry v0.0.12 kmodules.xyz/offshoot-api v0.30.1 diff --git a/go.sum b/go.sum index cfa8bd33c..25860d51b 100644 --- a/go.sum +++ b/go.sum @@ -334,8 +334,8 @@ k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0 h1:jgGTlFYnhF1PM1Ax/lAlxUPE+KfCI k8s.io/utils v0.0.0-20240502163921-fe8a2dddb1d0/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= kmodules.xyz/apiversion v0.2.0 h1:vAQYqZFm4xu4pbB1cAdHbFEPES6EQkcR4wc06xdTOWk= kmodules.xyz/apiversion v0.2.0/go.mod h1:oPX8g8LvlPdPX3Yc5YvCzJHQnw3YF/X4/jdW0b1am80= -kmodules.xyz/client-go v0.30.38 h1:kAQ3FdgX2HbkmfFGEoeKz7fmJYWo1Ndgdum50aaHyI0= -kmodules.xyz/client-go v0.30.38/go.mod h1:CAu+JlA8RVGtj6LQHu0Q1w2mnFUajuti49c7T1AvGdM= +kmodules.xyz/client-go v0.30.39 h1:/GjcgKLY1WdsHRK+956FXQdqDkJg/voJASo+IFyH0xA= +kmodules.xyz/client-go v0.30.39/go.mod h1:CAu+JlA8RVGtj6LQHu0Q1w2mnFUajuti49c7T1AvGdM= kmodules.xyz/crd-schema-fuzz v0.29.1 h1:zJTlWYOrT5dsVVHW8HGcnR/vaWfxQfNh11QwTtkYpcs= kmodules.xyz/crd-schema-fuzz v0.29.1/go.mod h1:n708z9YQqLMP2KNLQVgBcRJw1QpSWLvpNCEi+KJDOYE= kmodules.xyz/go-containerregistry v0.0.12 h1:Tl32QGmSqRVm9PUEb/f3dgDeu9zW5fVzt3qmAFIE37I= diff --git a/hub/resourcedescriptors/cluster.open-cluster-management.io/v1beta2/managedclustersetbindings.yaml b/hub/resourcedescriptors/cluster.open-cluster-management.io/v1beta2/managedclustersetbindings.yaml index 3e682e60b..3a4dbcbb9 100644 --- a/hub/resourcedescriptors/cluster.open-cluster-management.io/v1beta2/managedclustersetbindings.yaml +++ b/hub/resourcedescriptors/cluster.open-cluster-management.io/v1beta2/managedclustersetbindings.yaml @@ -26,22 +26,27 @@ spec: version: v1beta2 validation: openAPIV3Schema: - description: ManagedClusterSetBinding projects a ManagedClusterSet into a certain - namespace. You can create a ManagedClusterSetBinding in a namespace and bind - it to a ManagedClusterSet if both have a RBAC rules to CREATE on the virtual - subresource of managedclustersets/bind. Workloads that you create in the same - namespace can only be distributed to ManagedClusters in ManagedClusterSets - that are bound in this namespace by higher-level controllers. + description: |- + ManagedClusterSetBinding projects a ManagedClusterSet into a certain namespace. + You can create a ManagedClusterSetBinding in a namespace and bind it to a + ManagedClusterSet if both have a RBAC rules to CREATE on the virtual subresource of managedclustersets/bind. + Workloads that you create in the same namespace can only be distributed to ManagedClusters + in ManagedClusterSets that are bound in this namespace by higher-level controllers. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: properties: @@ -80,10 +85,11 @@ spec: description: Spec defines the attributes of ManagedClusterSetBinding. properties: clusterSet: - description: ClusterSet is the name of the ManagedClusterSet to bind. - It must match the instance name of the ManagedClusterSetBinding and - cannot change once created. User is allowed to set this field if they - have an RBAC rule to CREATE on the virtual subresource of managedclustersets/bind. + description: |- + ClusterSet is the name of the ManagedClusterSet to bind. It must match the + instance name of the ManagedClusterSetBinding and cannot change once created. + User is allowed to set this field if they have an RBAC rule to CREATE on the + virtual subresource of managedclustersets/bind. minLength: 1 type: string type: object diff --git a/hub/resourcedescriptors/cluster.open-cluster-management.io/v1beta2/managedclustersets.yaml b/hub/resourcedescriptors/cluster.open-cluster-management.io/v1beta2/managedclustersets.yaml index d8f07b556..eb642f418 100644 --- a/hub/resourcedescriptors/cluster.open-cluster-management.io/v1beta2/managedclustersets.yaml +++ b/hub/resourcedescriptors/cluster.open-cluster-management.io/v1beta2/managedclustersets.yaml @@ -27,27 +27,35 @@ spec: version: v1beta2 validation: openAPIV3Schema: - description: "ManagedClusterSet defines a group of ManagedClusters that user's - workload can run on. A workload can be defined to deployed on a ManagedClusterSet, - which mean: 1. The workload can run on any ManagedCluster in the ManagedClusterSet - 2. The workload cannot run on any ManagedCluster outside the ManagedClusterSet - 3. The service exposed by the workload can be shared in any ManagedCluster - in the ManagedClusterSet \n In order to assign a ManagedCluster to a certian - ManagedClusterSet, add a label with name `cluster.open-cluster-management.io/clusterset` - on the ManagedCluster to refers to the ManagedClusterSet. User is not allow - to add/remove this label on a ManagedCluster unless they have a RBAC rule - to CREATE on a virtual subresource of managedclustersets/join. In order to - update this label, user must have the permission on both the old and new ManagedClusterSet." + description: |- + ManagedClusterSet defines a group of ManagedClusters that you can run + workloads on. You can define a workload to be deployed on a ManagedClusterSet. See the following options for the workload: + - The workload can run on any ManagedCluster in the ManagedClusterSet + - The workload cannot run on any ManagedCluster outside the ManagedClusterSet + - The service exposed by the workload can be shared in any ManagedCluster in the ManagedClusterSet + + + To assign a ManagedCluster to a certain ManagedClusterSet, add a label with the name cluster.open-cluster-management.io/clusterset + on the ManagedCluster to refer to the ManagedClusterSet. You are not + allowed to add or remove this label on a ManagedCluster unless you have an + RBAC rule to CREATE on a virtual subresource of managedclustersets/join. + To update this label, you must have the permission on both + the old and new ManagedClusterSet. properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: properties: @@ -93,51 +101,51 @@ spec: description: matchExpressions is a list of label selector requirements. The requirements are ANDed. items: - description: A label selector requirement is a selector that - contains values, a key, and an operator that relates the - key and values. + description: |- + A label selector requirement is a selector that contains values, a key, and an operator that + relates the key and values. properties: key: description: key is the label key that the selector applies to. type: string operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, Exists - and DoesNotExist. + description: |- + operator represents a key's relationship to a set of values. + Valid operators are In, NotIn, Exists and DoesNotExist. type: string values: - description: values is an array of string values. If the - operator is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. This array is replaced during a - strategic merge patch. + description: |- + values is an array of string values. If the operator is In or NotIn, + the values array must be non-empty. If the operator is Exists or DoesNotExist, + the values array must be empty. This array is replaced during a strategic + merge patch. items: type: string type: array + x-kubernetes-list-type: atomic required: - key - operator type: object type: array + x-kubernetes-list-type: atomic matchLabels: additionalProperties: type: string - description: matchLabels is a map of {key,value} pairs. A single - {key,value} in the matchLabels map is equivalent to an element - of matchExpressions, whose key field is "key", the operator - is "In", and the values array contains only "value". The requirements - are ANDed. + description: |- + matchLabels is a map of {key,value} pairs. A single {key,value} in the matchLabels + map is equivalent to an element of matchExpressions, whose key field is "key", the + operator is "In", and the values array contains only "value". The requirements are ANDed. type: object type: object x-kubernetes-map-type: atomic selectorType: default: ExclusiveClusterSetLabel - description: SelectorType could only be "ExclusiveClusterSetLabel" - or "LabelSelector" "ExclusiveClusterSetLabel" means to use label - "cluster.open-cluster-management.io/clusterset:"" to select target clusters. "LabelSelector" means use labelSelector - to select target managedClusters + description: |- + SelectorType could only be "ExclusiveClusterSetLabel" or "LabelSelector" + "ExclusiveClusterSetLabel" means to use label "cluster.open-cluster-management.io/clusterset:"" to select target clusters. + "LabelSelector" means use labelSelector to select target managedClusters enum: - ExclusiveClusterSetLabel - LabelSelector diff --git a/hub/resourcetabledefinitions/cluster.open-cluster-management.io/v1beta2/managedclustersets.yaml b/hub/resourcetabledefinitions/cluster.open-cluster-management.io/v1beta2/managedclustersets.yaml index db49f0992..c5750b90b 100644 --- a/hub/resourcetabledefinitions/cluster.open-cluster-management.io/v1beta2/managedclustersets.yaml +++ b/hub/resourcetabledefinitions/cluster.open-cluster-management.io/v1beta2/managedclustersets.yaml @@ -19,20 +19,12 @@ spec: pathTemplate: '{{ .metadata.labels | toRawJson }}' priority: 3 type: object - - name: Hub Accepted - pathTemplate: '{{ jp `{.spec.hubAcceptsClient}` . }}' - priority: 3 - type: boolean - - name: Managed Cluster URLs - pathTemplate: '{{ jp `{.spec.managedClusterClientConfigs[*].url}` . }}' - priority: 3 - type: string - - name: Joined - pathTemplate: '{{ jp `{.status.conditions[?(@.type=="ManagedClusterJoined")].status}` . }}' + - name: Managed Clusters + pathTemplate: '{{ jp `{.status.conditions[?(@.type=="ClusterSetEmpty")]}` . | count_managed_clusters }}' priority: 3 type: string - - name: Available - pathTemplate: '{{ jp `{.status.conditions[?(@.type=="ManagedClusterConditionAvailable")].status}` . }}' + - name: Profile + pathTemplate: '{{ .metadata.labels | get_cluster_profile }}' priority: 3 type: string - name: Age diff --git a/pkg/tableconvertor/templates.go b/pkg/tableconvertor/templates.go index 59d0ad5fc..efb39bb30 100644 --- a/pkg/tableconvertor/templates.go +++ b/pkg/tableconvertor/templates.go @@ -23,6 +23,7 @@ import ( "text/template" "time" + kmapi "kmodules.xyz/client-go/api/v1" meta_util "kmodules.xyz/client-go/meta" "kmodules.xyz/resource-metadata/pkg/tableconvertor/lib" "kmodules.xyz/resource-metadata/pkg/tableconvertor/printers" @@ -63,6 +64,8 @@ func init() { templateFns["cert_validity"] = certificateValidity templateFns["k8s_fmt_resource_cpu"] = formatResourceCPUFn templateFns["k8s_fmt_resource_memory"] = formatResourceMemoryFn + templateFns["count_managed_clusters"] = managedClusterSetFn + templateFns["get_cluster_profile"] = getClusterProfile // ref: https://github.com/kmodules/resource-metrics/blob/bf6b257f8922a5572ccd20bf1cbab6bbedf4fcb4/template.go#L26-L36 for name, fn := range resourcemetrics.TxtFuncMap() { templateFns[name] = fn @@ -509,3 +512,45 @@ func formatResourceMemoryFn(data interface{}) (string, error) { } return fmt.Sprintf("%.1fGi", mem/1024.0/1024.0/1024.0), nil } + +func managedClusterSetFn(data interface{}) (string, error) { + conditionStr, ok := data.(string) + if !ok { + return "", fmt.Errorf("expected string input, got %T", data) + } + + var condition map[string]interface{} + if err := json.Unmarshal([]byte(conditionStr), &condition); err != nil { + return "", fmt.Errorf("failed to unmarshal condition data: %v", err) + } + + status, _ := condition["status"].(string) + message, _ := condition["message"].(string) + + // Return "0" if status is "True" + if status == "True" { + return "0", nil + } + + // Split the message and return the first word + words := strings.Split(message, " ") + if len(words) > 0 { + return words[0], nil + } + + return "", fmt.Errorf("message is empty or invalid") +} + +func getClusterProfile(data interface{}) (string, error) { + labels, ok := data.(map[string]interface{}) + if !ok { + return "", nil + } + + if profile, exists := labels[kmapi.ClusterProfileLabel]; exists { + if profileStr, ok := profile.(string); ok { + return profileStr, nil + } + } + return "", nil +} diff --git a/vendor/kmodules.xyz/client-go/api/v1/cluster.go b/vendor/kmodules.xyz/client-go/api/v1/cluster.go index b40cd8d1e..c8a0a104b 100644 --- a/vendor/kmodules.xyz/client-go/api/v1/cluster.go +++ b/vendor/kmodules.xyz/client-go/api/v1/cluster.go @@ -56,6 +56,7 @@ const ( ClusterNameKey string = "cluster.appscode.com/name" ClusterDisplayNameKey string = "cluster.appscode.com/display-name" ClusterProviderNameKey string = "cluster.appscode.com/provider" + ClusterProfileLabel string = "cluster.appscode.com/profile" AceOrgIDKey string = "ace.appscode.com/org-id" ClientOrgKey string = "ace.appscode.com/client-org" diff --git a/vendor/modules.txt b/vendor/modules.txt index cd383ed92..2f94e69d1 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -745,7 +745,7 @@ k8s.io/utils/trace # kmodules.xyz/apiversion v0.2.0 ## explicit; go 1.14 kmodules.xyz/apiversion -# kmodules.xyz/client-go v0.30.38 +# kmodules.xyz/client-go v0.30.39 ## explicit; go 1.22.0 kmodules.xyz/client-go kmodules.xyz/client-go/api/v1