update placement and placementdecision to v1beta1 (#198)

* update placement and placementdecision to v1beta1

Signed-off-by: haoqing0110 <qhao@redhat.com>

* add placement and placementdecision StorageVersionMigration

Signed-off-by: haoqing0110 <qhao@redhat.com>
This commit is contained in:
Qing Hao
2022-01-27 09:06:51 -05:00
committed by GitHub
parent 9332a9dc04
commit 2c2316fafa
30 changed files with 2267 additions and 21 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ require (
k8s.io/component-base v0.21.0-rc.0
k8s.io/klog/v2 v2.8.0
k8s.io/kube-aggregator v0.21.0-rc.0
open-cluster-management.io/api v0.5.1-0.20220111063708-e6fd0b245ae9
open-cluster-management.io/api v0.6.1-0.20220127035449-918b7bf7184f
sigs.k8s.io/controller-runtime v0.6.1-0.20200829232221-efc74d056b24
sigs.k8s.io/kube-storage-version-migrator v0.0.3
)
+2 -2
View File
@@ -968,8 +968,8 @@ modernc.org/golex v1.0.0/go.mod h1:b/QX9oBD/LhixY6NDh+IdGv17hgB+51fET1i2kPSmvk=
modernc.org/mathutil v1.0.0/go.mod h1:wU0vUrJsVWBZ4P6e7xtFJEhFSNsfRLJ8H458uRjg03k=
modernc.org/strutil v1.0.0/go.mod h1:lstksw84oURvj9y3tn8lGvRxyRC1S2+g5uuIzNfIOBs=
modernc.org/xc v1.0.0/go.mod h1:mRNCo0bvLjGhHO9WsyuKVU4q0ceiDDDoEeWDJHrNx8I=
open-cluster-management.io/api v0.5.1-0.20220111063708-e6fd0b245ae9 h1:5Ov3FblacHNaDOFSSB4ml+IvSr4uekd9b8b+wWydpM4=
open-cluster-management.io/api v0.5.1-0.20220111063708-e6fd0b245ae9/go.mod h1:0IUTh8J+p4pv1THh1r9oO0luX9Z1FLDEAmvzW09qC0o=
open-cluster-management.io/api v0.6.1-0.20220127035449-918b7bf7184f h1:qPXjohccAOJAa2PXSuoncKzMCmz35CScEjuseo2Siu8=
open-cluster-management.io/api v0.6.1-0.20220127035449-918b7bf7184f/go.mod h1:0IUTh8J+p4pv1THh1r9oO0luX9Z1FLDEAmvzW09qC0o=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
+2 -2
View File
@@ -8,8 +8,8 @@ HUB_CRD_FILES="./vendor/open-cluster-management.io/api/cluster/v1/*.crd.yaml
./vendor/open-cluster-management.io/api/addon/v1alpha1/*.crd.yaml
./vendor/open-cluster-management.io/api/cluster/v1beta1/0000_00_clusters.open-cluster-management.io_managedclustersets.crd.yaml
./vendor/open-cluster-management.io/api/cluster/v1beta1/0000_01_clusters.open-cluster-management.io_managedclustersetbindings.crd.yaml
./vendor/open-cluster-management.io/api/cluster/v1alpha1/0000_03_clusters.open-cluster-management.io_placements.crd.yaml
./vendor/open-cluster-management.io/api/cluster/v1alpha1/0000_04_clusters.open-cluster-management.io_placementdecisions.crd.yaml
./vendor/open-cluster-management.io/api/cluster/v1beta1/0000_02_clusters.open-cluster-management.io_placements.crd.yaml
./vendor/open-cluster-management.io/api/cluster/v1beta1/0000_03_clusters.open-cluster-management.io_placementdecisions.crd.yaml
./vendor/open-cluster-management.io/api/cluster/v1alpha1/0000_05_clusters.open-cluster-management.io_addonplacementscores.crd.yaml
./vendor/open-cluster-management.io/api/work/v1/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml
"
@@ -47,6 +47,10 @@ spec:
crdName:
description: crdName is the name of the CRD used to configure instances of the managed add-on. This field should be configured if the add-on have a CRD that controls the configuration of the add-on.
type: string
lastObservedGeneration:
description: lastObservedGeneration is the observed generation of the custom resource for the configuration of the addon.
type: integer
format: int64
addOnMeta:
description: addOnMeta is a reference to the metadata information for the add-on.
type: object
@@ -61,6 +61,10 @@ spec:
crdName:
description: crdName is the name of the CRD used to configure instances of the managed add-on. This field should be configured if the add-on have a CRD that controls the configuration of the add-on.
type: string
lastObservedGeneration:
description: lastObservedGeneration is the observed generation of the custom resource for the configuration of the addon.
type: integer
format: int64
addOnMeta:
description: addOnMeta is a reference to the metadata information for the add-on. This should be same as the addOnMeta for the corresponding ClusterManagementAddOn resource.
type: object
@@ -23,6 +23,8 @@ spec:
name: SelectedClusters
type: integer
name: v1alpha1
deprecated: true
deprecationWarning: "cluster.open-cluster-management.io/v1alpha1 Placement is deprecated; use cluster.open-cluster-management.io/v1beta1 Placement"
schema:
openAPIV3Schema:
description: "Placement defines a rule to select a set of ManagedClusters from the ManagedClusterSets bound to the placement namespace. \n Here is how the placement policy combines with other selection methods to determine a matching list of ManagedClusters: 1) Kubernetes clusters are registered with hub as cluster-scoped ManagedClusters; 2) ManagedClusters are organized into cluster-scoped ManagedClusterSets; 3) ManagedClusterSets are bound to workload namespaces; 4) Namespace-scoped Placements specify a slice of ManagedClusterSets which select a working set of potential ManagedClusters; 5) Then Placements subselect from that working set using label/claim selection. \n No ManagedCluster will be selected if no ManagedClusterSet is bound to the placement namespace. User is able to bind a ManagedClusterSet to a namespace by creating a ManagedClusterSetBinding in that namespace if they have a RBAC rule to CREATE on the virtual subresource of `managedclustersets/bind`. \n A slice of PlacementDecisions with label cluster.open-cluster-management.io/placement={placement name} will be created to represent the ManagedClusters selected by this placement. \n If a ManagedCluster is selected and added into the PlacementDecisions, other components may apply workload on it; once it is removed from the PlacementDecisions, the workload applied on this ManagedCluster should be evicted accordingly."
@@ -254,6 +256,250 @@ spec:
type: integer
format: int32
served: true
storage: false
subresources:
status: {}
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=="PlacementSatisfied")].status
name: Succeeded
type: string
- jsonPath: .status.conditions[?(@.type=="PlacementSatisfied")].reason
name: Reason
type: string
- jsonPath: .status.numberOfSelectedClusters
name: SelectedClusters
type: integer
name: v1beta1
schema:
openAPIV3Schema:
description: "Placement defines a rule to select a set of ManagedClusters from the ManagedClusterSets bound to the placement namespace. \n Here is how the placement policy combines with other selection methods to determine a matching list of ManagedClusters: 1) Kubernetes clusters are registered with hub as cluster-scoped ManagedClusters; 2) ManagedClusters are organized into cluster-scoped ManagedClusterSets; 3) ManagedClusterSets are bound to workload namespaces; 4) Namespace-scoped Placements specify a slice of ManagedClusterSets which select a working set of potential ManagedClusters; 5) Then Placements subselect from that working set using label/claim selection. \n No ManagedCluster will be selected if no ManagedClusterSet is bound to the placement namespace. User is able to bind a ManagedClusterSet to a namespace by creating a ManagedClusterSetBinding in that namespace if they have a RBAC rule to CREATE on the virtual subresource of `managedclustersets/bind`. \n A slice of PlacementDecisions with label cluster.open-cluster-management.io/placement={placement name} will be created to represent the ManagedClusters selected by this placement. \n If a ManagedCluster is selected and added into the PlacementDecisions, other components may apply workload on it; once it is removed from the PlacementDecisions, the workload applied on this ManagedCluster should be evicted accordingly."
type: object
required:
- spec
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'
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'
type: string
metadata:
type: object
spec:
description: Spec defines the attributes of Placement.
type: object
properties:
clusterSets:
description: ClusterSets represent the ManagedClusterSets from which the ManagedClusters are selected. If the slice is empty, ManagedClusters will be selected from the ManagedClusterSets bound to the placement namespace, otherwise ManagedClusters will be selected from the intersection of this slice and the ManagedClusterSets bound to the placement namespace.
type: array
items:
type: string
numberOfClusters:
description: NumberOfClusters represents the desired number of ManagedClusters to be selected which meet the placement requirements. 1) If not specified, all ManagedClusters which meet the placement requirements (including ClusterSets, and Predicates) will be selected; 2) Otherwise if the nubmer of ManagedClusters meet the placement requirements is larger than NumberOfClusters, a random subset with desired number of ManagedClusters will be selected; 3) If the nubmer of ManagedClusters meet the placement requirements is equal to NumberOfClusters, all of them will be selected; 4) If the nubmer of ManagedClusters meet the placement requirements is less than NumberOfClusters, all of them will be selected, and the status of condition `PlacementConditionSatisfied` will be set to false;
type: integer
format: int32
predicates:
description: Predicates represent a slice of predicates to select ManagedClusters. The predicates are ORed.
type: array
items:
description: ClusterPredicate represents a predicate to select ManagedClusters.
type: object
properties:
requiredClusterSelector:
description: RequiredClusterSelector represents a selector of ManagedClusters by label and claim. If specified, 1) Any ManagedCluster, which does not match the selector, should not be selected by this ClusterPredicate; 2) If a selected ManagedCluster (of this ClusterPredicate) ceases to match the selector (e.g. due to an update) of any ClusterPredicate, it will be eventually removed from the placement decisions; 3) If a ManagedCluster (not selected previously) starts to match the selector, it will either be selected or at least has a chance to be selected (when NumberOfClusters is specified);
type: object
properties:
claimSelector:
description: ClaimSelector represents a selector of ManagedClusters by clusterClaims in status
type: object
properties:
matchExpressions:
description: matchExpressions is a list of cluster claim selector requirements. The requirements are ANDed.
type: array
items:
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
type: object
required:
- key
- operator
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.
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.
type: array
items:
type: string
labelSelector:
description: LabelSelector represents a selector of ManagedClusters by label
type: object
properties:
matchExpressions:
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
type: array
items:
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
type: object
required:
- key
- operator
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.
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.
type: array
items:
type: string
matchLabels:
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
additionalProperties:
type: string
prioritizerPolicy:
description: PrioritizerPolicy defines the policy of the prioritizers. If this field is unset, then default prioritizer mode and configurations are used. Referring to PrioritizerPolicy to see more description about Mode and Configurations.
type: object
properties:
configurations:
type: array
items:
description: PrioritizerConfig represents the configuration of prioritizer
type: object
required:
- scoreCoordinate
properties:
scoreCoordinate:
description: ScoreCoordinate represents the configuration of the prioritizer and score source.
type: object
required:
- type
properties:
addOn:
description: When type is "AddOn", AddOn defines the resource name and score name.
type: object
required:
- resourceName
- scoreName
properties:
resourceName:
description: ResourceName defines the resource name of the AddOnPlacementScore. The placement prioritizer selects AddOnPlacementScore CR by this name.
type: string
scoreName:
description: ScoreName defines the score name inside AddOnPlacementScore. AddOnPlacementScore contains a list of score name and score value, ScoreName specify the score to be used by the prioritizer.
type: string
builtIn:
description: 'BuiltIn defines the name of a BuiltIn prioritizer. Below are the valid BuiltIn prioritizer names. 1) Balance: balance the decisions among the clusters. 2) Steady: ensure the existing decision is stabilized. 3) ResourceAllocatableCPU & ResourceAllocatableMemory: sort clusters based on the allocatable.'
type: string
type:
description: Type defines the type of the prioritizer score. Type is either "BuiltIn", "AddOn" or "", where "" is "BuiltIn" by default. When the type is "BuiltIn", need to specify a BuiltIn prioritizer name in BuiltIn. When the type is "AddOn", need to configure the score source in AddOn.
type: string
default: BuiltIn
enum:
- BuiltIn
- AddOn
weight:
description: Weight defines the weight of the prioritizer score. The value must be ranged in [-10,10]. Each prioritizer will calculate an integer score of a cluster in the range of [-100, 100]. The final score of a cluster will be sum(weight * prioritizer_score). A higher weight indicates that the prioritizer weights more in the cluster selection, while 0 weight indicates that the prioritizer is disabled. A negative weight indicates wants to select the last ones.
type: integer
format: int32
default: 1
maximum: 10
minimum: -10
mode:
description: Mode is either Exact, Additive, "" where "" is Additive by default. In Additive mode, any prioritizer not explicitly enumerated is enabled in its default Configurations, in which Steady and Balance prioritizers have the weight of 1 while other prioritizers have the weight of 0. Additive doesn't require configuring all prioritizers. The default Configurations may change in the future, and additional prioritization will happen. In Exact mode, any prioritizer not explicitly enumerated is weighted as zero. Exact requires knowing the full set of prioritizers you want, but avoids behavior changes between releases.
type: string
default: Additive
tolerations:
description: Tolerations are applied to placements, and allow (but do not require) the managed clusters with certain taints to be selected by placements with matching tolerations.
type: array
items:
description: Toleration represents the toleration object that can be attached to a placement. The placement this Toleration is attached to tolerates any taint that matches the triple <key,value,effect> using the matching operator <operator>.
type: object
properties:
effect:
description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSelect, PreferNoSelect and NoSelectIfNew.
type: string
enum:
- NoSelect
- PreferNoSelect
- NoSelectIfNew
key:
description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys.
type: string
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
operator:
description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a placement can tolerate all taints of a particular category.
type: string
default: Equal
tolerationSeconds:
description: TolerationSeconds represents the period of time the toleration (which must be of effect NoSelect/PreferNoSelect, otherwise this field is ignored) tolerates the taint. The default value is nil, which indicates it tolerates the taint forever. The start time of counting the TolerationSeconds should be the TimeAdded in Taint, not the cluster scheduled time or TolerationSeconds added time.
type: integer
format: int64
value:
description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string.
type: string
maxLength: 1024
status:
description: Status represents the current status of the Placement
type: object
properties:
conditions:
description: Conditions contains the different condition status for this Placement.
type: array
items:
description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
type: object
required:
- lastTransitionTime
- message
- reason
- status
- type
properties:
lastTransitionTime:
description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
type: string
format: date-time
message:
description: message is a human readable message indicating details about the transition. This may be an empty string.
type: string
maxLength: 32768
observedGeneration:
description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
type: integer
format: int64
minimum: 0
reason:
description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
type: string
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
status:
description: status of the condition, one of True, False, Unknown.
type: string
enum:
- "True"
- "False"
- Unknown
type:
description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
type: string
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
numberOfSelectedClusters:
description: NumberOfSelectedClusters represents the number of selected ManagedClusters
type: integer
format: int32
served: true
storage: true
subresources:
status: {}
@@ -13,6 +13,48 @@ spec:
preserveUnknownFields: false
versions:
- name: v1alpha1
deprecated: true
deprecationWarning: "cluster.open-cluster-management.io/v1alpha1 PlacementDecision is deprecated; use cluster.open-cluster-management.io/v1beta1 PlacementDecision"
schema:
openAPIV3Schema:
description: "PlacementDecision indicates a decision from a placement PlacementDecision should has a label cluster.open-cluster-management.io/placement={placement name} to reference a certain placement. \n If a placement has spec.numberOfClusters specified, the total number of decisions contained in status.decisions of PlacementDecisions should always be NumberOfClusters; otherwise, the total number of decisions should be the number of ManagedClusters which match the placement requirements. \n Some of the decisions might be empty when there are no enough ManagedClusters meet the placement requirements."
type: object
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'
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'
type: string
metadata:
type: object
status:
description: Status represents the current status of the PlacementDecision
type: object
required:
- decisions
properties:
decisions:
description: Decisions is a slice of decisions according to a placement The number of decisions should not be larger than 100
type: array
items:
description: ClusterDecision represents a decision from a placement An empty ClusterDecision indicates it is not scheduled yet.
type: object
required:
- clusterName
- reason
properties:
clusterName:
description: ClusterName is the name of the ManagedCluster. If it is not empty, its value should be unique cross all placement decisions for the Placement.
type: string
reason:
description: Reason represents the reason why the ManagedCluster is selected.
type: string
served: true
storage: false
subresources:
status: {}
- name: v1beta1
schema:
openAPIV3Schema:
description: "PlacementDecision indicates a decision from a placement PlacementDecision should has a label cluster.open-cluster-management.io/placement={placement name} to reference a certain placement. \n If a placement has spec.numberOfClusters specified, the total number of decisions contained in status.decisions of PlacementDecisions should always be NumberOfClusters; otherwise, the total number of decisions should be the number of ManagedClusters which match the placement requirements. \n Some of the decisions might be empty when there are no enough ManagedClusters meet the placement requirements."
@@ -0,0 +1,9 @@
apiVersion: migration.k8s.io/v1alpha1
kind: StorageVersionMigration
metadata:
name: placementdecisions.cluster.open-cluster-management.io
spec:
resource:
group: cluster.open-cluster-management.io
resource: placementdecisions
version: v1alpha1
@@ -0,0 +1,9 @@
apiVersion: migration.k8s.io/v1alpha1
kind: StorageVersionMigration
metadata:
name: placements.cluster.open-cluster-management.io
spec:
resource:
group: cluster.open-cluster-management.io
resource: placements
version: v1alpha1
@@ -44,8 +44,8 @@ var (
"cluster-manager/0000_00_work.open-cluster-management.io_manifestworks.crd.yaml",
"cluster-manager/0000_01_addon.open-cluster-management.io_managedclusteraddons.crd.yaml",
"cluster-manager/0000_01_clusters.open-cluster-management.io_managedclustersetbindings.crd.yaml",
"cluster-manager/0000_03_clusters.open-cluster-management.io_placements.crd.yaml",
"cluster-manager/0000_04_clusters.open-cluster-management.io_placementdecisions.crd.yaml",
"cluster-manager/0000_02_clusters.open-cluster-management.io_placements.crd.yaml",
"cluster-manager/0000_03_clusters.open-cluster-management.io_placementdecisions.crd.yaml",
"cluster-manager/0000_05_clusters.open-cluster-management.io_addonplacementscores.crd.yaml",
"cluster-manager/cluster-manager-registration-clusterrole.yaml",
"cluster-manager/cluster-manager-registration-clusterrolebinding.yaml",
@@ -40,6 +40,8 @@ var (
migrationRequestFiles = []string{
"cluster-manager/cluster-manager-managedclustersets-migration.yaml",
"cluster-manager/cluster-manager-managedclustersetbindings-migration.yaml",
"cluster-manager/cluster-manager-placements-migration.yaml",
"cluster-manager/cluster-manager-placementdecisions-migration.yaml",
}
)
@@ -61,11 +61,15 @@ func TestApplyStorageVersionMigrations(t *testing.T) {
{
name: "created",
validateActions: func(t *testing.T, actions []clienttesting.Action) {
assertActions(t, actions, "get", "create", "get", "create")
assertActions(t, actions, "get", "create", "get", "create", "get", "create", "get", "create")
actual := actions[1].(clienttesting.CreateActionImpl).Object
assertStorageVersionMigration(t, "managedclustersets.cluster.open-cluster-management.io", actual)
actual = actions[3].(clienttesting.CreateActionImpl).Object
assertStorageVersionMigration(t, "managedclustersetbindings.cluster.open-cluster-management.io", actual)
actual = actions[5].(clienttesting.CreateActionImpl).Object
assertStorageVersionMigration(t, "placements.cluster.open-cluster-management.io", actual)
actual = actions[7].(clienttesting.CreateActionImpl).Object
assertStorageVersionMigration(t, "placementdecisions.cluster.open-cluster-management.io", actual)
},
},
{
@@ -76,13 +80,22 @@ func TestApplyStorageVersionMigrations(t *testing.T) {
Name: "managedclustersetbindings.cluster.open-cluster-management.io",
},
},
&migrationv1alpha1.StorageVersionMigration{
ObjectMeta: metav1.ObjectMeta{
Name: "placementdecisions.cluster.open-cluster-management.io",
},
},
},
validateActions: func(t *testing.T, actions []clienttesting.Action) {
assertActions(t, actions, "get", "create", "get", "update")
assertActions(t, actions, "get", "create", "get", "update", "get", "create", "get", "update")
actual := actions[1].(clienttesting.CreateActionImpl).Object
assertStorageVersionMigration(t, "managedclustersets.cluster.open-cluster-management.io", actual)
actual = actions[3].(clienttesting.UpdateActionImpl).Object
assertStorageVersionMigration(t, "managedclustersetbindings.cluster.open-cluster-management.io", actual)
actual = actions[5].(clienttesting.CreateActionImpl).Object
assertStorageVersionMigration(t, "placements.cluster.open-cluster-management.io", actual)
actual = actions[7].(clienttesting.UpdateActionImpl).Object
assertStorageVersionMigration(t, "placementdecisions.cluster.open-cluster-management.io", actual)
},
},
}
@@ -104,6 +117,8 @@ func TestRemoveStorageVersionMigrations(t *testing.T) {
names := []string{
"managedclustersets.cluster.open-cluster-management.io",
"managedclustersetbindings.cluster.open-cluster-management.io",
"placements.cluster.open-cluster-management.io",
"placementdecisions.cluster.open-cluster-management.io",
}
cases := []struct {
name string
@@ -121,6 +136,11 @@ func TestRemoveStorageVersionMigrations(t *testing.T) {
Name: "managedclustersetbindings.cluster.open-cluster-management.io",
},
},
&migrationv1alpha1.StorageVersionMigration{
ObjectMeta: metav1.ObjectMeta{
Name: "placementdecisions.cluster.open-cluster-management.io",
},
},
},
},
}
+7 -8
View File
@@ -12,7 +12,6 @@ import (
"k8s.io/apimachinery/pkg/util/rand"
clusterapiv1 "open-cluster-management.io/api/cluster/v1"
clusterapiv1alpha1 "open-cluster-management.io/api/cluster/v1alpha1"
clusterapiv1beta1 "open-cluster-management.io/api/cluster/v1beta1"
)
@@ -103,19 +102,19 @@ var _ = Describe("Placement", func() {
}
By("Create a placement")
placement := &clusterapiv1alpha1.Placement{
placement := &clusterapiv1beta1.Placement{
ObjectMeta: metav1.ObjectMeta{
Namespace: placementNamespace,
Name: placementName,
},
}
placement, err = t.ClusterClient.ClusterV1alpha1().Placements(placementNamespace).Create(context.TODO(), placement, metav1.CreateOptions{})
placement, err = t.ClusterClient.ClusterV1beta1().Placements(placementNamespace).Create(context.TODO(), placement, metav1.CreateOptions{})
Expect(err).ToNot(HaveOccurred())
By("Check if placementdecisions are created with desired number of decisions")
Eventually(func() bool {
placementDecisions, err := t.ClusterClient.ClusterV1alpha1().PlacementDecisions(placementNamespace).List(context.TODO(), metav1.ListOptions{
placementDecisions, err := t.ClusterClient.ClusterV1beta1().PlacementDecisions(placementNamespace).List(context.TODO(), metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=%s", placementLabel, placementName),
})
if err != nil {
@@ -132,7 +131,7 @@ var _ = Describe("Placement", func() {
By("Check if placement status is updated")
Eventually(func() bool {
placement, err := t.ClusterClient.ClusterV1alpha1().Placements(placementNamespace).Get(context.TODO(), placementName, metav1.GetOptions{})
placement, err := t.ClusterClient.ClusterV1beta1().Placements(placementNamespace).Get(context.TODO(), placementName, metav1.GetOptions{})
if err != nil {
return false
}
@@ -141,16 +140,16 @@ var _ = Describe("Placement", func() {
return false
}
return meta.IsStatusConditionTrue(placement.Status.Conditions, clusterapiv1alpha1.PlacementConditionSatisfied)
return meta.IsStatusConditionTrue(placement.Status.Conditions, clusterapiv1beta1.PlacementConditionSatisfied)
}, t.EventuallyTimeout*5, t.EventuallyInterval*5).Should(BeTrue())
By("Delete placement")
err = t.ClusterClient.ClusterV1alpha1().Placements(placementNamespace).Delete(context.TODO(), placementName, metav1.DeleteOptions{})
err = t.ClusterClient.ClusterV1beta1().Placements(placementNamespace).Delete(context.TODO(), placementName, metav1.DeleteOptions{})
Expect(err).ToNot(HaveOccurred())
By("Check if placementdecisions are deleted as well")
Eventually(func() bool {
placementDecisions, err := t.ClusterClient.ClusterV1alpha1().PlacementDecisions(placementNamespace).List(context.TODO(), metav1.ListOptions{
placementDecisions, err := t.ClusterClient.ClusterV1beta1().PlacementDecisions(placementNamespace).List(context.TODO(), metav1.ListOptions{
LabelSelector: fmt.Sprintf("%s=%s", placementLabel, placementName),
})
if err != nil {
+1 -1
View File
@@ -1047,7 +1047,7 @@ k8s.io/utils/net
k8s.io/utils/path
k8s.io/utils/pointer
k8s.io/utils/trace
# open-cluster-management.io/api v0.5.1-0.20220111063708-e6fd0b245ae9
# open-cluster-management.io/api v0.6.1-0.20220127035449-918b7bf7184f
## explicit; go 1.17
open-cluster-management.io/api/addon/v1alpha1
open-cluster-management.io/api/client/addon/clientset/versioned
@@ -47,6 +47,10 @@ spec:
crdName:
description: crdName is the name of the CRD used to configure instances of the managed add-on. This field should be configured if the add-on have a CRD that controls the configuration of the add-on.
type: string
lastObservedGeneration:
description: lastObservedGeneration is the observed generation of the custom resource for the configuration of the addon.
type: integer
format: int64
addOnMeta:
description: addOnMeta is a reference to the metadata information for the add-on.
type: object
@@ -61,6 +61,10 @@ spec:
crdName:
description: crdName is the name of the CRD used to configure instances of the managed add-on. This field should be configured if the add-on have a CRD that controls the configuration of the add-on.
type: string
lastObservedGeneration:
description: lastObservedGeneration is the observed generation of the custom resource for the configuration of the addon.
type: integer
format: int64
addOnMeta:
description: addOnMeta is a reference to the metadata information for the add-on. This should be same as the addOnMeta for the corresponding ClusterManagementAddOn resource.
type: object
@@ -66,6 +66,10 @@ type ConfigCoordinates struct {
// This field should be configured if add-on CR have a consistent name across the all of the ManagedCluster instaces.
// +optional
CRName string `json:"crName"`
// lastObservedGeneration is the observed generation of the custom resource for the configuration of the addon.
// +optional
LastObservedGeneration int64 `json:"lastObservedGeneration,omitempty"`
}
// ClusterManagementAddOnStatus represents the current status of cluster management add-on.
@@ -60,9 +60,10 @@ func (ClusterManagementAddOnStatus) SwaggerDoc() map[string]string {
}
var map_ConfigCoordinates = map[string]string{
"": "ConfigCoordinates represents the information for locating the CRD and CR that configures the add-on.",
"crdName": "crdName is the name of the CRD used to configure instances of the managed add-on. This field should be configured if the add-on have a CRD that controls the configuration of the add-on.",
"crName": "crName is the name of the CR used to configure instances of the managed add-on. This field should be configured if add-on CR have a consistent name across the all of the ManagedCluster instaces.",
"": "ConfigCoordinates represents the information for locating the CRD and CR that configures the add-on.",
"crdName": "crdName is the name of the CRD used to configure instances of the managed add-on. This field should be configured if the add-on have a CRD that controls the configuration of the add-on.",
"crName": "crName is the name of the CR used to configure instances of the managed add-on. This field should be configured if add-on CR have a consistent name across the all of the ManagedCluster instaces.",
"lastObservedGeneration": "lastObservedGeneration is the observed generation of the custom resource for the configuration of the addon.",
}
func (ConfigCoordinates) SwaggerDoc() map[string]string {
@@ -12,6 +12,8 @@ type ClusterV1beta1Interface interface {
RESTClient() rest.Interface
ManagedClusterSetsGetter
ManagedClusterSetBindingsGetter
PlacementsGetter
PlacementDecisionsGetter
}
// ClusterV1beta1Client is used to interact with features provided by the cluster.open-cluster-management.io group.
@@ -27,6 +29,14 @@ func (c *ClusterV1beta1Client) ManagedClusterSetBindings(namespace string) Manag
return newManagedClusterSetBindings(c, namespace)
}
func (c *ClusterV1beta1Client) Placements(namespace string) PlacementInterface {
return newPlacements(c, namespace)
}
func (c *ClusterV1beta1Client) PlacementDecisions(namespace string) PlacementDecisionInterface {
return newPlacementDecisions(c, namespace)
}
// NewForConfig creates a new ClusterV1beta1Client for the given config.
func NewForConfig(c *rest.Config) (*ClusterV1beta1Client, error) {
config := *c
@@ -5,3 +5,7 @@ package v1beta1
type ManagedClusterSetExpansion interface{}
type ManagedClusterSetBindingExpansion interface{}
type PlacementExpansion interface{}
type PlacementDecisionExpansion interface{}
@@ -0,0 +1,179 @@
// Code generated by client-gen. DO NOT EDIT.
package v1beta1
import (
"context"
"time"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
scheme "open-cluster-management.io/api/client/cluster/clientset/versioned/scheme"
v1beta1 "open-cluster-management.io/api/cluster/v1beta1"
)
// PlacementsGetter has a method to return a PlacementInterface.
// A group's client should implement this interface.
type PlacementsGetter interface {
Placements(namespace string) PlacementInterface
}
// PlacementInterface has methods to work with Placement resources.
type PlacementInterface interface {
Create(ctx context.Context, placement *v1beta1.Placement, opts v1.CreateOptions) (*v1beta1.Placement, error)
Update(ctx context.Context, placement *v1beta1.Placement, opts v1.UpdateOptions) (*v1beta1.Placement, error)
UpdateStatus(ctx context.Context, placement *v1beta1.Placement, opts v1.UpdateOptions) (*v1beta1.Placement, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.Placement, error)
List(ctx context.Context, opts v1.ListOptions) (*v1beta1.PlacementList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Placement, err error)
PlacementExpansion
}
// placements implements PlacementInterface
type placements struct {
client rest.Interface
ns string
}
// newPlacements returns a Placements
func newPlacements(c *ClusterV1beta1Client, namespace string) *placements {
return &placements{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the placement, and returns the corresponding placement object, and an error if there is any.
func (c *placements) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.Placement, err error) {
result = &v1beta1.Placement{}
err = c.client.Get().
Namespace(c.ns).
Resource("placements").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of Placements that match those selectors.
func (c *placements) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.PlacementList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1beta1.PlacementList{}
err = c.client.Get().
Namespace(c.ns).
Resource("placements").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested placements.
func (c *placements) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("placements").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a placement and creates it. Returns the server's representation of the placement, and an error, if there is any.
func (c *placements) Create(ctx context.Context, placement *v1beta1.Placement, opts v1.CreateOptions) (result *v1beta1.Placement, err error) {
result = &v1beta1.Placement{}
err = c.client.Post().
Namespace(c.ns).
Resource("placements").
VersionedParams(&opts, scheme.ParameterCodec).
Body(placement).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a placement and updates it. Returns the server's representation of the placement, and an error, if there is any.
func (c *placements) Update(ctx context.Context, placement *v1beta1.Placement, opts v1.UpdateOptions) (result *v1beta1.Placement, err error) {
result = &v1beta1.Placement{}
err = c.client.Put().
Namespace(c.ns).
Resource("placements").
Name(placement.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(placement).
Do(ctx).
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *placements) UpdateStatus(ctx context.Context, placement *v1beta1.Placement, opts v1.UpdateOptions) (result *v1beta1.Placement, err error) {
result = &v1beta1.Placement{}
err = c.client.Put().
Namespace(c.ns).
Resource("placements").
Name(placement.Name).
SubResource("status").
VersionedParams(&opts, scheme.ParameterCodec).
Body(placement).
Do(ctx).
Into(result)
return
}
// Delete takes name of the placement and deletes it. Returns an error if one occurs.
func (c *placements) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("placements").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *placements) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("placements").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched placement.
func (c *placements) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.Placement, err error) {
result = &v1beta1.Placement{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("placements").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}
@@ -0,0 +1,179 @@
// Code generated by client-gen. DO NOT EDIT.
package v1beta1
import (
"context"
"time"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
rest "k8s.io/client-go/rest"
scheme "open-cluster-management.io/api/client/cluster/clientset/versioned/scheme"
v1beta1 "open-cluster-management.io/api/cluster/v1beta1"
)
// PlacementDecisionsGetter has a method to return a PlacementDecisionInterface.
// A group's client should implement this interface.
type PlacementDecisionsGetter interface {
PlacementDecisions(namespace string) PlacementDecisionInterface
}
// PlacementDecisionInterface has methods to work with PlacementDecision resources.
type PlacementDecisionInterface interface {
Create(ctx context.Context, placementDecision *v1beta1.PlacementDecision, opts v1.CreateOptions) (*v1beta1.PlacementDecision, error)
Update(ctx context.Context, placementDecision *v1beta1.PlacementDecision, opts v1.UpdateOptions) (*v1beta1.PlacementDecision, error)
UpdateStatus(ctx context.Context, placementDecision *v1beta1.PlacementDecision, opts v1.UpdateOptions) (*v1beta1.PlacementDecision, error)
Delete(ctx context.Context, name string, opts v1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error
Get(ctx context.Context, name string, opts v1.GetOptions) (*v1beta1.PlacementDecision, error)
List(ctx context.Context, opts v1.ListOptions) (*v1beta1.PlacementDecisionList, error)
Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.PlacementDecision, err error)
PlacementDecisionExpansion
}
// placementDecisions implements PlacementDecisionInterface
type placementDecisions struct {
client rest.Interface
ns string
}
// newPlacementDecisions returns a PlacementDecisions
func newPlacementDecisions(c *ClusterV1beta1Client, namespace string) *placementDecisions {
return &placementDecisions{
client: c.RESTClient(),
ns: namespace,
}
}
// Get takes name of the placementDecision, and returns the corresponding placementDecision object, and an error if there is any.
func (c *placementDecisions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1beta1.PlacementDecision, err error) {
result = &v1beta1.PlacementDecision{}
err = c.client.Get().
Namespace(c.ns).
Resource("placementdecisions").
Name(name).
VersionedParams(&options, scheme.ParameterCodec).
Do(ctx).
Into(result)
return
}
// List takes label and field selectors, and returns the list of PlacementDecisions that match those selectors.
func (c *placementDecisions) List(ctx context.Context, opts v1.ListOptions) (result *v1beta1.PlacementDecisionList, err error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
result = &v1beta1.PlacementDecisionList{}
err = c.client.Get().
Namespace(c.ns).
Resource("placementdecisions").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Do(ctx).
Into(result)
return
}
// Watch returns a watch.Interface that watches the requested placementDecisions.
func (c *placementDecisions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) {
var timeout time.Duration
if opts.TimeoutSeconds != nil {
timeout = time.Duration(*opts.TimeoutSeconds) * time.Second
}
opts.Watch = true
return c.client.Get().
Namespace(c.ns).
Resource("placementdecisions").
VersionedParams(&opts, scheme.ParameterCodec).
Timeout(timeout).
Watch(ctx)
}
// Create takes the representation of a placementDecision and creates it. Returns the server's representation of the placementDecision, and an error, if there is any.
func (c *placementDecisions) Create(ctx context.Context, placementDecision *v1beta1.PlacementDecision, opts v1.CreateOptions) (result *v1beta1.PlacementDecision, err error) {
result = &v1beta1.PlacementDecision{}
err = c.client.Post().
Namespace(c.ns).
Resource("placementdecisions").
VersionedParams(&opts, scheme.ParameterCodec).
Body(placementDecision).
Do(ctx).
Into(result)
return
}
// Update takes the representation of a placementDecision and updates it. Returns the server's representation of the placementDecision, and an error, if there is any.
func (c *placementDecisions) Update(ctx context.Context, placementDecision *v1beta1.PlacementDecision, opts v1.UpdateOptions) (result *v1beta1.PlacementDecision, err error) {
result = &v1beta1.PlacementDecision{}
err = c.client.Put().
Namespace(c.ns).
Resource("placementdecisions").
Name(placementDecision.Name).
VersionedParams(&opts, scheme.ParameterCodec).
Body(placementDecision).
Do(ctx).
Into(result)
return
}
// UpdateStatus was generated because the type contains a Status member.
// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus().
func (c *placementDecisions) UpdateStatus(ctx context.Context, placementDecision *v1beta1.PlacementDecision, opts v1.UpdateOptions) (result *v1beta1.PlacementDecision, err error) {
result = &v1beta1.PlacementDecision{}
err = c.client.Put().
Namespace(c.ns).
Resource("placementdecisions").
Name(placementDecision.Name).
SubResource("status").
VersionedParams(&opts, scheme.ParameterCodec).
Body(placementDecision).
Do(ctx).
Into(result)
return
}
// Delete takes name of the placementDecision and deletes it. Returns an error if one occurs.
func (c *placementDecisions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error {
return c.client.Delete().
Namespace(c.ns).
Resource("placementdecisions").
Name(name).
Body(&opts).
Do(ctx).
Error()
}
// DeleteCollection deletes a collection of objects.
func (c *placementDecisions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error {
var timeout time.Duration
if listOpts.TimeoutSeconds != nil {
timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second
}
return c.client.Delete().
Namespace(c.ns).
Resource("placementdecisions").
VersionedParams(&listOpts, scheme.ParameterCodec).
Timeout(timeout).
Body(&opts).
Do(ctx).
Error()
}
// Patch applies the patch and returns the patched placementDecision.
func (c *placementDecisions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1beta1.PlacementDecision, err error) {
result = &v1beta1.PlacementDecision{}
err = c.client.Patch(pt).
Namespace(c.ns).
Resource("placementdecisions").
Name(name).
SubResource(subresources...).
VersionedParams(&opts, scheme.ParameterCodec).
Body(data).
Do(ctx).
Into(result)
return
}
+2
View File
@@ -440,6 +440,8 @@ const (
// A placement is not satisfied only if there is empty ClusterDecision in the status.decisions
// of PlacementDecisions.
PlacementConditionSatisfied string = "PlacementSatisfied"
// PlacementConditionMisconfigured means Placement configuration is incorrect.
PlacementConditionMisconfigured string = "PlacementMisconfigured"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
@@ -0,0 +1,511 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: placements.cluster.open-cluster-management.io
spec:
group: cluster.open-cluster-management.io
names:
kind: Placement
listKind: PlacementList
plural: placements
singular: placement
scope: Namespaced
preserveUnknownFields: false
versions:
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=="PlacementSatisfied")].status
name: Succeeded
type: string
- jsonPath: .status.conditions[?(@.type=="PlacementSatisfied")].reason
name: Reason
type: string
- jsonPath: .status.numberOfSelectedClusters
name: SelectedClusters
type: integer
name: v1alpha1
deprecated: true
deprecationWarning: "cluster.open-cluster-management.io/v1alpha1 Placement is deprecated; use cluster.open-cluster-management.io/v1beta1 Placement"
schema:
openAPIV3Schema:
description: "Placement defines a rule to select a set of ManagedClusters from the ManagedClusterSets bound to the placement namespace. \n Here is how the placement policy combines with other selection methods to determine a matching list of ManagedClusters: 1) Kubernetes clusters are registered with hub as cluster-scoped ManagedClusters; 2) ManagedClusters are organized into cluster-scoped ManagedClusterSets; 3) ManagedClusterSets are bound to workload namespaces; 4) Namespace-scoped Placements specify a slice of ManagedClusterSets which select a working set of potential ManagedClusters; 5) Then Placements subselect from that working set using label/claim selection. \n No ManagedCluster will be selected if no ManagedClusterSet is bound to the placement namespace. User is able to bind a ManagedClusterSet to a namespace by creating a ManagedClusterSetBinding in that namespace if they have a RBAC rule to CREATE on the virtual subresource of `managedclustersets/bind`. \n A slice of PlacementDecisions with label cluster.open-cluster-management.io/placement={placement name} will be created to represent the ManagedClusters selected by this placement. \n If a ManagedCluster is selected and added into the PlacementDecisions, other components may apply workload on it; once it is removed from the PlacementDecisions, the workload applied on this ManagedCluster should be evicted accordingly."
type: object
required:
- spec
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'
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'
type: string
metadata:
type: object
spec:
description: Spec defines the attributes of Placement.
type: object
properties:
clusterSets:
description: ClusterSets represent the ManagedClusterSets from which the ManagedClusters are selected. If the slice is empty, ManagedClusters will be selected from the ManagedClusterSets bound to the placement namespace, otherwise ManagedClusters will be selected from the intersection of this slice and the ManagedClusterSets bound to the placement namespace.
type: array
items:
type: string
numberOfClusters:
description: NumberOfClusters represents the desired number of ManagedClusters to be selected which meet the placement requirements. 1) If not specified, all ManagedClusters which meet the placement requirements (including ClusterSets, and Predicates) will be selected; 2) Otherwise if the nubmer of ManagedClusters meet the placement requirements is larger than NumberOfClusters, a random subset with desired number of ManagedClusters will be selected; 3) If the nubmer of ManagedClusters meet the placement requirements is equal to NumberOfClusters, all of them will be selected; 4) If the nubmer of ManagedClusters meet the placement requirements is less than NumberOfClusters, all of them will be selected, and the status of condition `PlacementConditionSatisfied` will be set to false;
type: integer
format: int32
predicates:
description: Predicates represent a slice of predicates to select ManagedClusters. The predicates are ORed.
type: array
items:
description: ClusterPredicate represents a predicate to select ManagedClusters.
type: object
properties:
requiredClusterSelector:
description: RequiredClusterSelector represents a selector of ManagedClusters by label and claim. If specified, 1) Any ManagedCluster, which does not match the selector, should not be selected by this ClusterPredicate; 2) If a selected ManagedCluster (of this ClusterPredicate) ceases to match the selector (e.g. due to an update) of any ClusterPredicate, it will be eventually removed from the placement decisions; 3) If a ManagedCluster (not selected previously) starts to match the selector, it will either be selected or at least has a chance to be selected (when NumberOfClusters is specified);
type: object
properties:
claimSelector:
description: ClaimSelector represents a selector of ManagedClusters by clusterClaims in status
type: object
properties:
matchExpressions:
description: matchExpressions is a list of cluster claim selector requirements. The requirements are ANDed.
type: array
items:
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
type: object
required:
- key
- operator
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.
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.
type: array
items:
type: string
labelSelector:
description: LabelSelector represents a selector of ManagedClusters by label
type: object
properties:
matchExpressions:
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
type: array
items:
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
type: object
required:
- key
- operator
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.
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.
type: array
items:
type: string
matchLabels:
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
additionalProperties:
type: string
prioritizerPolicy:
description: PrioritizerPolicy defines the policy of the prioritizers. If this field is unset, then default prioritizer mode and configurations are used. Referring to PrioritizerPolicy to see more description about Mode and Configurations.
type: object
properties:
configurations:
type: array
items:
description: PrioritizerConfig represents the configuration of prioritizer
type: object
properties:
name:
description: 'Name will be removed in v1beta1 and replaced by ScoreCoordinate.BuiltIn. If both Name and ScoreCoordinate.BuiltIn are defined, will use the value in ScoreCoordinate.BuiltIn. Name is the name of a prioritizer. Below are the valid names: 1) Balance: balance the decisions among the clusters. 2) Steady: ensure the existing decision is stabilized. 3) ResourceAllocatableCPU & ResourceAllocatableMemory: sort clusters based on the allocatable.'
type: string
scoreCoordinate:
description: ScoreCoordinate represents the configuration of the prioritizer and score source.
type: object
required:
- type
properties:
addOn:
description: When type is "AddOn", AddOn defines the resource name and score name.
type: object
required:
- resourceName
- scoreName
properties:
resourceName:
description: ResourceName defines the resource name of the AddOnPlacementScore. The placement prioritizer selects AddOnPlacementScore CR by this name.
type: string
scoreName:
description: ScoreName defines the score name inside AddOnPlacementScore. AddOnPlacementScore contains a list of score name and score value, ScoreName specify the score to be used by the prioritizer.
type: string
builtIn:
description: 'BuiltIn defines the name of a BuiltIn prioritizer. Below are the valid BuiltIn prioritizer names. 1) Balance: balance the decisions among the clusters. 2) Steady: ensure the existing decision is stabilized. 3) ResourceAllocatableCPU & ResourceAllocatableMemory: sort clusters based on the allocatable.'
type: string
type:
description: Type defines the type of the prioritizer score. Type is either "BuiltIn", "AddOn" or "", where "" is "BuiltIn" by default. When the type is "BuiltIn", need to specify a BuiltIn prioritizer name in BuiltIn. When the type is "AddOn", need to configure the score source in AddOn.
type: string
default: BuiltIn
enum:
- BuiltIn
- AddOn
weight:
description: Weight defines the weight of the prioritizer score. The value must be ranged in [-10,10]. Each prioritizer will calculate an integer score of a cluster in the range of [-100, 100]. The final score of a cluster will be sum(weight * prioritizer_score). A higher weight indicates that the prioritizer weights more in the cluster selection, while 0 weight indicates that the prioritizer is disabled. A negative weight indicates wants to select the last ones.
type: integer
format: int32
default: 1
maximum: 10
minimum: -10
mode:
description: Mode is either Exact, Additive, "" where "" is Additive by default. In Additive mode, any prioritizer not explicitly enumerated is enabled in its default Configurations, in which Steady and Balance prioritizers have the weight of 1 while other prioritizers have the weight of 0. Additive doesn't require configuring all prioritizers. The default Configurations may change in the future, and additional prioritization will happen. In Exact mode, any prioritizer not explicitly enumerated is weighted as zero. Exact requires knowing the full set of prioritizers you want, but avoids behavior changes between releases.
type: string
default: Additive
tolerations:
description: Tolerations are applied to placements, and allow (but do not require) the managed clusters with certain taints to be selected by placements with matching tolerations.
type: array
items:
description: Toleration represents the toleration object that can be attached to a placement. The placement this Toleration is attached to tolerates any taint that matches the triple <key,value,effect> using the matching operator <operator>.
type: object
properties:
effect:
description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSelect, PreferNoSelect and NoSelectIfNew.
type: string
enum:
- NoSelect
- PreferNoSelect
- NoSelectIfNew
key:
description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys.
type: string
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
operator:
description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a placement can tolerate all taints of a particular category.
type: string
default: Equal
tolerationSeconds:
description: TolerationSeconds represents the period of time the toleration (which must be of effect NoSelect/PreferNoSelect, otherwise this field is ignored) tolerates the taint. The default value is nil, which indicates it tolerates the taint forever. The start time of counting the TolerationSeconds should be the TimeAdded in Taint, not the cluster scheduled time or TolerationSeconds added time.
type: integer
format: int64
value:
description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string.
type: string
maxLength: 1024
status:
description: Status represents the current status of the Placement
type: object
properties:
conditions:
description: Conditions contains the different condition status for this Placement.
type: array
items:
description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
type: object
required:
- lastTransitionTime
- message
- reason
- status
- type
properties:
lastTransitionTime:
description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
type: string
format: date-time
message:
description: message is a human readable message indicating details about the transition. This may be an empty string.
type: string
maxLength: 32768
observedGeneration:
description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
type: integer
format: int64
minimum: 0
reason:
description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
type: string
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
status:
description: status of the condition, one of True, False, Unknown.
type: string
enum:
- "True"
- "False"
- Unknown
type:
description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
type: string
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
numberOfSelectedClusters:
description: NumberOfSelectedClusters represents the number of selected ManagedClusters
type: integer
format: int32
served: true
storage: false
subresources:
status: {}
- additionalPrinterColumns:
- jsonPath: .status.conditions[?(@.type=="PlacementSatisfied")].status
name: Succeeded
type: string
- jsonPath: .status.conditions[?(@.type=="PlacementSatisfied")].reason
name: Reason
type: string
- jsonPath: .status.numberOfSelectedClusters
name: SelectedClusters
type: integer
name: v1beta1
schema:
openAPIV3Schema:
description: "Placement defines a rule to select a set of ManagedClusters from the ManagedClusterSets bound to the placement namespace. \n Here is how the placement policy combines with other selection methods to determine a matching list of ManagedClusters: 1) Kubernetes clusters are registered with hub as cluster-scoped ManagedClusters; 2) ManagedClusters are organized into cluster-scoped ManagedClusterSets; 3) ManagedClusterSets are bound to workload namespaces; 4) Namespace-scoped Placements specify a slice of ManagedClusterSets which select a working set of potential ManagedClusters; 5) Then Placements subselect from that working set using label/claim selection. \n No ManagedCluster will be selected if no ManagedClusterSet is bound to the placement namespace. User is able to bind a ManagedClusterSet to a namespace by creating a ManagedClusterSetBinding in that namespace if they have a RBAC rule to CREATE on the virtual subresource of `managedclustersets/bind`. \n A slice of PlacementDecisions with label cluster.open-cluster-management.io/placement={placement name} will be created to represent the ManagedClusters selected by this placement. \n If a ManagedCluster is selected and added into the PlacementDecisions, other components may apply workload on it; once it is removed from the PlacementDecisions, the workload applied on this ManagedCluster should be evicted accordingly."
type: object
required:
- spec
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'
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'
type: string
metadata:
type: object
spec:
description: Spec defines the attributes of Placement.
type: object
properties:
clusterSets:
description: ClusterSets represent the ManagedClusterSets from which the ManagedClusters are selected. If the slice is empty, ManagedClusters will be selected from the ManagedClusterSets bound to the placement namespace, otherwise ManagedClusters will be selected from the intersection of this slice and the ManagedClusterSets bound to the placement namespace.
type: array
items:
type: string
numberOfClusters:
description: NumberOfClusters represents the desired number of ManagedClusters to be selected which meet the placement requirements. 1) If not specified, all ManagedClusters which meet the placement requirements (including ClusterSets, and Predicates) will be selected; 2) Otherwise if the nubmer of ManagedClusters meet the placement requirements is larger than NumberOfClusters, a random subset with desired number of ManagedClusters will be selected; 3) If the nubmer of ManagedClusters meet the placement requirements is equal to NumberOfClusters, all of them will be selected; 4) If the nubmer of ManagedClusters meet the placement requirements is less than NumberOfClusters, all of them will be selected, and the status of condition `PlacementConditionSatisfied` will be set to false;
type: integer
format: int32
predicates:
description: Predicates represent a slice of predicates to select ManagedClusters. The predicates are ORed.
type: array
items:
description: ClusterPredicate represents a predicate to select ManagedClusters.
type: object
properties:
requiredClusterSelector:
description: RequiredClusterSelector represents a selector of ManagedClusters by label and claim. If specified, 1) Any ManagedCluster, which does not match the selector, should not be selected by this ClusterPredicate; 2) If a selected ManagedCluster (of this ClusterPredicate) ceases to match the selector (e.g. due to an update) of any ClusterPredicate, it will be eventually removed from the placement decisions; 3) If a ManagedCluster (not selected previously) starts to match the selector, it will either be selected or at least has a chance to be selected (when NumberOfClusters is specified);
type: object
properties:
claimSelector:
description: ClaimSelector represents a selector of ManagedClusters by clusterClaims in status
type: object
properties:
matchExpressions:
description: matchExpressions is a list of cluster claim selector requirements. The requirements are ANDed.
type: array
items:
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
type: object
required:
- key
- operator
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.
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.
type: array
items:
type: string
labelSelector:
description: LabelSelector represents a selector of ManagedClusters by label
type: object
properties:
matchExpressions:
description: matchExpressions is a list of label selector requirements. The requirements are ANDed.
type: array
items:
description: A label selector requirement is a selector that contains values, a key, and an operator that relates the key and values.
type: object
required:
- key
- operator
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.
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.
type: array
items:
type: string
matchLabels:
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
additionalProperties:
type: string
prioritizerPolicy:
description: PrioritizerPolicy defines the policy of the prioritizers. If this field is unset, then default prioritizer mode and configurations are used. Referring to PrioritizerPolicy to see more description about Mode and Configurations.
type: object
properties:
configurations:
type: array
items:
description: PrioritizerConfig represents the configuration of prioritizer
type: object
required:
- scoreCoordinate
properties:
scoreCoordinate:
description: ScoreCoordinate represents the configuration of the prioritizer and score source.
type: object
required:
- type
properties:
addOn:
description: When type is "AddOn", AddOn defines the resource name and score name.
type: object
required:
- resourceName
- scoreName
properties:
resourceName:
description: ResourceName defines the resource name of the AddOnPlacementScore. The placement prioritizer selects AddOnPlacementScore CR by this name.
type: string
scoreName:
description: ScoreName defines the score name inside AddOnPlacementScore. AddOnPlacementScore contains a list of score name and score value, ScoreName specify the score to be used by the prioritizer.
type: string
builtIn:
description: 'BuiltIn defines the name of a BuiltIn prioritizer. Below are the valid BuiltIn prioritizer names. 1) Balance: balance the decisions among the clusters. 2) Steady: ensure the existing decision is stabilized. 3) ResourceAllocatableCPU & ResourceAllocatableMemory: sort clusters based on the allocatable.'
type: string
type:
description: Type defines the type of the prioritizer score. Type is either "BuiltIn", "AddOn" or "", where "" is "BuiltIn" by default. When the type is "BuiltIn", need to specify a BuiltIn prioritizer name in BuiltIn. When the type is "AddOn", need to configure the score source in AddOn.
type: string
default: BuiltIn
enum:
- BuiltIn
- AddOn
weight:
description: Weight defines the weight of the prioritizer score. The value must be ranged in [-10,10]. Each prioritizer will calculate an integer score of a cluster in the range of [-100, 100]. The final score of a cluster will be sum(weight * prioritizer_score). A higher weight indicates that the prioritizer weights more in the cluster selection, while 0 weight indicates that the prioritizer is disabled. A negative weight indicates wants to select the last ones.
type: integer
format: int32
default: 1
maximum: 10
minimum: -10
mode:
description: Mode is either Exact, Additive, "" where "" is Additive by default. In Additive mode, any prioritizer not explicitly enumerated is enabled in its default Configurations, in which Steady and Balance prioritizers have the weight of 1 while other prioritizers have the weight of 0. Additive doesn't require configuring all prioritizers. The default Configurations may change in the future, and additional prioritization will happen. In Exact mode, any prioritizer not explicitly enumerated is weighted as zero. Exact requires knowing the full set of prioritizers you want, but avoids behavior changes between releases.
type: string
default: Additive
tolerations:
description: Tolerations are applied to placements, and allow (but do not require) the managed clusters with certain taints to be selected by placements with matching tolerations.
type: array
items:
description: Toleration represents the toleration object that can be attached to a placement. The placement this Toleration is attached to tolerates any taint that matches the triple <key,value,effect> using the matching operator <operator>.
type: object
properties:
effect:
description: Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSelect, PreferNoSelect and NoSelectIfNew.
type: string
enum:
- NoSelect
- PreferNoSelect
- NoSelectIfNew
key:
description: Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys.
type: string
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
operator:
description: Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a placement can tolerate all taints of a particular category.
type: string
default: Equal
tolerationSeconds:
description: TolerationSeconds represents the period of time the toleration (which must be of effect NoSelect/PreferNoSelect, otherwise this field is ignored) tolerates the taint. The default value is nil, which indicates it tolerates the taint forever. The start time of counting the TolerationSeconds should be the TimeAdded in Taint, not the cluster scheduled time or TolerationSeconds added time.
type: integer
format: int64
value:
description: Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string.
type: string
maxLength: 1024
status:
description: Status represents the current status of the Placement
type: object
properties:
conditions:
description: Conditions contains the different condition status for this Placement.
type: array
items:
description: "Condition contains details for one aspect of the current state of this API Resource. --- This struct is intended for direct use as an array at the field path .status.conditions. For example, type FooStatus struct{ // Represents the observations of a foo's current state. // Known .status.conditions.type are: \"Available\", \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge // +listType=map // +listMapKey=type Conditions []metav1.Condition `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }"
type: object
required:
- lastTransitionTime
- message
- reason
- status
- type
properties:
lastTransitionTime:
description: lastTransitionTime is the last time the condition transitioned from one status to another. This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable.
type: string
format: date-time
message:
description: message is a human readable message indicating details about the transition. This may be an empty string.
type: string
maxLength: 32768
observedGeneration:
description: observedGeneration represents the .metadata.generation that the condition was set based upon. For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date with respect to the current state of the instance.
type: integer
format: int64
minimum: 0
reason:
description: reason contains a programmatic identifier indicating the reason for the condition's last transition. Producers of specific condition types may define expected values and meanings for this field, and whether the values are considered a guaranteed API. The value should be a CamelCase string. This field may not be empty.
type: string
maxLength: 1024
minLength: 1
pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$
status:
description: status of the condition, one of True, False, Unknown.
type: string
enum:
- "True"
- "False"
- Unknown
type:
description: type of condition in CamelCase or in foo.example.com/CamelCase. --- Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be useful (see .node.status.conditions), the ability to deconflict is important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt)
type: string
maxLength: 316
pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$
numberOfSelectedClusters:
description: NumberOfSelectedClusters represents the number of selected ManagedClusters
type: integer
format: int32
served: true
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
@@ -0,0 +1,102 @@
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: placementdecisions.cluster.open-cluster-management.io
spec:
group: cluster.open-cluster-management.io
names:
kind: PlacementDecision
listKind: PlacementDecisionList
plural: placementdecisions
singular: placementdecision
scope: Namespaced
preserveUnknownFields: false
versions:
- name: v1alpha1
deprecated: true
deprecationWarning: "cluster.open-cluster-management.io/v1alpha1 PlacementDecision is deprecated; use cluster.open-cluster-management.io/v1beta1 PlacementDecision"
schema:
openAPIV3Schema:
description: "PlacementDecision indicates a decision from a placement PlacementDecision should has a label cluster.open-cluster-management.io/placement={placement name} to reference a certain placement. \n If a placement has spec.numberOfClusters specified, the total number of decisions contained in status.decisions of PlacementDecisions should always be NumberOfClusters; otherwise, the total number of decisions should be the number of ManagedClusters which match the placement requirements. \n Some of the decisions might be empty when there are no enough ManagedClusters meet the placement requirements."
type: object
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'
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'
type: string
metadata:
type: object
status:
description: Status represents the current status of the PlacementDecision
type: object
required:
- decisions
properties:
decisions:
description: Decisions is a slice of decisions according to a placement The number of decisions should not be larger than 100
type: array
items:
description: ClusterDecision represents a decision from a placement An empty ClusterDecision indicates it is not scheduled yet.
type: object
required:
- clusterName
- reason
properties:
clusterName:
description: ClusterName is the name of the ManagedCluster. If it is not empty, its value should be unique cross all placement decisions for the Placement.
type: string
reason:
description: Reason represents the reason why the ManagedCluster is selected.
type: string
served: true
storage: false
subresources:
status: {}
- name: v1beta1
schema:
openAPIV3Schema:
description: "PlacementDecision indicates a decision from a placement PlacementDecision should has a label cluster.open-cluster-management.io/placement={placement name} to reference a certain placement. \n If a placement has spec.numberOfClusters specified, the total number of decisions contained in status.decisions of PlacementDecisions should always be NumberOfClusters; otherwise, the total number of decisions should be the number of ManagedClusters which match the placement requirements. \n Some of the decisions might be empty when there are no enough ManagedClusters meet the placement requirements."
type: object
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'
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'
type: string
metadata:
type: object
status:
description: Status represents the current status of the PlacementDecision
type: object
required:
- decisions
properties:
decisions:
description: Decisions is a slice of decisions according to a placement The number of decisions should not be larger than 100
type: array
items:
description: ClusterDecision represents a decision from a placement An empty ClusterDecision indicates it is not scheduled yet.
type: object
required:
- clusterName
- reason
properties:
clusterName:
description: ClusterName is the name of the ManagedCluster. If it is not empty, its value should be unique cross all placement decisions for the Placement.
type: string
reason:
description: Reason represents the reason why the ManagedCluster is selected.
type: string
served: true
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
+4
View File
@@ -34,6 +34,10 @@ func addKnownTypes(scheme *runtime.Scheme) error {
&ManagedClusterSetList{},
&ManagedClusterSetBinding{},
&ManagedClusterSetBindingList{},
&Placement{},
&PlacementList{},
&PlacementDecision{},
&PlacementDecisionList{},
)
metav1.AddToGroupVersion(scheme, GroupVersion)
return nil
@@ -0,0 +1,294 @@
package v1beta1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "open-cluster-management.io/api/cluster/v1"
)
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:resource:scope="Namespaced"
// +kubebuilder:subresource:status
// +kubebuilder:printcolumn:name="Succeeded",type="string",JSONPath=".status.conditions[?(@.type==\"PlacementSatisfied\")].status"
// +kubebuilder:printcolumn:name="Reason",type="string",JSONPath=".status.conditions[?(@.type==\"PlacementSatisfied\")].reason"
// +kubebuilder:printcolumn:name="SelectedClusters",type="integer",JSONPath=".status.numberOfSelectedClusters"
// Placement defines a rule to select a set of ManagedClusters from the ManagedClusterSets bound
// to the placement namespace.
//
// Here is how the placement policy combines with other selection methods to determine a matching
// list of ManagedClusters:
// 1) Kubernetes clusters are registered with hub as cluster-scoped ManagedClusters;
// 2) ManagedClusters are organized into cluster-scoped ManagedClusterSets;
// 3) ManagedClusterSets are bound to workload namespaces;
// 4) Namespace-scoped Placements specify a slice of ManagedClusterSets which select a working set
// of potential ManagedClusters;
// 5) Then Placements subselect from that working set using label/claim selection.
//
// No ManagedCluster will be selected if no ManagedClusterSet is bound to the placement
// namespace. User is able to bind a ManagedClusterSet to a namespace by creating a
// ManagedClusterSetBinding in that namespace if they have a RBAC rule to CREATE on the virtual
// subresource of `managedclustersets/bind`.
//
// A slice of PlacementDecisions with label cluster.open-cluster-management.io/placement={placement name}
// will be created to represent the ManagedClusters selected by this placement.
//
// If a ManagedCluster is selected and added into the PlacementDecisions, other components may
// apply workload on it; once it is removed from the PlacementDecisions, the workload applied on
// this ManagedCluster should be evicted accordingly.
type Placement struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// Spec defines the attributes of Placement.
// +kubebuilder:validation:Required
// +required
Spec PlacementSpec `json:"spec"`
// Status represents the current status of the Placement
// +optional
Status PlacementStatus `json:"status,omitempty"`
}
// PlacementSpec defines the attributes of Placement.
// An empty PlacementSpec selects all ManagedClusters from the ManagedClusterSets bound to
// the placement namespace. The containing fields are ANDed.
type PlacementSpec struct {
// ClusterSets represent the ManagedClusterSets from which the ManagedClusters are selected.
// If the slice is empty, ManagedClusters will be selected from the ManagedClusterSets bound to the placement
// namespace, otherwise ManagedClusters will be selected from the intersection of this slice and the
// ManagedClusterSets bound to the placement namespace.
// +optional
ClusterSets []string `json:"clusterSets,omitempty"`
// NumberOfClusters represents the desired number of ManagedClusters to be selected which meet the
// placement requirements.
// 1) If not specified, all ManagedClusters which meet the placement requirements (including ClusterSets,
// and Predicates) will be selected;
// 2) Otherwise if the nubmer of ManagedClusters meet the placement requirements is larger than
// NumberOfClusters, a random subset with desired number of ManagedClusters will be selected;
// 3) If the nubmer of ManagedClusters meet the placement requirements is equal to NumberOfClusters,
// all of them will be selected;
// 4) If the nubmer of ManagedClusters meet the placement requirements is less than NumberOfClusters,
// all of them will be selected, and the status of condition `PlacementConditionSatisfied` will be
// set to false;
// +optional
NumberOfClusters *int32 `json:"numberOfClusters,omitempty"`
// Predicates represent a slice of predicates to select ManagedClusters. The predicates are ORed.
// +optional
Predicates []ClusterPredicate `json:"predicates,omitempty"`
// PrioritizerPolicy defines the policy of the prioritizers.
// If this field is unset, then default prioritizer mode and configurations are used.
// Referring to PrioritizerPolicy to see more description about Mode and Configurations.
// +optional
PrioritizerPolicy PrioritizerPolicy `json:"prioritizerPolicy"`
// Tolerations are applied to placements, and allow (but do not require) the managed clusters with
// certain taints to be selected by placements with matching tolerations.
// +optional
Tolerations []Toleration `json:"tolerations,omitempty"`
}
// ClusterPredicate represents a predicate to select ManagedClusters.
type ClusterPredicate struct {
// RequiredClusterSelector represents a selector of ManagedClusters by label and claim. If specified,
// 1) Any ManagedCluster, which does not match the selector, should not be selected by this ClusterPredicate;
// 2) If a selected ManagedCluster (of this ClusterPredicate) ceases to match the selector (e.g. due to
// an update) of any ClusterPredicate, it will be eventually removed from the placement decisions;
// 3) If a ManagedCluster (not selected previously) starts to match the selector, it will either
// be selected or at least has a chance to be selected (when NumberOfClusters is specified);
// +optional
RequiredClusterSelector ClusterSelector `json:"requiredClusterSelector,omitempty"`
}
// ClusterSelector represents the AND of the containing selectors. An empty cluster selector matches all objects.
// A null cluster selector matches no objects.
type ClusterSelector struct {
// LabelSelector represents a selector of ManagedClusters by label
// +optional
LabelSelector metav1.LabelSelector `json:"labelSelector,omitempty"`
// ClaimSelector represents a selector of ManagedClusters by clusterClaims in status
// +optional
ClaimSelector ClusterClaimSelector `json:"claimSelector,omitempty"`
}
// ClusterClaimSelector is a claim query over a set of ManagedClusters. An empty cluster claim
// selector matches all objects. A null cluster claim selector matches no objects.
type ClusterClaimSelector struct {
// matchExpressions is a list of cluster claim selector requirements. The requirements are ANDed.
// +optional
MatchExpressions []metav1.LabelSelectorRequirement `json:"matchExpressions,omitempty"`
}
// PrioritizerPolicy represents the policy of prioritizer
type PrioritizerPolicy struct {
// Mode is either Exact, Additive, "" where "" is Additive by default.
// In Additive mode, any prioritizer not explicitly enumerated is enabled in its default Configurations,
// in which Steady and Balance prioritizers have the weight of 1 while other prioritizers have the weight of 0.
// Additive doesn't require configuring all prioritizers. The default Configurations may change in the future,
// and additional prioritization will happen.
// In Exact mode, any prioritizer not explicitly enumerated is weighted as zero.
// Exact requires knowing the full set of prioritizers you want, but avoids behavior changes between releases.
// +kubebuilder:default:=Additive
// +optional
Mode PrioritizerPolicyModeType `json:"mode,omitempty"`
// +optional
Configurations []PrioritizerConfig `json:"configurations,omitempty"`
}
// PrioritizerPolicyModeType represents the type of PrioritizerPolicy.Mode
type PrioritizerPolicyModeType string
const (
// Valid PrioritizerPolicyModeType value is Exact, Additive.
PrioritizerPolicyModeAdditive PrioritizerPolicyModeType = "Additive"
PrioritizerPolicyModeExact PrioritizerPolicyModeType = "Exact"
)
// PrioritizerConfig represents the configuration of prioritizer
type PrioritizerConfig struct {
// ScoreCoordinate represents the configuration of the prioritizer and score source.
// +kubebuilder:validation:Required
// +required
ScoreCoordinate *ScoreCoordinate `json:"scoreCoordinate,omitempty"`
// Weight defines the weight of the prioritizer score. The value must be ranged in [-10,10].
// Each prioritizer will calculate an integer score of a cluster in the range of [-100, 100].
// The final score of a cluster will be sum(weight * prioritizer_score).
// A higher weight indicates that the prioritizer weights more in the cluster selection,
// while 0 weight indicates that the prioritizer is disabled. A negative weight indicates
// wants to select the last ones.
// +kubebuilder:validation:Minimum:=-10
// +kubebuilder:validation:Maximum:=10
// +kubebuilder:default:=1
// +optional
Weight int32 `json:"weight,omitempty"`
}
// ScoreCoordinate represents the configuration of the score type and score source
type ScoreCoordinate struct {
// Type defines the type of the prioritizer score.
// Type is either "BuiltIn", "AddOn" or "", where "" is "BuiltIn" by default.
// When the type is "BuiltIn", need to specify a BuiltIn prioritizer name in BuiltIn.
// When the type is "AddOn", need to configure the score source in AddOn.
// +kubebuilder:validation:Required
// +kubebuilder:validation:Enum=BuiltIn;AddOn
// +kubebuilder:default:=BuiltIn
// +required
Type string `json:"type,omitempty"`
// BuiltIn defines the name of a BuiltIn prioritizer. Below are the valid BuiltIn prioritizer names.
// 1) Balance: balance the decisions among the clusters.
// 2) Steady: ensure the existing decision is stabilized.
// 3) ResourceAllocatableCPU & ResourceAllocatableMemory: sort clusters based on the allocatable.
// +optional
BuiltIn string `json:"builtIn,omitempty"`
// When type is "AddOn", AddOn defines the resource name and score name.
// +optional
AddOn *AddOnScore `json:"addOn,omitempty"`
}
const (
// Valid ScoreCoordinate type is BuiltIn, AddOn.
ScoreCoordinateTypeBuiltIn string = "BuiltIn"
ScoreCoordinateTypeAddOn string = "AddOn"
)
// AddOnScore represents the configuration of the addon score source.
type AddOnScore struct {
// ResourceName defines the resource name of the AddOnPlacementScore.
// The placement prioritizer selects AddOnPlacementScore CR by this name.
// +kubebuilder:validation:Required
// +required
ResourceName string `json:"resourceName"`
// ScoreName defines the score name inside AddOnPlacementScore.
// AddOnPlacementScore contains a list of score name and score value, ScoreName specify the score to be used by
// the prioritizer.
// +kubebuilder:validation:Required
// +required
ScoreName string `json:"scoreName"`
}
// Toleration represents the toleration object that can be attached to a placement.
// The placement this Toleration is attached to tolerates any taint that matches
// the triple <key,value,effect> using the matching operator <operator>.
type Toleration struct {
// Key is the taint key that the toleration applies to. Empty means match all taint keys.
// If the key is empty, operator must be Exists; this combination means to match all values and all keys.
// +kubebuilder:validation:Pattern=`^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$`
// +kubebuilder:validation:MaxLength=316
// +optional
Key string `json:"key,omitempty"`
// Operator represents a key's relationship to the value.
// Valid operators are Exists and Equal. Defaults to Equal.
// Exists is equivalent to wildcard for value, so that a placement can
// tolerate all taints of a particular category.
// +kubebuilder:default:="Equal"
// +optional
Operator TolerationOperator `json:"operator,omitempty"`
// Value is the taint value the toleration matches to.
// If the operator is Exists, the value should be empty, otherwise just a regular string.
// +kubebuilder:validation:MaxLength=1024
// +optional
Value string `json:"value,omitempty"`
// Effect indicates the taint effect to match. Empty means match all taint effects.
// When specified, allowed values are NoSelect, PreferNoSelect and NoSelectIfNew.
// +kubebuilder:validation:Enum:=NoSelect;PreferNoSelect;NoSelectIfNew
// +optional
Effect v1.TaintEffect `json:"effect,omitempty"`
// TolerationSeconds represents the period of time the toleration (which must be of effect
// NoSelect/PreferNoSelect, otherwise this field is ignored) tolerates the taint.
// The default value is nil, which indicates it tolerates the taint forever.
// The start time of counting the TolerationSeconds should be the TimeAdded in Taint, not the cluster
// scheduled time or TolerationSeconds added time.
// +optional
TolerationSeconds *int64 `json:"tolerationSeconds,omitempty"`
}
// TolerationOperator is the set of operators that can be used in a toleration.
type TolerationOperator string
// These are valid values for TolerationOperator
const (
TolerationOpExists TolerationOperator = "Exists"
TolerationOpEqual TolerationOperator = "Equal"
)
type PlacementStatus struct {
// NumberOfSelectedClusters represents the number of selected ManagedClusters
// +optional
NumberOfSelectedClusters int32 `json:"numberOfSelectedClusters"`
// Conditions contains the different condition status for this Placement.
// +optional
Conditions []metav1.Condition `json:"conditions"`
}
const (
// PlacementConditionSatisfied means Placement requirements are satisfied.
// A placement is not satisfied only if there is empty ClusterDecision in the status.decisions
// of PlacementDecisions.
PlacementConditionSatisfied string = "PlacementSatisfied"
// PlacementConditionMisconfigured means Placement configuration is incorrect.
PlacementConditionMisconfigured string = "PlacementMisconfigured"
)
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// PlacementList is a collection of Placements.
type PlacementList struct {
metav1.TypeMeta `json:",inline"`
// Standard list metadata.
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
// +optional
metav1.ListMeta `json:"metadata,omitempty"`
// Items is a list of Placements.
Items []Placement `json:"items"`
}
@@ -0,0 +1,70 @@
package v1beta1
import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// +genclient
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// +kubebuilder:resource:scope="Namespaced"
// +kubebuilder:subresource:status
// PlacementDecision indicates a decision from a placement
// PlacementDecision should has a label cluster.open-cluster-management.io/placement={placement name}
// to reference a certain placement.
//
// If a placement has spec.numberOfClusters specified, the total number of decisions contained in
// status.decisions of PlacementDecisions should always be NumberOfClusters; otherwise, the total
// number of decisions should be the number of ManagedClusters which match the placement requirements.
//
// Some of the decisions might be empty when there are no enough ManagedClusters meet the placement
// requirements.
type PlacementDecision struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
// Status represents the current status of the PlacementDecision
// +optional
Status PlacementDecisionStatus `json:"status,omitempty"`
}
//The placementDecsion label name holding the placement name
const (
PlacementLabel string = "cluster.open-cluster-management.io/placement"
)
// PlacementDecisionStatus represents the current status of the PlacementDecision.
type PlacementDecisionStatus struct {
// Decisions is a slice of decisions according to a placement
// The number of decisions should not be larger than 100
// +kubebuilder:validation:Required
// +required
Decisions []ClusterDecision `json:"decisions"`
}
// ClusterDecision represents a decision from a placement
// An empty ClusterDecision indicates it is not scheduled yet.
type ClusterDecision struct {
// ClusterName is the name of the ManagedCluster. If it is not empty, its value should be unique cross all
// placement decisions for the Placement.
// +kubebuilder:validation:Required
// +required
ClusterName string `json:"clusterName"`
// Reason represents the reason why the ManagedCluster is selected.
// +kubebuilder:validation:Required
// +required
Reason string `json:"reason"`
}
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// ClusterDecisionList is a collection of PlacementDecision.
type PlacementDecisionList struct {
metav1.TypeMeta `json:",inline"`
// Standard list metadata.
// More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds
// +optional
metav1.ListMeta `json:"metadata,omitempty"`
// Items is a list of PlacementDecision.
Items []PlacementDecision `json:"items"`
}
@@ -10,6 +10,96 @@ import (
runtime "k8s.io/apimachinery/pkg/runtime"
)
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *AddOnScore) DeepCopyInto(out *AddOnScore) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AddOnScore.
func (in *AddOnScore) DeepCopy() *AddOnScore {
if in == nil {
return nil
}
out := new(AddOnScore)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterClaimSelector) DeepCopyInto(out *ClusterClaimSelector) {
*out = *in
if in.MatchExpressions != nil {
in, out := &in.MatchExpressions, &out.MatchExpressions
*out = make([]v1.LabelSelectorRequirement, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterClaimSelector.
func (in *ClusterClaimSelector) DeepCopy() *ClusterClaimSelector {
if in == nil {
return nil
}
out := new(ClusterClaimSelector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterDecision) DeepCopyInto(out *ClusterDecision) {
*out = *in
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterDecision.
func (in *ClusterDecision) DeepCopy() *ClusterDecision {
if in == nil {
return nil
}
out := new(ClusterDecision)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterPredicate) DeepCopyInto(out *ClusterPredicate) {
*out = *in
in.RequiredClusterSelector.DeepCopyInto(&out.RequiredClusterSelector)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterPredicate.
func (in *ClusterPredicate) DeepCopy() *ClusterPredicate {
if in == nil {
return nil
}
out := new(ClusterPredicate)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ClusterSelector) DeepCopyInto(out *ClusterSelector) {
*out = *in
in.LabelSelector.DeepCopyInto(&out.LabelSelector)
in.ClaimSelector.DeepCopyInto(&out.ClaimSelector)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSelector.
func (in *ClusterSelector) DeepCopy() *ClusterSelector {
if in == nil {
return nil
}
out := new(ClusterSelector)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ManagedClusterSet) DeepCopyInto(out *ManagedClusterSet) {
*out = *in
@@ -185,3 +275,295 @@ func (in *ManagedClusterSetStatus) DeepCopy() *ManagedClusterSetStatus {
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Placement) DeepCopyInto(out *Placement) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Spec.DeepCopyInto(&out.Spec)
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Placement.
func (in *Placement) DeepCopy() *Placement {
if in == nil {
return nil
}
out := new(Placement)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *Placement) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PlacementDecision) DeepCopyInto(out *PlacementDecision) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
in.Status.DeepCopyInto(&out.Status)
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlacementDecision.
func (in *PlacementDecision) DeepCopy() *PlacementDecision {
if in == nil {
return nil
}
out := new(PlacementDecision)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PlacementDecision) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PlacementDecisionList) DeepCopyInto(out *PlacementDecisionList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]PlacementDecision, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlacementDecisionList.
func (in *PlacementDecisionList) DeepCopy() *PlacementDecisionList {
if in == nil {
return nil
}
out := new(PlacementDecisionList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PlacementDecisionList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PlacementDecisionStatus) DeepCopyInto(out *PlacementDecisionStatus) {
*out = *in
if in.Decisions != nil {
in, out := &in.Decisions, &out.Decisions
*out = make([]ClusterDecision, len(*in))
copy(*out, *in)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlacementDecisionStatus.
func (in *PlacementDecisionStatus) DeepCopy() *PlacementDecisionStatus {
if in == nil {
return nil
}
out := new(PlacementDecisionStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PlacementList) DeepCopyInto(out *PlacementList) {
*out = *in
out.TypeMeta = in.TypeMeta
in.ListMeta.DeepCopyInto(&out.ListMeta)
if in.Items != nil {
in, out := &in.Items, &out.Items
*out = make([]Placement, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlacementList.
func (in *PlacementList) DeepCopy() *PlacementList {
if in == nil {
return nil
}
out := new(PlacementList)
in.DeepCopyInto(out)
return out
}
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
func (in *PlacementList) DeepCopyObject() runtime.Object {
if c := in.DeepCopy(); c != nil {
return c
}
return nil
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PlacementSpec) DeepCopyInto(out *PlacementSpec) {
*out = *in
if in.ClusterSets != nil {
in, out := &in.ClusterSets, &out.ClusterSets
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.NumberOfClusters != nil {
in, out := &in.NumberOfClusters, &out.NumberOfClusters
*out = new(int32)
**out = **in
}
if in.Predicates != nil {
in, out := &in.Predicates, &out.Predicates
*out = make([]ClusterPredicate, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
in.PrioritizerPolicy.DeepCopyInto(&out.PrioritizerPolicy)
if in.Tolerations != nil {
in, out := &in.Tolerations, &out.Tolerations
*out = make([]Toleration, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlacementSpec.
func (in *PlacementSpec) DeepCopy() *PlacementSpec {
if in == nil {
return nil
}
out := new(PlacementSpec)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PlacementStatus) DeepCopyInto(out *PlacementStatus) {
*out = *in
if in.Conditions != nil {
in, out := &in.Conditions, &out.Conditions
*out = make([]v1.Condition, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PlacementStatus.
func (in *PlacementStatus) DeepCopy() *PlacementStatus {
if in == nil {
return nil
}
out := new(PlacementStatus)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PrioritizerConfig) DeepCopyInto(out *PrioritizerConfig) {
*out = *in
if in.ScoreCoordinate != nil {
in, out := &in.ScoreCoordinate, &out.ScoreCoordinate
*out = new(ScoreCoordinate)
(*in).DeepCopyInto(*out)
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PrioritizerConfig.
func (in *PrioritizerConfig) DeepCopy() *PrioritizerConfig {
if in == nil {
return nil
}
out := new(PrioritizerConfig)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *PrioritizerPolicy) DeepCopyInto(out *PrioritizerPolicy) {
*out = *in
if in.Configurations != nil {
in, out := &in.Configurations, &out.Configurations
*out = make([]PrioritizerConfig, len(*in))
for i := range *in {
(*in)[i].DeepCopyInto(&(*out)[i])
}
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PrioritizerPolicy.
func (in *PrioritizerPolicy) DeepCopy() *PrioritizerPolicy {
if in == nil {
return nil
}
out := new(PrioritizerPolicy)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *ScoreCoordinate) DeepCopyInto(out *ScoreCoordinate) {
*out = *in
if in.AddOn != nil {
in, out := &in.AddOn, &out.AddOn
*out = new(AddOnScore)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ScoreCoordinate.
func (in *ScoreCoordinate) DeepCopy() *ScoreCoordinate {
if in == nil {
return nil
}
out := new(ScoreCoordinate)
in.DeepCopyInto(out)
return out
}
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
func (in *Toleration) DeepCopyInto(out *Toleration) {
*out = *in
if in.TolerationSeconds != nil {
in, out := &in.TolerationSeconds, &out.TolerationSeconds
*out = new(int64)
**out = **in
}
return
}
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Toleration.
func (in *Toleration) DeepCopy() *Toleration {
if in == nil {
return nil
}
out := new(Toleration)
in.DeepCopyInto(out)
return out
}
@@ -76,4 +76,165 @@ func (ManagedClusterSetBindingSpec) SwaggerDoc() map[string]string {
return map_ManagedClusterSetBindingSpec
}
var map_AddOnScore = map[string]string{
"": "AddOnScore represents the configuration of the addon score source.",
"resourceName": "ResourceName defines the resource name of the AddOnPlacementScore. The placement prioritizer selects AddOnPlacementScore CR by this name.",
"scoreName": "ScoreName defines the score name inside AddOnPlacementScore. AddOnPlacementScore contains a list of score name and score value, ScoreName specify the score to be used by the prioritizer.",
}
func (AddOnScore) SwaggerDoc() map[string]string {
return map_AddOnScore
}
var map_ClusterClaimSelector = map[string]string{
"": "ClusterClaimSelector is a claim query over a set of ManagedClusters. An empty cluster claim selector matches all objects. A null cluster claim selector matches no objects.",
"matchExpressions": "matchExpressions is a list of cluster claim selector requirements. The requirements are ANDed.",
}
func (ClusterClaimSelector) SwaggerDoc() map[string]string {
return map_ClusterClaimSelector
}
var map_ClusterPredicate = map[string]string{
"": "ClusterPredicate represents a predicate to select ManagedClusters.",
"requiredClusterSelector": "RequiredClusterSelector represents a selector of ManagedClusters by label and claim. If specified, 1) Any ManagedCluster, which does not match the selector, should not be selected by this ClusterPredicate; 2) If a selected ManagedCluster (of this ClusterPredicate) ceases to match the selector (e.g. due to\n an update) of any ClusterPredicate, it will be eventually removed from the placement decisions;\n3) If a ManagedCluster (not selected previously) starts to match the selector, it will either\n be selected or at least has a chance to be selected (when NumberOfClusters is specified);",
}
func (ClusterPredicate) SwaggerDoc() map[string]string {
return map_ClusterPredicate
}
var map_ClusterSelector = map[string]string{
"": "ClusterSelector represents the AND of the containing selectors. An empty cluster selector matches all objects. A null cluster selector matches no objects.",
"labelSelector": "LabelSelector represents a selector of ManagedClusters by label",
"claimSelector": "ClaimSelector represents a selector of ManagedClusters by clusterClaims in status",
}
func (ClusterSelector) SwaggerDoc() map[string]string {
return map_ClusterSelector
}
var map_Placement = map[string]string{
"": "Placement defines a rule to select a set of ManagedClusters from the ManagedClusterSets bound to the placement namespace.\n\nHere is how the placement policy combines with other selection methods to determine a matching list of ManagedClusters: 1) Kubernetes clusters are registered with hub as cluster-scoped ManagedClusters; 2) ManagedClusters are organized into cluster-scoped ManagedClusterSets; 3) ManagedClusterSets are bound to workload namespaces; 4) Namespace-scoped Placements specify a slice of ManagedClusterSets which select a working set\n of potential ManagedClusters;\n5) Then Placements subselect from that working set using label/claim selection.\n\nNo ManagedCluster will be selected if no ManagedClusterSet is bound to the placement namespace. User is able to bind a ManagedClusterSet to a namespace by creating a ManagedClusterSetBinding in that namespace if they have a RBAC rule to CREATE on the virtual subresource of `managedclustersets/bind`.\n\nA slice of PlacementDecisions with label cluster.open-cluster-management.io/placement={placement name} will be created to represent the ManagedClusters selected by this placement.\n\nIf a ManagedCluster is selected and added into the PlacementDecisions, other components may apply workload on it; once it is removed from the PlacementDecisions, the workload applied on this ManagedCluster should be evicted accordingly.",
"spec": "Spec defines the attributes of Placement.",
"status": "Status represents the current status of the Placement",
}
func (Placement) SwaggerDoc() map[string]string {
return map_Placement
}
var map_PlacementList = map[string]string{
"": "PlacementList is a collection of Placements.",
"metadata": "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
"items": "Items is a list of Placements.",
}
func (PlacementList) SwaggerDoc() map[string]string {
return map_PlacementList
}
var map_PlacementSpec = map[string]string{
"": "PlacementSpec defines the attributes of Placement. An empty PlacementSpec selects all ManagedClusters from the ManagedClusterSets bound to the placement namespace. The containing fields are ANDed.",
"clusterSets": "ClusterSets represent the ManagedClusterSets from which the ManagedClusters are selected. If the slice is empty, ManagedClusters will be selected from the ManagedClusterSets bound to the placement namespace, otherwise ManagedClusters will be selected from the intersection of this slice and the ManagedClusterSets bound to the placement namespace.",
"numberOfClusters": "NumberOfClusters represents the desired number of ManagedClusters to be selected which meet the placement requirements. 1) If not specified, all ManagedClusters which meet the placement requirements (including ClusterSets,\n and Predicates) will be selected;\n2) Otherwise if the nubmer of ManagedClusters meet the placement requirements is larger than\n NumberOfClusters, a random subset with desired number of ManagedClusters will be selected;\n3) If the nubmer of ManagedClusters meet the placement requirements is equal to NumberOfClusters,\n all of them will be selected;\n4) If the nubmer of ManagedClusters meet the placement requirements is less than NumberOfClusters,\n all of them will be selected, and the status of condition `PlacementConditionSatisfied` will be\n set to false;",
"predicates": "Predicates represent a slice of predicates to select ManagedClusters. The predicates are ORed.",
"prioritizerPolicy": "PrioritizerPolicy defines the policy of the prioritizers. If this field is unset, then default prioritizer mode and configurations are used. Referring to PrioritizerPolicy to see more description about Mode and Configurations.",
"tolerations": "Tolerations are applied to placements, and allow (but do not require) the managed clusters with certain taints to be selected by placements with matching tolerations.",
}
func (PlacementSpec) SwaggerDoc() map[string]string {
return map_PlacementSpec
}
var map_PlacementStatus = map[string]string{
"numberOfSelectedClusters": "NumberOfSelectedClusters represents the number of selected ManagedClusters",
"conditions": "Conditions contains the different condition status for this Placement.",
}
func (PlacementStatus) SwaggerDoc() map[string]string {
return map_PlacementStatus
}
var map_PrioritizerConfig = map[string]string{
"": "PrioritizerConfig represents the configuration of prioritizer",
"scoreCoordinate": "ScoreCoordinate represents the configuration of the prioritizer and score source.",
"weight": "Weight defines the weight of the prioritizer score. The value must be ranged in [-10,10]. Each prioritizer will calculate an integer score of a cluster in the range of [-100, 100]. The final score of a cluster will be sum(weight * prioritizer_score). A higher weight indicates that the prioritizer weights more in the cluster selection, while 0 weight indicates that the prioritizer is disabled. A negative weight indicates wants to select the last ones.",
}
func (PrioritizerConfig) SwaggerDoc() map[string]string {
return map_PrioritizerConfig
}
var map_PrioritizerPolicy = map[string]string{
"": "PrioritizerPolicy represents the policy of prioritizer",
"mode": "Mode is either Exact, Additive, \"\" where \"\" is Additive by default. In Additive mode, any prioritizer not explicitly enumerated is enabled in its default Configurations, in which Steady and Balance prioritizers have the weight of 1 while other prioritizers have the weight of 0. Additive doesn't require configuring all prioritizers. The default Configurations may change in the future, and additional prioritization will happen. In Exact mode, any prioritizer not explicitly enumerated is weighted as zero. Exact requires knowing the full set of prioritizers you want, but avoids behavior changes between releases.",
}
func (PrioritizerPolicy) SwaggerDoc() map[string]string {
return map_PrioritizerPolicy
}
var map_ScoreCoordinate = map[string]string{
"": "ScoreCoordinate represents the configuration of the score type and score source",
"type": "Type defines the type of the prioritizer score. Type is either \"BuiltIn\", \"AddOn\" or \"\", where \"\" is \"BuiltIn\" by default. When the type is \"BuiltIn\", need to specify a BuiltIn prioritizer name in BuiltIn. When the type is \"AddOn\", need to configure the score source in AddOn.",
"builtIn": "BuiltIn defines the name of a BuiltIn prioritizer. Below are the valid BuiltIn prioritizer names. 1) Balance: balance the decisions among the clusters. 2) Steady: ensure the existing decision is stabilized. 3) ResourceAllocatableCPU & ResourceAllocatableMemory: sort clusters based on the allocatable.",
"addOn": "When type is \"AddOn\", AddOn defines the resource name and score name.",
}
func (ScoreCoordinate) SwaggerDoc() map[string]string {
return map_ScoreCoordinate
}
var map_Toleration = map[string]string{
"": "Toleration represents the toleration object that can be attached to a placement. The placement this Toleration is attached to tolerates any taint that matches the triple <key,value,effect> using the matching operator <operator>.",
"key": "Key is the taint key that the toleration applies to. Empty means match all taint keys. If the key is empty, operator must be Exists; this combination means to match all values and all keys.",
"operator": "Operator represents a key's relationship to the value. Valid operators are Exists and Equal. Defaults to Equal. Exists is equivalent to wildcard for value, so that a placement can tolerate all taints of a particular category.",
"value": "Value is the taint value the toleration matches to. If the operator is Exists, the value should be empty, otherwise just a regular string.",
"effect": "Effect indicates the taint effect to match. Empty means match all taint effects. When specified, allowed values are NoSelect, PreferNoSelect and NoSelectIfNew.",
"tolerationSeconds": "TolerationSeconds represents the period of time the toleration (which must be of effect NoSelect/PreferNoSelect, otherwise this field is ignored) tolerates the taint. The default value is nil, which indicates it tolerates the taint forever. The start time of counting the TolerationSeconds should be the TimeAdded in Taint, not the cluster scheduled time or TolerationSeconds added time.",
}
func (Toleration) SwaggerDoc() map[string]string {
return map_Toleration
}
var map_ClusterDecision = map[string]string{
"": "ClusterDecision represents a decision from a placement An empty ClusterDecision indicates it is not scheduled yet.",
"clusterName": "ClusterName is the name of the ManagedCluster. If it is not empty, its value should be unique cross all placement decisions for the Placement.",
"reason": "Reason represents the reason why the ManagedCluster is selected.",
}
func (ClusterDecision) SwaggerDoc() map[string]string {
return map_ClusterDecision
}
var map_PlacementDecision = map[string]string{
"": "PlacementDecision indicates a decision from a placement PlacementDecision should has a label cluster.open-cluster-management.io/placement={placement name} to reference a certain placement.\n\nIf a placement has spec.numberOfClusters specified, the total number of decisions contained in status.decisions of PlacementDecisions should always be NumberOfClusters; otherwise, the total number of decisions should be the number of ManagedClusters which match the placement requirements.\n\nSome of the decisions might be empty when there are no enough ManagedClusters meet the placement requirements.",
"status": "Status represents the current status of the PlacementDecision",
}
func (PlacementDecision) SwaggerDoc() map[string]string {
return map_PlacementDecision
}
var map_PlacementDecisionList = map[string]string{
"": "ClusterDecisionList is a collection of PlacementDecision.",
"metadata": "Standard list metadata. More info: https://git.k8s.io/community/contributors/devel/api-conventions.md#types-kinds",
"items": "Items is a list of PlacementDecision.",
}
func (PlacementDecisionList) SwaggerDoc() map[string]string {
return map_PlacementDecisionList
}
var map_PlacementDecisionStatus = map[string]string{
"": "PlacementDecisionStatus represents the current status of the PlacementDecision.",
"decisions": "Decisions is a slice of decisions according to a placement The number of decisions should not be larger than 100",
}
func (PlacementDecisionStatus) SwaggerDoc() map[string]string {
return map_PlacementDecisionStatus
}
// AUTO-GENERATED FUNCTIONS END HERE