From 88fecd61782f2e57c222fd6acafb79d0636b776f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lenny=20H=C3=A4ndler?= Date: Thu, 23 Feb 2023 10:09:24 +0100 Subject: [PATCH 01/12] Add fields for claimed resources --- .../crd/kube-bind.io_apiservicebindings.yaml | 283 ++++++ ...kube-bind.io_apiserviceexportrequests.yaml | 290 ++++++ .../crd/kube-bind.io_apiserviceexports.yaml | 271 ++++++ ...ube-bind.io_apiserviceexporttemplates.yaml | 186 ++++ .../v1alpha1/apiservicebinding_types.go | 257 ++++++ .../v1alpha1/apiserviceexport_types.go | 3 + .../v1alpha1/apiserviceexportrequest_types.go | 6 + .../v1alpha1/zz_generated.deepcopy.go | 256 +++++- .../bind-apiservice/plugin/servicebindings.go | 181 ++++ .../plugin/servicebindings_test.go | 824 ++++++++++++++++++ 10 files changed, 2556 insertions(+), 1 deletion(-) create mode 100644 deploy/crd/kube-bind.io_apiserviceexporttemplates.yaml create mode 100644 pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go diff --git a/deploy/crd/kube-bind.io_apiservicebindings.yaml b/deploy/crd/kube-bind.io_apiservicebindings.yaml index 132432963..bc67a56cf 100644 --- a/deploy/crd/kube-bind.io_apiservicebindings.yaml +++ b/deploy/crd/kube-bind.io_apiservicebindings.yaml @@ -84,6 +84,289 @@ spec: x-kubernetes-validations: - message: kubeconfigSecretRef is immutable rule: self == oldSelf + permissionClaims: + description: permissionClaims records decisions about permission claims + requested by the API service provider. Individual claims can be + accepted or rejected. If accepted, the API service provider gets + the requested access to the specified resources in this workspace. + Access is granted per GroupResource and other properties like selectors. + items: + description: acceptablePermissionClaim is a permission claim that + stores the users acceptance in the field state. Only accepted + permission claims are reconciled. + properties: + autoAdopt: + description: autoAdopt set to true means that objects created + by the consumer are adopted by the provider. i.e. the provider + will become the owner. Mutually exclusive with autoDonate. + type: boolean + autoDonate: + description: autoDonate set to true means that a newly created + object by the provider is immediately owned by the consumer. + If false, the object stays in ownership of the provider. Mutually + exclusive with autoDonate. + type: boolean + create: + description: create determines whether the kube-bind konnector + will sync matching objects from the provider cluster down + to the consumer cluster. only for owner Provider + properties: + replaceExisting: + description: "replaceExisting means that an existing object + owned by the consumer will be replaced by the provider + object. \n If set to false, and a conflicting consumer + object exists, it is not touched." + type: boolean + type: object + group: + default: "" + description: group is the name of an API group. For core groups + this is the empty string '""'. + pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9](\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)?)$ + type: string + onConflict: + description: onConflict determines how the conflicts between + objects on the consumer cluster will be resolved. + properties: + recreateWhenConsumerSideDeleted: + default: true + description: "recreateWhenConsumerSideDeleted set to true + (the default) means the provider will recreate the object + in case the object is missing on the consumer cluster, + but has been synchronized before. \n If set to false, + deleted provider-owned objects get deleted on the provider + cluster as well. \n Even if the consumer mistakenly or + intentionally deletes the object, the provider will recreate + it. If the field is set as false, the provider will not + recreate the object in case the object is deleted on the + consumer cluster." + type: boolean + type: object + read: + description: read claims read access to matching objects for + the provider. reading of the claimed object(s) is always claimed. + By default no labels and annotations are read. Reading of + labels and annotations can be claimed optionally by adding + labels and annotations items. If labels on consumer owned + objects that are set by the consumer are read, labelsOnProviderOwnedObjects + and annotationsOnProviderOwnedObjects can be set. + properties: + annotations: + description: annotations is a list of claimed annotation + key wildcard patterns that are synchronized from the consumer + cluster to the provider on objects that are owned by the + consumer. + items: + properties: + pattern: + type: string + type: object + type: array + labels: + description: labels is a list of claimed label key wildcard + patterns that are synchronized from the consumer cluster + to the provider on objects that are owned by the consumer. + items: + properties: + pattern: + type: string + type: object + type: array + labelsOnProviderOwnedObjects: + description: labelsOnProviderOwnedObjects is a list of claimed + label key wildcard patterns that are synchronized from + the consumer cluster to the provider on objects owned + by the provider. + items: + properties: + pattern: + type: string + type: object + type: array + overrideAnnotations: + description: overrideAnnotations is a list of claimed annotation + key wildcard patterns that are synchronized from the consumer + cluster to the provider on objects owned by the provider. + items: + properties: + pattern: + type: string + type: object + type: array + type: object + required: + description: required indicates whether the APIServiceBinding + will work if this claim is not accepted. If a required claim + is denied, the binding is aborted. + type: boolean + resource: + description: 'resource is the name of the resource. Note: it + is worth noting that you can not ask for permissions for resource + provided by a CRD not provided by an service binding export.' + pattern: ^[a-z][-a-z0-9]*[a-z0-9]$ + type: string + selector: + description: selector selects which resources are being claimed. + If unset, all resources across all namespaces are being claimed. + properties: + fieldSelectors: + description: fieldSelectors is a list of field selectors + matching selected resources, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/. + items: + type: string + type: array + labelSelectors: + description: labelSelectors is a list of label selectors + matching selected resources. label selectors follow the + same rules as kubernetes label selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. + items: + additionalProperties: + type: string + type: object + type: array + names: + default: + - '*' + description: "names is a list of specific resource names + to select. Names matches the metadata.name field of the + underlying object. An entry of \"*\" anywhere in the list + means all object names of the group/resource within the + \"namespaces\" field are claimed. Wildcard entries other + than \"*\" and regular expressions are currently unsupported. + If a resources name matches any value in names, the resource + name is considered matching. \n // +kubebuilder:validation:XValidation:rule=\"self.all(n, + n.matches('^[A-z-]+|[*]$'))\",message=\"only names or + * are allowed\"" + items: + type: string + type: array + namespaces: + default: + - '*' + description: "namespaces represents namespaces where an + object of the given group/resource may be managed. Namespaces + matches against the metadata.namespace field. A value + of \"*\" matches namespaced objects across all namespaces. + If a resources namespace matches any value in namespaces, + the resource namespace is considered matching. If the + claim is for a cluster-scoped resource, namespaces has + to explicitly be set to an empty array to prevent defaulting + to \"*\". If the \"names\" field is unset, all objects + of the group/resource within the listed namespaces (or + cluster) will be claimed. \n // +kubebuilder:validation:XValidation:rule=\"self.all(n, + n.matches('^[A-z-]+|[*]$'))\",message=\"only names or + * are allowed\"" + items: + type: string + type: array + owner: + description: owner matches the resource's owner. If an owner + selector is set, resources owned by other owners will + not be claimed. Resources without a present owner will + be considered, if configured owner could be the owner + of the object. For example, if the consumer creates a + resource that is claimed by the provider for reading. + In this case the resource will be marked as owned by the + consumer, and handled as such in further reconciliations. + An unset owner selector means objects from both sides + are considered. + enum: + - Provider + - Consumer + type: string + type: object + state: + description: state indicates if the claim is accepted or rejected. + enum: + - Accepted + - Rejected + type: string + update: + description: update lists which updates to objects on the consumer + cluster are claimed. By default, the whole object is synced, + but metadata is not. + properties: + alwaysRecreate: + description: "alwaysRecreate, when true will delete the + old object and create new ones instead of updating. Useful + for immutable objects. \n This does not apply to metadata + field updates." + type: boolean + annotations: + description: "annotations is a list of claimed annotation + keys or annotation wildcard patterns that are synchronized + from the provider to the consumer for objects owned by + the provider. \n By default, no annotations are synced." + items: + properties: + pattern: + type: string + type: object + type: array + annotationsOnConsumerOwnedObjects: + description: "annotationsOnConsumerOwnedObjects is a list + of claimed annotation key wildcard patterns that are synchronized + from the provider to the consumer for objects owned by + the consumer. \n By default, no annotations are synced." + items: + properties: + pattern: + type: string + type: object + type: array + fields: + description: "fields are a list of JSON Paths describing + which parts of an object the provider wants to control. + \n This field is ignored if the owner in the claim selector + is set to \"Provider\"." + items: + type: string + type: array + labels: + description: "labels is a list of claimed label keys or + label wildcard patterns that are synchronized from the + provider to the consumer for objects owned by the provider. + \n By default, no labels are synced." + items: + properties: + pattern: + type: string + type: object + type: array + labelsOnConsumerOwnedObjects: + description: "labelsOnConsumerOwnedObjects is a list of + claimed label key wildcard patterns that are synchronized + from the provider to the consumer for objects owned by + the consumer. \n By default, no labels are synced." + items: + properties: + pattern: + type: string + type: object + type: array + preserving: + description: "preserving is a list of JSON Paths describing + which parts of an object owned by the provider the consumer + keeps controlling. \n This field is ignored if the owner + in the claim selector is set to \"Consumer\"." + items: + type: string + type: array + type: object + version: + description: version is the version of the claimed resource. + minLength: 1 + type: string + required: + - resource + - state + - version + type: object + x-kubernetes-validations: + - message: donate and adopt are mutually exclusive + rule: '!(has(self.autoDonate) && self.autoDonate && has(self.autoAdopt) + && self.autoAdopt)' + type: array required: - kubeconfigSecretRef type: object diff --git a/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml b/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml index 7a38c14f2..bbddb1d1d 100644 --- a/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml +++ b/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml @@ -63,6 +63,296 @@ spec: this is the empty string '""'. pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9](\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)?)$ type: string + permissionClaims: + description: permissionClaims records decisions about permission + claims requested by the service provider. Individual claims + can be accepted or rejected. If accepted, the API service + provider gets the requested access to the specified resources + in this workspace. Access is granted per GroupResource, identity, + and other properties. + items: + description: permissionClaim selects objects of a GVR that + a service provider may request and that a consumer may accept + and allow the service provider access to. + properties: + autoAdopt: + description: autoAdopt set to true means that objects + created by the consumer are adopted by the provider. + i.e. the provider will become the owner. Mutually exclusive + with autoDonate. + type: boolean + autoDonate: + description: autoDonate set to true means that a newly + created object by the provider is immediately owned + by the consumer. If false, the object stays in ownership + of the provider. Mutually exclusive with autoDonate. + type: boolean + create: + description: create determines whether the kube-bind konnector + will sync matching objects from the provider cluster + down to the consumer cluster. only for owner Provider + properties: + replaceExisting: + description: "replaceExisting means that an existing + object owned by the consumer will be replaced by + the provider object. \n If set to false, and a conflicting + consumer object exists, it is not touched." + type: boolean + type: object + group: + default: "" + description: group is the name of an API group. For core + groups this is the empty string '""'. + pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9](\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)?)$ + type: string + onConflict: + description: onConflict determines how the conflicts between + objects on the consumer cluster will be resolved. + properties: + recreateWhenConsumerSideDeleted: + default: true + description: "recreateWhenConsumerSideDeleted set + to true (the default) means the provider will recreate + the object in case the object is missing on the + consumer cluster, but has been synchronized before. + \n If set to false, deleted provider-owned objects + get deleted on the provider cluster as well. \n + Even if the consumer mistakenly or intentionally + deletes the object, the provider will recreate it. + If the field is set as false, the provider will + not recreate the object in case the object is deleted + on the consumer cluster." + type: boolean + type: object + read: + description: read claims read access to matching objects + for the provider. reading of the claimed object(s) is + always claimed. By default no labels and annotations + are read. Reading of labels and annotations can be claimed + optionally by adding labels and annotations items. If + labels on consumer owned objects that are set by the + consumer are read, labelsOnProviderOwnedObjects and + annotationsOnProviderOwnedObjects can be set. + properties: + annotations: + description: annotations is a list of claimed annotation + key wildcard patterns that are synchronized from + the consumer cluster to the provider on objects + that are owned by the consumer. + items: + properties: + pattern: + type: string + type: object + type: array + labels: + description: labels is a list of claimed label key + wildcard patterns that are synchronized from the + consumer cluster to the provider on objects that + are owned by the consumer. + items: + properties: + pattern: + type: string + type: object + type: array + labelsOnProviderOwnedObjects: + description: labelsOnProviderOwnedObjects is a list + of claimed label key wildcard patterns that are + synchronized from the consumer cluster to the provider + on objects owned by the provider. + items: + properties: + pattern: + type: string + type: object + type: array + overrideAnnotations: + description: overrideAnnotations is a list of claimed + annotation key wildcard patterns that are synchronized + from the consumer cluster to the provider on objects + owned by the provider. + items: + properties: + pattern: + type: string + type: object + type: array + type: object + required: + description: required indicates whether the APIServiceBinding + will work if this claim is not accepted. If a required + claim is denied, the binding is aborted. + type: boolean + resource: + description: 'resource is the name of the resource. Note: + it is worth noting that you can not ask for permissions + for resource provided by a CRD not provided by an service + binding export.' + pattern: ^[a-z][-a-z0-9]*[a-z0-9]$ + type: string + selector: + description: selector selects which resources are being + claimed. If unset, all resources across all namespaces + are being claimed. + properties: + fieldSelectors: + description: fieldSelectors is a list of field selectors + matching selected resources, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/. + items: + type: string + type: array + labelSelectors: + description: labelSelectors is a list of label selectors + matching selected resources. label selectors follow + the same rules as kubernetes label selectors, see + https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. + items: + additionalProperties: + type: string + type: object + type: array + names: + default: + - '*' + description: "names is a list of specific resource + names to select. Names matches the metadata.name + field of the underlying object. An entry of \"*\" + anywhere in the list means all object names of the + group/resource within the \"namespaces\" field are + claimed. Wildcard entries other than \"*\" and regular + expressions are currently unsupported. If a resources + name matches any value in names, the resource name + is considered matching. \n // +kubebuilder:validation:XValidation:rule=\"self.all(n, + n.matches('^[A-z-]+|[*]$'))\",message=\"only names + or * are allowed\"" + items: + type: string + type: array + namespaces: + default: + - '*' + description: "namespaces represents namespaces where + an object of the given group/resource may be managed. + Namespaces matches against the metadata.namespace + field. A value of \"*\" matches namespaced objects + across all namespaces. If a resources namespace + matches any value in namespaces, the resource namespace + is considered matching. If the claim is for a cluster-scoped + resource, namespaces has to explicitly be set to + an empty array to prevent defaulting to \"*\". If + the \"names\" field is unset, all objects of the + group/resource within the listed namespaces (or + cluster) will be claimed. \n // +kubebuilder:validation:XValidation:rule=\"self.all(n, + n.matches('^[A-z-]+|[*]$'))\",message=\"only names + or * are allowed\"" + items: + type: string + type: array + owner: + description: owner matches the resource's owner. If + an owner selector is set, resources owned by other + owners will not be claimed. Resources without a + present owner will be considered, if configured + owner could be the owner of the object. For example, + if the consumer creates a resource that is claimed + by the provider for reading. In this case the resource + will be marked as owned by the consumer, and handled + as such in further reconciliations. An unset owner + selector means objects from both sides are considered. + enum: + - Provider + - Consumer + type: string + type: object + update: + description: update lists which updates to objects on + the consumer cluster are claimed. By default, the whole + object is synced, but metadata is not. + properties: + alwaysRecreate: + description: "alwaysRecreate, when true will delete + the old object and create new ones instead of updating. + Useful for immutable objects. \n This does not apply + to metadata field updates." + type: boolean + annotations: + description: "annotations is a list of claimed annotation + keys or annotation wildcard patterns that are synchronized + from the provider to the consumer for objects owned + by the provider. \n By default, no annotations are + synced." + items: + properties: + pattern: + type: string + type: object + type: array + annotationsOnConsumerOwnedObjects: + description: "annotationsOnConsumerOwnedObjects is + a list of claimed annotation key wildcard patterns + that are synchronized from the provider to the consumer + for objects owned by the consumer. \n By default, + no annotations are synced." + items: + properties: + pattern: + type: string + type: object + type: array + fields: + description: "fields are a list of JSON Paths describing + which parts of an object the provider wants to control. + \n This field is ignored if the owner in the claim + selector is set to \"Provider\"." + items: + type: string + type: array + labels: + description: "labels is a list of claimed label keys + or label wildcard patterns that are synchronized + from the provider to the consumer for objects owned + by the provider. \n By default, no labels are synced." + items: + properties: + pattern: + type: string + type: object + type: array + labelsOnConsumerOwnedObjects: + description: "labelsOnConsumerOwnedObjects is a list + of claimed label key wildcard patterns that are + synchronized from the provider to the consumer for + objects owned by the consumer. \n By default, no + labels are synced." + items: + properties: + pattern: + type: string + type: object + type: array + preserving: + description: "preserving is a list of JSON Paths describing + which parts of an object owned by the provider the + consumer keeps controlling. \n This field is ignored + if the owner in the claim selector is set to \"Consumer\"." + items: + type: string + type: array + type: object + version: + description: version is the version of the claimed resource. + minLength: 1 + type: string + required: + - resource + - version + type: object + x-kubernetes-validations: + - message: donate and adopt are mutually exclusive + rule: '!(has(self.autoDonate) && self.autoDonate && has(self.autoAdopt) + && self.autoAdopt)' + type: array resource: description: 'resource is the name of the resource. Note: it is worth noting that you can not ask for permissions for resource diff --git a/deploy/crd/kube-bind.io_apiserviceexports.yaml b/deploy/crd/kube-bind.io_apiserviceexports.yaml index 6b5a75827..d99e6bfc6 100644 --- a/deploy/crd/kube-bind.io_apiserviceexports.yaml +++ b/deploy/crd/kube-bind.io_apiserviceexports.yaml @@ -108,6 +108,277 @@ spec: - kind - plural type: object + permissionClaims: + items: + description: permissionClaim selects objects of a GVR that a service + provider may request and that a consumer may accept and allow + the service provider access to. + properties: + autoAdopt: + description: autoAdopt set to true means that objects created + by the consumer are adopted by the provider. i.e. the provider + will become the owner. Mutually exclusive with autoDonate. + type: boolean + autoDonate: + description: autoDonate set to true means that a newly created + object by the provider is immediately owned by the consumer. + If false, the object stays in ownership of the provider. Mutually + exclusive with autoDonate. + type: boolean + create: + description: create determines whether the kube-bind konnector + will sync matching objects from the provider cluster down + to the consumer cluster. only for owner Provider + properties: + replaceExisting: + description: "replaceExisting means that an existing object + owned by the consumer will be replaced by the provider + object. \n If set to false, and a conflicting consumer + object exists, it is not touched." + type: boolean + type: object + group: + default: "" + description: group is the name of an API group. For core groups + this is the empty string '""'. + pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9](\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)?)$ + type: string + onConflict: + description: onConflict determines how the conflicts between + objects on the consumer cluster will be resolved. + properties: + recreateWhenConsumerSideDeleted: + default: true + description: "recreateWhenConsumerSideDeleted set to true + (the default) means the provider will recreate the object + in case the object is missing on the consumer cluster, + but has been synchronized before. \n If set to false, + deleted provider-owned objects get deleted on the provider + cluster as well. \n Even if the consumer mistakenly or + intentionally deletes the object, the provider will recreate + it. If the field is set as false, the provider will not + recreate the object in case the object is deleted on the + consumer cluster." + type: boolean + type: object + read: + description: read claims read access to matching objects for + the provider. reading of the claimed object(s) is always claimed. + By default no labels and annotations are read. Reading of + labels and annotations can be claimed optionally by adding + labels and annotations items. If labels on consumer owned + objects that are set by the consumer are read, labelsOnProviderOwnedObjects + and annotationsOnProviderOwnedObjects can be set. + properties: + annotations: + description: annotations is a list of claimed annotation + key wildcard patterns that are synchronized from the consumer + cluster to the provider on objects that are owned by the + consumer. + items: + properties: + pattern: + type: string + type: object + type: array + labels: + description: labels is a list of claimed label key wildcard + patterns that are synchronized from the consumer cluster + to the provider on objects that are owned by the consumer. + items: + properties: + pattern: + type: string + type: object + type: array + labelsOnProviderOwnedObjects: + description: labelsOnProviderOwnedObjects is a list of claimed + label key wildcard patterns that are synchronized from + the consumer cluster to the provider on objects owned + by the provider. + items: + properties: + pattern: + type: string + type: object + type: array + overrideAnnotations: + description: overrideAnnotations is a list of claimed annotation + key wildcard patterns that are synchronized from the consumer + cluster to the provider on objects owned by the provider. + items: + properties: + pattern: + type: string + type: object + type: array + type: object + required: + description: required indicates whether the APIServiceBinding + will work if this claim is not accepted. If a required claim + is denied, the binding is aborted. + type: boolean + resource: + description: 'resource is the name of the resource. Note: it + is worth noting that you can not ask for permissions for resource + provided by a CRD not provided by an service binding export.' + pattern: ^[a-z][-a-z0-9]*[a-z0-9]$ + type: string + selector: + description: selector selects which resources are being claimed. + If unset, all resources across all namespaces are being claimed. + properties: + fieldSelectors: + description: fieldSelectors is a list of field selectors + matching selected resources, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/. + items: + type: string + type: array + labelSelectors: + description: labelSelectors is a list of label selectors + matching selected resources. label selectors follow the + same rules as kubernetes label selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. + items: + additionalProperties: + type: string + type: object + type: array + names: + default: + - '*' + description: "names is a list of specific resource names + to select. Names matches the metadata.name field of the + underlying object. An entry of \"*\" anywhere in the list + means all object names of the group/resource within the + \"namespaces\" field are claimed. Wildcard entries other + than \"*\" and regular expressions are currently unsupported. + If a resources name matches any value in names, the resource + name is considered matching. \n // +kubebuilder:validation:XValidation:rule=\"self.all(n, + n.matches('^[A-z-]+|[*]$'))\",message=\"only names or + * are allowed\"" + items: + type: string + type: array + namespaces: + default: + - '*' + description: "namespaces represents namespaces where an + object of the given group/resource may be managed. Namespaces + matches against the metadata.namespace field. A value + of \"*\" matches namespaced objects across all namespaces. + If a resources namespace matches any value in namespaces, + the resource namespace is considered matching. If the + claim is for a cluster-scoped resource, namespaces has + to explicitly be set to an empty array to prevent defaulting + to \"*\". If the \"names\" field is unset, all objects + of the group/resource within the listed namespaces (or + cluster) will be claimed. \n // +kubebuilder:validation:XValidation:rule=\"self.all(n, + n.matches('^[A-z-]+|[*]$'))\",message=\"only names or + * are allowed\"" + items: + type: string + type: array + owner: + description: owner matches the resource's owner. If an owner + selector is set, resources owned by other owners will + not be claimed. Resources without a present owner will + be considered, if configured owner could be the owner + of the object. For example, if the consumer creates a + resource that is claimed by the provider for reading. + In this case the resource will be marked as owned by the + consumer, and handled as such in further reconciliations. + An unset owner selector means objects from both sides + are considered. + enum: + - Provider + - Consumer + type: string + type: object + update: + description: update lists which updates to objects on the consumer + cluster are claimed. By default, the whole object is synced, + but metadata is not. + properties: + alwaysRecreate: + description: "alwaysRecreate, when true will delete the + old object and create new ones instead of updating. Useful + for immutable objects. \n This does not apply to metadata + field updates." + type: boolean + annotations: + description: "annotations is a list of claimed annotation + keys or annotation wildcard patterns that are synchronized + from the provider to the consumer for objects owned by + the provider. \n By default, no annotations are synced." + items: + properties: + pattern: + type: string + type: object + type: array + annotationsOnConsumerOwnedObjects: + description: "annotationsOnConsumerOwnedObjects is a list + of claimed annotation key wildcard patterns that are synchronized + from the provider to the consumer for objects owned by + the consumer. \n By default, no annotations are synced." + items: + properties: + pattern: + type: string + type: object + type: array + fields: + description: "fields are a list of JSON Paths describing + which parts of an object the provider wants to control. + \n This field is ignored if the owner in the claim selector + is set to \"Provider\"." + items: + type: string + type: array + labels: + description: "labels is a list of claimed label keys or + label wildcard patterns that are synchronized from the + provider to the consumer for objects owned by the provider. + \n By default, no labels are synced." + items: + properties: + pattern: + type: string + type: object + type: array + labelsOnConsumerOwnedObjects: + description: "labelsOnConsumerOwnedObjects is a list of + claimed label key wildcard patterns that are synchronized + from the provider to the consumer for objects owned by + the consumer. \n By default, no labels are synced." + items: + properties: + pattern: + type: string + type: object + type: array + preserving: + description: "preserving is a list of JSON Paths describing + which parts of an object owned by the provider the consumer + keeps controlling. \n This field is ignored if the owner + in the claim selector is set to \"Consumer\"." + items: + type: string + type: array + type: object + version: + description: version is the version of the claimed resource. + minLength: 1 + type: string + required: + - resource + - version + type: object + x-kubernetes-validations: + - message: donate and adopt are mutually exclusive + rule: '!(has(self.autoDonate) && self.autoDonate && has(self.autoAdopt) + && self.autoAdopt)' + type: array scope: description: scope indicates whether the defined custom resource is cluster- or namespace-scoped. Allowed values are `Cluster` and `Namespaced`. diff --git a/deploy/crd/kube-bind.io_apiserviceexporttemplates.yaml b/deploy/crd/kube-bind.io_apiserviceexporttemplates.yaml new file mode 100644 index 000000000..c11a2da9d --- /dev/null +++ b/deploy/crd/kube-bind.io_apiserviceexporttemplates.yaml @@ -0,0 +1,186 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.10.0 + creationTimestamp: null + name: apiserviceexporttemplates.kube-bind.io +spec: + group: kube-bind.io + names: + categories: + - kube-bindings + kind: APIServiceExportTemplate + listKind: APIServiceExportTemplateList + plural: apiserviceexporttemplates + singular: apiserviceexporttemplate + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[?(@.type=="Established")].status + name: Established + priority: 5 + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: APIServiceExportTemplate specifies the resource to be exported. + It references the CRD to be exported along with additional resources that + are synchronized from and to the consumer cluster. + 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 specifies the resource. + properties: + APIServiceSelector: + properties: + group: + type: string + resource: + type: string + versions: + items: + type: string + type: array + type: object + permissionClaims: + items: + description: "PermissionClaim selects objects of a GVR that a service + provider may request and that a consumer may accept and allow + the service provider access to. \n TODO fix validation +kubebuilder:validation:XValidation:rule=\"!(self.create.donate + && self.adopt)\",message=\"donate and adopt are mutually exclusive\"" + properties: + adopt: + description: adopt set to true means that objects created by + the consumer are adopted by the provider. i.e. the provider + will become the owner. + type: boolean + create: + description: "only for owner Provider \n create determines whether + the kube-bind konnector will sync matching objects from the + provider side down to the consumer cluster." + properties: + donate: + description: donate set to true means that a newly created + object by the provider is immediately owned by hte consumer. + If false, the object stays in ownership of the provider + type: boolean + type: object + global: + description: Global claims global resources for the given group/resource. + This is mutually exclusive with resourceSelector. + type: boolean + group: + default: "" + description: group is the name of an API group. For core groups + this is the empty string '""'. + pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9](\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)?)$ + type: string + onConflict: + description: onConflict determines how the conflicts between + objects on the consumer side will be resolved. + properties: + providerOverrides: + description: providerOverrides will make the provider override + any object that might already exist in the consumer cluster + if it has the same namespaced name as a resource created + by the provider, but is not the result of syncing. + type: boolean + recreateWhenConsumerSideDeleted: + description: recreateWhenConsumerSideDeleted set to true + means the provider will recreate the object in case the + object is missing on the consumer side. Even if the consumer + mistakenly or intentionally deletes the objet, the provider + will recreate it. If the field is set as false, the provider + will not recreate the object in case the object is deleted + on the RecreateWhenConsumerSideDeleted side. + type: boolean + type: object + required: + description: required indicates whether the APIServiceBinding + will work if this claim is not accepted. + type: boolean + resource: + description: 'resource is the name of the resource. Note: it + is worth noting that you can not ask for permissions for resource + provided by a CRD not provided by an service binding export.' + pattern: ^[a-z][-a-z0-9]*[a-z0-9]$ + type: string + selector: + description: selector selects which resources are affected by + this claim. + properties: + name: + description: name of an object within a claimed group/resource. + It matches the metadata.name field of the underlying object. + If name is unset, all objects in bound namespaces will + be claimed. + maxLength: 253 + minLength: 1 + pattern: ^([a-z0-9][-a-z0-9_.]*)?[a-z0-9]$ + type: string + owner: + enum: + - Provider + - Consumer + type: string + type: object + update: + description: update lists a number of claimed permissions for + the provider. "field" and "preserving" are mutually exclusive. + properties: + alwaysRecreate: + description: alwaysRecreate, when true will make the konnector + delete the old object and create a new one instead of + updating. Useful for immutable objects. + type: boolean + fields: + description: fields are the fields owned by the owner of + the claim. If the owner sets values of those fields, they + will be synced to the other participant. Mutually exclusive + with preservings. + items: + type: string + type: array + preservings: + description: Preservings are the fields that are preserved + by the konnector during synchronization. The owner is + not able to set those fields. If the owner changes the + value of these fields, their change will be overwritten. + items: + type: string + type: array + type: object + version: + type: string + required: + - resource + - version + type: object + type: array + type: object + status: + description: status contains reconciliation information for the resource. + type: object + required: + - spec + type: object + served: true + storage: true + subresources: + status: {} diff --git a/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go b/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go index 4a664a7af..47c37ae9b 100644 --- a/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go +++ b/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go @@ -87,8 +87,265 @@ type APIServiceBindingSpec struct { // +kubebuilder:validation:Required // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="kubeconfigSecretRef is immutable" KubeconfigSecretRef ClusterSecretKeyRef `json:"kubeconfigSecretRef"` + + // permissionClaims records decisions about permission claims requested by the API service provider. + // Individual claims can be accepted or rejected. If accepted, the API service provider gets the + // requested access to the specified resources in this workspace. Access is granted per + // GroupResource and other properties like selectors. + // + // +optional + PermissionClaims []AcceptablePermissionClaim `json:"permissionClaims,omitempty"` +} + +// acceptablePermissionClaim is a permission claim that stores the users acceptance in the field state. Only accepted permission claims are reconciled. +type AcceptablePermissionClaim struct { + PermissionClaim `json:",inline"` + + // state indicates if the claim is accepted or rejected. + // + // +required + // +kubebuilder:validation:Required + // +kubebuilder:validation:Enum=Accepted;Rejected + State AcceptablePermissionClaimState `json:"state"` } +type AcceptablePermissionClaimState string + +const ( + ClaimAccepted AcceptablePermissionClaimState = "Accepted" + ClaimRejected AcceptablePermissionClaimState = "Rejected" +) + +// permissionClaim selects objects of a GVR that a service provider may +// request and that a consumer may accept and allow the service provider access to. +// +// +kubebuilder:validation:XValidation:rule="!(has(self.autoDonate) && self.autoDonate && has(self.autoAdopt) && self.autoAdopt)",message="donate and adopt are mutually exclusive" +type PermissionClaim struct { + GroupResource `json:","` + + // version is the version of the claimed resource. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength:=1 + Version string `json:"version"` + + // selector selects which resources are being claimed. + // If unset, all resources across all namespaces are being claimed. + // + // +optional + // +kubebuilder:default:={} + Selector *ResourceSelector `json:"selector,omitempty"` + + // required indicates whether the APIServiceBinding will work if this claim is not accepted. If a required claim is denied, the binding is aborted. + Required bool `json:"required"` + + // read claims read access to matching objects for the provider. + // reading of the claimed object(s) is always claimed. + // By default no labels and annotations are read. Reading of labels and annotations can be claimed + // optionally by adding labels and annotations items. + // If labels on consumer owned objects that are set by the consumer are read, labelsOnProviderOwnedObjects and + // annotationsOnProviderOwnedObjects can be set. + // + // +optional + // +kubebuilder:default={} + Read *ReadOptions `json:"read,omitempty"` + + // create determines whether the kube-bind konnector will sync matching objects from the + // provider cluster down to the consumer cluster. + // only for owner Provider + // + // +optional + Create *CreateOptions `json:"create,omitempty"` + + // autoAdopt set to true means that objects created by the consumer are adopted by the provider. + // i.e. the provider will become the owner. + // Mutually exclusive with autoDonate. + // + // +optional + AutoAdopt bool `json:"autoAdopt,omitempty"` + + // autoDonate set to true means that a newly created object by the provider is immediately owned by the consumer. + // If false, the object stays in ownership of the provider. + // Mutually exclusive with autoDonate. + // + // +optional + AutoDonate bool `json:"autoDonate,omitempty"` + + // onConflict determines how the conflicts between objects on the consumer cluster will be resolved. + // + // +optional + // +kubebuilder:default:={} + OnConflict *OnConflictOptions `json:"onConflict,omitempty"` + + // update lists which updates to objects on the consumer cluster are claimed. + // By default, the whole object is synced, but metadata is not. + // + // +optional + Update *UpdateOptions `json:"update,omitempty"` +} + +type ReadOptions struct { + // labels is a list of claimed label key wildcard patterns + // that are synchronized from the consumer cluster to the provider on + // objects that are owned by the consumer. + // + // +optional + Labels []Matcher `json:"labels,omitempty"` + + // labelsOnProviderOwnedObjects is a list of claimed label key wildcard + // patterns that are synchronized from the consumer cluster + // to the provider on objects owned by the provider. + // + // +optional + LabelsOnProviderOwnedObjects []Matcher `json:"labelsOnProviderOwnedObjects,omitempty"` + + // annotations is a list of claimed annotation key wildcard patterns + // that are synchronized from the consumer cluster to the provider on + // objects that are owned by the consumer. + // + // +optional + Annotations []Matcher `json:"annotations,omitempty"` + + // overrideAnnotations is a list of claimed annotation key wildcard + // patterns that are synchronized from the consumer cluster + // to the provider on objects owned by the provider. + // + // +optional + OverrideAnnotations []Matcher `json:"overrideAnnotations,omitempty"` +} + +type Matcher struct { + // +optional + Pattern string `json:"pattern,omitempty"` +} + +type OnConflictOptions struct { + // recreateWhenConsumerSideDeleted set to true (the default) means the provider will recreate the object + // in case the object is missing on the consumer cluster, but has been synchronized before. + // + // If set to false, deleted provider-owned objects get deleted on the provider cluster as well. + // + // Even if the consumer mistakenly or intentionally + // deletes the object, the provider will recreate it. If the field is set as false, + // the provider will not recreate the object in case the object is deleted on the consumer cluster. + // + // +kubebuilder:default:=true + RecreateWhenConsumerSideDeleted bool `json:"recreateWhenConsumerSideDeleted"` +} + +type CreateOptions struct { + // replaceExisting means that an existing object owned by the consumer will be replaced by the provider object. + // + // If set to false, and a conflicting consumer object exists, it is not touched. + // + // +optional + ReplaceExisting bool `json:"replaceExisting,omitempty"` +} + +type UpdateOptions struct { + // fields are a list of JSON Paths describing which parts of an object the provider wants to control. + // + // This field is ignored if the owner in the claim selector is set to "Provider". + // + // +optional + Fields []string `json:"fields,omitempty"` + + // preserving is a list of JSON Paths describing which parts of an object owned by the provider the consumer keeps controlling. + // + // This field is ignored if the owner in the claim selector is set to "Consumer". + // + // +optional + Preserving []string `json:"preserving,omitempty"` + + // alwaysRecreate, when true will delete the old object and create new ones + // instead of updating. Useful for immutable objects. + // + // This does not apply to metadata field updates. + // + // +optional + AlwaysRecreate bool `json:"alwaysRecreate,omitempty"` + + // labels is a list of claimed label keys or label wildcard patterns that are synchronized from the provider to the consumer for objects owned by the provider. + // + // By default, no labels are synced. + // + // +optional + Labels []Matcher `json:"labels,omitempty"` + + // labelsOnConsumerOwnedObjects is a list of claimed label key wildcard patterns that are synchronized from the provider to the consumer for objects owned by the consumer. + // + // By default, no labels are synced. + // + // +optional + LabelsOnConsumerOwnedObjects []Matcher `json:"labelsOnConsumerOwnedObjects,omitempty"` + + // annotations is a list of claimed annotation keys or annotation wildcard patterns that are synchronized from the provider to the consumer for objects owned by the provider. + // + // By default, no annotations are synced. + // + // +optional + Annotations []Matcher `json:"annotations,omitempty"` + + // annotationsOnConsumerOwnedObjects is a list of claimed annotation key wildcard patterns that are synchronized from the provider to the consumer for objects owned by the consumer. + // + // By default, no annotations are synced. + // + // +optional + AnnotationsOnConsumerOwnedObjects []Matcher `json:"annotationsOnConsumerOwnedObjects,omitempty"` +} + +type ResourceSelector struct { + // names is a list of specific resource names to select. + // Names matches the metadata.name field of the underlying object. + // An entry of "*" anywhere in the list means all object names of the group/resource within the "namespaces" field are claimed. + // Wildcard entries other than "*" and regular expressions are currently unsupported. + // If a resources name matches any value in names, the resource name is considered matching. + // + // // +kubebuilder:validation:XValidation:rule="self.all(n, n.matches('^[A-z-]+|[*]$'))",message="only names or * are allowed" + // +kubebuilder:default:={"*"} + // +optional + Names []string `json:"names,omitempty"` + + // namespaces represents namespaces where an object of the given group/resource may be managed. + // Namespaces matches against the metadata.namespace field. A value of "*" matches namespaced objects across all namespaces. + // If a resources namespace matches any value in namespaces, the resource namespace is considered matching. + // If the claim is for a cluster-scoped resource, namespaces has to explicitly be set to an empty array to prevent defaulting to "*". + // If the "names" field is unset, all objects of the group/resource within the listed namespaces (or cluster) will be claimed. + // + // // +kubebuilder:validation:XValidation:rule="self.all(n, n.matches('^[A-z-]+|[*]$'))",message="only names or * are allowed" + // +kubebuilder:default:={"*"} + // +optional + Namespaces []string `json:"namespaces,omitempty"` + + // labelSelectors is a list of label selectors matching selected resources. label selectors follow the same rules as kubernetes label selectors, + // see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. + LabelSelectors []map[string]string `json:"labelSelectors,omitempty"` + + // fieldSelectors is a list of field selectors matching selected resources, + // see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/. + FieldSelectors []string `json:"fieldSelectors,omitempty"` + + // owner matches the resource's owner. If an owner selector is set, resources owned by other owners will not be claimed. + // Resources without a present owner will be considered, if configured owner could be the owner of the object. + // For example, if the consumer creates a resource that is claimed by the provider for reading. In this case the resource + // will be marked as owned by the consumer, and handled as such in further reconciliations. + // An unset owner selector means objects from both sides are considered. + // + // +kubebuilder:validation:Enum=Provider;Consumer + // +optional + Owner Owner `json:"owner,omitempty"` +} + +type Owner string + +const ( + // provider means that the owner of the resource is the Provider. + Provider Owner = "Provider" + + // consumer means that the owner of the resource is the Consumer. + Consumer Owner = "Consumer" +) + type APIServiceBindingStatus struct { // providerPrettyName is the pretty name of the service provider cluster. This // can be shared among different APIServiceBindings. diff --git a/pkg/apis/kubebind/v1alpha1/apiserviceexport_types.go b/pkg/apis/kubebind/v1alpha1/apiserviceexport_types.go index a802ad167..74d226191 100644 --- a/pkg/apis/kubebind/v1alpha1/apiserviceexport_types.go +++ b/pkg/apis/kubebind/v1alpha1/apiserviceexport_types.go @@ -79,6 +79,9 @@ func (in *APIServiceExport) SetConditions(conditions conditionsapi.Conditions) { type APIServiceExportSpec struct { APIServiceExportCRDSpec `json:",inline"` + // +optional + PermissionClaims []PermissionClaim `json:"permissionClaims,omitempty"` + // informerScope is the scope of the APIServiceExport. It can be either Cluster or Namespace. // // Cluster: The konnector has permission to watch all namespaces at once and cluster-scoped resources. diff --git a/pkg/apis/kubebind/v1alpha1/apiserviceexportrequest_types.go b/pkg/apis/kubebind/v1alpha1/apiserviceexportrequest_types.go index f5234bb05..a0d329825 100644 --- a/pkg/apis/kubebind/v1alpha1/apiserviceexportrequest_types.go +++ b/pkg/apis/kubebind/v1alpha1/apiserviceexportrequest_types.go @@ -110,6 +110,12 @@ type APIServiceExportRequestResource struct { // versions is a list of versions that should be exported. If this is empty // a sensible default is chosen by the service provider. Versions []string `json:"versions,omitempty"` + + // permissionClaims records decisions about permission claims requested by the service provider. + // Individual claims can be accepted or rejected. If accepted, the API service provider gets the + // requested access to the specified resources in this workspace. Access is granted per + // GroupResource, identity, and other properties. + PermissionClaims []PermissionClaim `json:"permissionClaims,omitempty"` } // GroupResource identifies a resource. diff --git a/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go index f16e3d1d0..b1bb2ca50 100644 --- a/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go @@ -33,7 +33,7 @@ func (in *APIServiceBinding) DeepCopyInto(out *APIServiceBinding) { *out = *in out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - out.Spec = in.Spec + in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) return } @@ -93,6 +93,13 @@ func (in *APIServiceBindingList) DeepCopyObject() runtime.Object { func (in *APIServiceBindingSpec) DeepCopyInto(out *APIServiceBindingSpec) { *out = *in out.KubeconfigSecretRef = in.KubeconfigSecretRef + if in.PermissionClaims != nil { + in, out := &in.PermissionClaims, &out.PermissionClaims + *out = make([]AcceptablePermissionClaim, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -284,6 +291,13 @@ func (in *APIServiceExportRequestResource) DeepCopyInto(out *APIServiceExportReq *out = make([]string, len(*in)) copy(*out, *in) } + if in.PermissionClaims != nil { + in, out := &in.PermissionClaims, &out.PermissionClaims + *out = make([]PermissionClaim, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -397,6 +411,13 @@ func (in *APIServiceExportSchema) DeepCopy() *APIServiceExportSchema { func (in *APIServiceExportSpec) DeepCopyInto(out *APIServiceExportSpec) { *out = *in in.APIServiceExportCRDSpec.DeepCopyInto(&out.APIServiceExportCRDSpec) + if in.PermissionClaims != nil { + in, out := &in.PermissionClaims, &out.PermissionClaims + *out = make([]PermissionClaim, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } return } @@ -560,6 +581,23 @@ func (in *APIServiceNamespaceStatus) DeepCopy() *APIServiceNamespaceStatus { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AcceptablePermissionClaim) DeepCopyInto(out *AcceptablePermissionClaim) { + *out = *in + in.PermissionClaim.DeepCopyInto(&out.PermissionClaim) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AcceptablePermissionClaim. +func (in *AcceptablePermissionClaim) DeepCopy() *AcceptablePermissionClaim { + if in == nil { + return nil + } + out := new(AcceptablePermissionClaim) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *AuthenticationMethod) DeepCopyInto(out *AuthenticationMethod) { *out = *in @@ -809,6 +847,22 @@ func (in *ClusterSecretKeyRef) DeepCopy() *ClusterSecretKeyRef { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CreateOptions) DeepCopyInto(out *CreateOptions) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CreateOptions. +func (in *CreateOptions) DeepCopy() *CreateOptions { + if in == nil { + return nil + } + out := new(CreateOptions) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GroupResource) DeepCopyInto(out *GroupResource) { *out = *in @@ -841,6 +895,22 @@ func (in *LocalSecretKeyRef) DeepCopy() *LocalSecretKeyRef { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Matcher) DeepCopyInto(out *Matcher) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Matcher. +func (in *Matcher) DeepCopy() *Matcher { + if in == nil { + return nil + } + out := new(Matcher) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NameObjectMeta) DeepCopyInto(out *NameObjectMeta) { *out = *in @@ -872,3 +942,187 @@ func (in *OAuth2CodeGrant) DeepCopy() *OAuth2CodeGrant { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *OnConflictOptions) DeepCopyInto(out *OnConflictOptions) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OnConflictOptions. +func (in *OnConflictOptions) DeepCopy() *OnConflictOptions { + if in == nil { + return nil + } + out := new(OnConflictOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PermissionClaim) DeepCopyInto(out *PermissionClaim) { + *out = *in + out.GroupResource = in.GroupResource + if in.Selector != nil { + in, out := &in.Selector, &out.Selector + *out = new(ResourceSelector) + (*in).DeepCopyInto(*out) + } + if in.Read != nil { + in, out := &in.Read, &out.Read + *out = new(ReadOptions) + (*in).DeepCopyInto(*out) + } + if in.Create != nil { + in, out := &in.Create, &out.Create + *out = new(CreateOptions) + **out = **in + } + if in.OnConflict != nil { + in, out := &in.OnConflict, &out.OnConflict + *out = new(OnConflictOptions) + **out = **in + } + if in.Update != nil { + in, out := &in.Update, &out.Update + *out = new(UpdateOptions) + (*in).DeepCopyInto(*out) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PermissionClaim. +func (in *PermissionClaim) DeepCopy() *PermissionClaim { + if in == nil { + return nil + } + out := new(PermissionClaim) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ReadOptions) DeepCopyInto(out *ReadOptions) { + *out = *in + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make([]Matcher, len(*in)) + copy(*out, *in) + } + if in.LabelsOnProviderOwnedObjects != nil { + in, out := &in.LabelsOnProviderOwnedObjects, &out.LabelsOnProviderOwnedObjects + *out = make([]Matcher, len(*in)) + copy(*out, *in) + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make([]Matcher, len(*in)) + copy(*out, *in) + } + if in.OverrideAnnotations != nil { + in, out := &in.OverrideAnnotations, &out.OverrideAnnotations + *out = make([]Matcher, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReadOptions. +func (in *ReadOptions) DeepCopy() *ReadOptions { + if in == nil { + return nil + } + out := new(ReadOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceSelector) DeepCopyInto(out *ResourceSelector) { + *out = *in + if in.Names != nil { + in, out := &in.Names, &out.Names + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Namespaces != nil { + in, out := &in.Namespaces, &out.Namespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.LabelSelectors != nil { + in, out := &in.LabelSelectors, &out.LabelSelectors + *out = make([]map[string]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + } + if in.FieldSelectors != nil { + in, out := &in.FieldSelectors, &out.FieldSelectors + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSelector. +func (in *ResourceSelector) DeepCopy() *ResourceSelector { + if in == nil { + return nil + } + out := new(ResourceSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *UpdateOptions) DeepCopyInto(out *UpdateOptions) { + *out = *in + if in.Fields != nil { + in, out := &in.Fields, &out.Fields + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Preserving != nil { + in, out := &in.Preserving, &out.Preserving + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Labels != nil { + in, out := &in.Labels, &out.Labels + *out = make([]Matcher, len(*in)) + copy(*out, *in) + } + if in.LabelsOnConsumerOwnedObjects != nil { + in, out := &in.LabelsOnConsumerOwnedObjects, &out.LabelsOnConsumerOwnedObjects + *out = make([]Matcher, len(*in)) + copy(*out, *in) + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make([]Matcher, len(*in)) + copy(*out, *in) + } + if in.AnnotationsOnConsumerOwnedObjects != nil { + in, out := &in.AnnotationsOnConsumerOwnedObjects, &out.AnnotationsOnConsumerOwnedObjects + *out = make([]Matcher, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateOptions. +func (in *UpdateOptions) DeepCopy() *UpdateOptions { + if in == nil { + return nil + } + out := new(UpdateOptions) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/kubectl/bind-apiservice/plugin/servicebindings.go b/pkg/kubectl/bind-apiservice/plugin/servicebindings.go index 431ed7f14..a66b804af 100644 --- a/pkg/kubectl/bind-apiservice/plugin/servicebindings.go +++ b/pkg/kubectl/bind-apiservice/plugin/servicebindings.go @@ -17,8 +17,12 @@ limitations under the License. package plugin import ( + "bufio" + "bytes" "context" "fmt" + "io" + "strings" "time" apiextensionsclientset "k8s.io/apiextensions-apiserver/pkg/client/clientset/clientset" @@ -115,3 +119,180 @@ func (b *BindAPIServiceOptions) createAPIServiceBindings(ctx context.Context, co return bindings, nil } + +func printPermissionClaim(w io.Writer, p kubebindv1alpha1.PermissionClaim) error { + var b bytes.Buffer + + var groupResource string + if p.GroupResource.Group != "" { + groupResource = fmt.Sprintf("%s objects (apiVersion: \"%s/%s\")", p.GroupResource.Resource, p.GroupResource.Group, p.Version) + } else { + groupResource = fmt.Sprintf("%s objects (apiVersion: \"%s\")", p.GroupResource.Resource, p.Version) + } + + if err := writeFirstLines(&b, groupResource, p); err != nil { + return err + } + + if err := writeCreate(&b, p); err != nil { + return err + } + + if err := writeOnConflict(&b, p); err != nil { + return err + } + + if err := writeUpdateClause(&b, p); err != nil { + return err + } + + if err := writeRequiredAndAcceptance(&b, p.Required); err != nil { + return err + } + + _, err := fmt.Fprint(w, b.String()) + return err +} + +func writeFirstLines(b *bytes.Buffer, groupResource string, claim kubebindv1alpha1.PermissionClaim) error { + var err error + + donate := claim.AutoDonate + + adopt := claim.AutoAdopt + + var names []string + var owner kubebindv1alpha1.Owner + if claim.Selector != nil { + names = claim.Selector.Names + owner = claim.Selector.Owner + } + + var verb string + switch owner { + case kubebindv1alpha1.Provider: + verb = "write" + case kubebindv1alpha1.Consumer: + verb = "read" + default: + verb = "read and write" + } + + switch { + case !donate && !adopt: + groupResource = verb + " " + groupResource + case donate && !adopt: + groupResource = "create user owned " + groupResource + case !donate && adopt: + groupResource = "have ownership of " + groupResource + } + + var ref string + if len(names) > 0 { + ref = " which are referenced with:" + for _, name := range names { + ref = fmt.Sprintf("%s\n\t- name: \"%s\"", ref, name) + } + ref += "\n" + } else { + ref += " " + } + + _, err = fmt.Fprintf(b, "The provider wants to %s%son your cluster.\n", groupResource, ref) + + return err + +} + +func writeCreate(b io.StringWriter, claim kubebindv1alpha1.PermissionClaim) error { + var err error + + switch { + case claim.Create == nil || !claim.Create.ReplaceExisting: + //_, err = b.WriteString("Conflicting objects will not be overwritten. ") + case claim.Create.ReplaceExisting: + _, err = b.WriteString("Conflicting objects will be replaced by the provider. ") + } + + return err +} + +func writeOnConflict(b io.StringWriter, claim kubebindv1alpha1.PermissionClaim) error { + var err error + + switch { + case claim.OnConflict == nil || !claim.OnConflict.RecreateWhenConsumerSideDeleted: + //_, err = b.WriteString("Created objects will not be recreated upon deletion. ") + case claim.OnConflict.RecreateWhenConsumerSideDeleted: + _, err = b.WriteString("Created objects will be recreated upon deletion. ") + default: //Do nothing + } + + return err +} + +func writeUpdateClause(b *bytes.Buffer, claim kubebindv1alpha1.PermissionClaim) error { + var err error + + if claim.Update == nil { + return nil + } + + if claim.Update.Fields != nil { + _, err = fmt.Fprintf(b, "The following fields of the objects will still be able to be changed by the provider:\n") + } + if claim.Update.Preserving != nil { + _, err = b.WriteString("The following fields of the objects will be preserved by the provider:\n") + } + + for _, s := range append(claim.Update.Fields, claim.Update.Preserving...) { + _, err = fmt.Fprintf(b, "\t\"%s\"\n", s) + } + + if claim.Update.AlwaysRecreate { + _, err = b.WriteString("Modification of said objects will by handled by deletion and recreation of said objects.\n") + } + + return err +} + +func writeRequiredAndAcceptance(b *bytes.Buffer, required bool) error { + var err error + + if required { + _, err = fmt.Fprint(b, "Accepting this Permission is required in order to proceed.\n") + } + if !required { + _, err = fmt.Fprint(b, "Accepting this Permission is optional.\n") + } + if err != nil { + return nil + } + + _, err = fmt.Fprint(b, "Do you accept this Permission? [No,Yes]\n") + + return err +} + +func (opt BindAPIServiceOptions) promptYesNo(p kubebindv1alpha1.PermissionClaim) (bool, error) { + + reader := bufio.NewReader(opt.Options.IOStreams.In) + + for { + if err := printPermissionClaim(opt.Options.Out, p); err != nil { + return false, err + } + + response, err := reader.ReadString('\n') + if err != nil { + return false, err + } + + response = strings.ToLower(strings.TrimSpace(response)) + if response == "y" || response == "yes" { + return true, nil + } else if response == "n" || response == "no" { + return false, nil + } + } +} diff --git a/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go b/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go new file mode 100644 index 000000000..48384643b --- /dev/null +++ b/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go @@ -0,0 +1,824 @@ +/* +Copyright 2023 The Kube Bind Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package plugin + +import ( + "bytes" + "os" + "testing" + + "k8s.io/cli-runtime/pkg/genericclioptions" + + kubebindv1alpha1 "github.com/kube-bind/kube-bind/pkg/apis/kubebind/v1alpha1" +) + +func TestHumanReadablePromt(t *testing.T) { + t.Parallel() + + tests := []struct { + name string + testData kubebindv1alpha1.PermissionClaim + expectedOutput string + }{ + {"Owner=Provider", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,Required=false", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: false, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is optional.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,Selector.Names={foo}", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar"}, + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") which are referenced with:\n" + + "\t- name: \"bar\"\n" + + "on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,GroupResource.Group", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "example.com", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + }, + "The provider wants to write foo objects (apiVersion: \"example.com/v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,Selector.Names={bar},GroupResource.Group", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "example.com", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar"}, + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + }, + "The provider wants to write foo objects (apiVersion: \"example.com/v1\") which are referenced with:\n" + + "\t- name: \"bar\"\n" + + "on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,CreateOptions={}", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + Create: &kubebindv1alpha1.CreateOptions{}, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,AutoDonate=false", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + AutoDonate: false, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,AutoDonate=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + AutoDonate: true, + }, + "The provider wants to create user owned foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,OnConflict={}", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + OnConflict: &kubebindv1alpha1.OnConflictOptions{}, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,Create.ReplaceExisting=false", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + Create: &kubebindv1alpha1.CreateOptions{ + ReplaceExisting: false, + }, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,Create.ReplaceExisting=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + Create: &kubebindv1alpha1.CreateOptions{ + ReplaceExisting: true, + }, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Conflicting objects will be replaced by the provider. " + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,OnConflict.RecreateWhenConsumerSideDeleted=false", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + OnConflict: &kubebindv1alpha1.OnConflictOptions{ + RecreateWhenConsumerSideDeleted: false, + }, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,OnConflict.RecreateWhenConsumerSideDeleted=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + OnConflict: &kubebindv1alpha1.OnConflictOptions{ + RecreateWhenConsumerSideDeleted: true, + }, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Created objects will be recreated upon deletion. " + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,UpdateOptions={}", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + Update: &kubebindv1alpha1.UpdateOptions{}, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,UpdateOptions.Fields", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + Update: &kubebindv1alpha1.UpdateOptions{ + Fields: []string{"foo", "bar"}, + }, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "The following fields of the objects will still be able to be changed by the provider:\n" + // TODO + "\t\"foo\"\n" + + "\t\"bar\"\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,UpdateOptions.Preserving", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + Update: &kubebindv1alpha1.UpdateOptions{ + Preserving: []string{"foo", "bar"}, + }, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "The following fields of the objects will be preserved by the provider:\n" + + "\t\"foo\"\n" + + "\t\"bar\"\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,UpdateOptions.AlwaysRecreate=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + Update: &kubebindv1alpha1.UpdateOptions{ + AlwaysRecreate: true, + }, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Modification of said objects will by handled by deletion and recreation of said objects.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,UpdateOptions.Fields,AutoDonate=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + AutoDonate: true, + Update: &kubebindv1alpha1.UpdateOptions{ + Fields: []string{"foo", "bar"}, + }, + }, + "The provider wants to create user owned foo objects (apiVersion: \"v1\") on your cluster.\n" + + "The following fields of the objects will still be able to be changed by the provider:\n" + + "\t\"foo\"\n" + + "\t\"bar\"\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,UpdateOptions.Preserving,AutoDonate=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + AutoDonate: true, + Update: &kubebindv1alpha1.UpdateOptions{ + Preserving: []string{"foo", "bar"}, + }, + }, + "The provider wants to create user owned foo objects (apiVersion: \"v1\") on your cluster.\n" + + "The following fields of the objects will be preserved by the provider:\n" + + "\t\"foo\"\n" + + "\t\"bar\"\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Required: true, + }, + "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,Selector.Names={bar}", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar"}, + Owner: kubebindv1alpha1.Consumer, + }, + Required: true, + }, + "The provider wants to read foo objects (apiVersion: \"v1\") which are referenced with:\n" + + "\t- name: \"bar\"\n" + + "on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,GroupResource.Group", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "example.com", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Required: true, + }, + "The provider wants to read foo objects (apiVersion: \"example.com/v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,Selector.Names={bar},GroupResource.Group", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "example.com", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar"}, + Owner: kubebindv1alpha1.Consumer, + }, + Required: true, + }, + "The provider wants to read foo objects (apiVersion: \"example.com/v1\") which are referenced with:\n" + + "\t- name: \"bar\"\n" + + "on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,Adopt=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + AutoAdopt: true, + Required: true, + }, + "The provider wants to have ownership of foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,Selector.Names={bar},Adopt=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar"}, + Owner: kubebindv1alpha1.Consumer, + }, + AutoAdopt: true, + Required: true, + }, + "The provider wants to have ownership of foo objects (apiVersion: \"v1\") which are referenced with:\n" + + "\t- name: \"bar\"\n" + + "on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,OnConflict={}", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Required: true, + OnConflict: &kubebindv1alpha1.OnConflictOptions{}, + }, + "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,Create.ReplaceExisting=false", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Required: true, + Create: &kubebindv1alpha1.CreateOptions{ + ReplaceExisting: false, + }, + }, + "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,Create.ReplaceExisting=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Required: true, + Create: &kubebindv1alpha1.CreateOptions{ + ReplaceExisting: true, + }, + }, + "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Conflicting objects will be replaced by the provider. " + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,UpdateOptions={}", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Required: true, + Update: &kubebindv1alpha1.UpdateOptions{}, + }, + "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,UpdateOptions.Fields", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Required: true, + Update: &kubebindv1alpha1.UpdateOptions{ + Fields: []string{"foo", "bar"}, + }, + }, + "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + + "The following fields of the objects will still be able to be changed by the provider:\n" + + "\t\"foo\"\n" + + "\t\"bar\"\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,UpdateOptions.Preserving", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Required: true, + Update: &kubebindv1alpha1.UpdateOptions{ + Preserving: []string{"foo", "bar"}, + }, + }, + "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + + "The following fields of the objects will be preserved by the provider:\n" + + "\t\"foo\"\n" + + "\t\"bar\"\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,UpdateOptions.AlwaysRecreate=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Required: true, + Update: &kubebindv1alpha1.UpdateOptions{ + AlwaysRecreate: true, + }, + }, + "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Modification of said objects will by handled by deletion and recreation of said objects.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,UpdateOptions.Fields,Adopt=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Required: true, + AutoAdopt: true, + Update: &kubebindv1alpha1.UpdateOptions{ + Fields: []string{"foo", "bar"}, + }, + }, + "The provider wants to have ownership of foo objects (apiVersion: \"v1\") on your cluster.\n" + + "The following fields of the objects will still be able to be changed by the provider:\n" + + "\t\"foo\"\n" + + "\t\"bar\"\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Consumer,UpdateOptions.Preserving,Adopt=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Required: true, + AutoAdopt: true, + Update: &kubebindv1alpha1.UpdateOptions{ + Preserving: []string{"foo", "bar"}, + }, + }, + "The provider wants to have ownership of foo objects (apiVersion: \"v1\") on your cluster.\n" + + "The following fields of the objects will be preserved by the provider:\n" + " \"foo\"\n" + + "\t\"bar\"\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Selector={}", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{}, + Required: true, + }, + "The provider wants to read and write foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Selector.Owner=\"\",Selector.Names={bar}", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar"}, + }, + Required: true, + }, + "The provider wants to read and write foo objects (apiVersion: \"v1\") which are referenced with:\n" + + "\t- name: \"bar\"\n" + + "on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Selector={},AutoDonate=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{}, + Required: true, + AutoDonate: true, + }, + "The provider wants to create user owned foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Selector={},AutoDonate=true,update.Fields=[\"spec\"]", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{}, + AutoDonate: true, + Update: &kubebindv1alpha1.UpdateOptions{ + Fields: []string{"spec"}, + }, + }, + "The provider wants to create user owned foo objects (apiVersion: \"v1\") on your cluster.\n" + + "The following fields of the objects will still be able to be changed by the provider:\n" + + "\t\"spec\"\n" + + "Accepting this Permission is optional.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Selector={},adopt=true", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{}, + Required: true, + AutoAdopt: true, + }, + "The provider wants to have ownership of foo objects (apiVersion: \"v1\") on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Selector={},adopt=true,update.Fields=[\"spec\"]", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{}, + AutoAdopt: true, + Update: &kubebindv1alpha1.UpdateOptions{ + Fields: []string{"spec"}, + }, + }, + "The provider wants to have ownership of foo objects (apiVersion: \"v1\") on your cluster.\n" + + "The following fields of the objects will still be able to be changed by the provider:\n" + + "\t\"spec\"\n" + + "Accepting this Permission is optional.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + {"Owner=Provider,Selector.Names={bar,baz}", + kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar", "baz"}, + Owner: kubebindv1alpha1.Provider, + }, + Required: true, + }, + "The provider wants to write foo objects (apiVersion: \"v1\") which are referenced with:\n" + + "\t- name: \"bar\"\n" + + "\t- name: \"baz\"\n" + + "on your cluster.\n" + + "Accepting this Permission is required in order to proceed.\n" + + "Do you accept this Permission? [No,Yes]\n", + }, + } + + for _, tt := range tests { + tt := tt + t.Run(tt.name, func(t *testing.T) { + t.Parallel() + var output bytes.Buffer + var input bytes.Buffer + input.WriteString("y\n") + opts := NewBindAPIServiceOptions(genericclioptions.IOStreams{In: &input, Out: &output, ErrOut: os.Stderr}) + b, err := opts.promptYesNo(tt.testData) + if output.String() != tt.expectedOutput { + t.Errorf("Expected IO Output did not match. got: \"\n%s\"\nwanted: \"\n%s\"\n", output.String(), tt.expectedOutput) + } + if b == false || (err != nil) { + t.Errorf("Expected Return value did not match. got: \"%v\", \"%v\"", b, err) + } + }) + } +} From f0dee162f8a5b86e2bbd66a00a7a6463d5cf7a8f Mon Sep 17 00:00:00 2001 From: a9s-niklas-kempf <103116383+a9s-niklas-kempf@users.noreply.github.com> Date: Tue, 6 Jun 2023 11:12:13 +0200 Subject: [PATCH 02/12] Add readable prompts for permission claims (#1) Add human readable prompts for permission claims to cli plugin Add unit tests for permission claim prompts --- deploy/crd/kube-bind.io_apiserviceexporttemplates.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deploy/crd/kube-bind.io_apiserviceexporttemplates.yaml b/deploy/crd/kube-bind.io_apiserviceexporttemplates.yaml index c11a2da9d..2a15d271d 100644 --- a/deploy/crd/kube-bind.io_apiserviceexporttemplates.yaml +++ b/deploy/crd/kube-bind.io_apiserviceexporttemplates.yaml @@ -77,7 +77,7 @@ spec: properties: donate: description: donate set to true means that a newly created - object by the provider is immediately owned by hte consumer. + object by the provider is immediately owned by the consumer. If false, the object stays in ownership of the provider type: boolean type: object From 5f5a8ccf169aff30695afd69641acbae27fdf382 Mon Sep 17 00:00:00 2001 From: lhaendler <94445906+lhaendler@users.noreply.github.com> Date: Wed, 18 Oct 2023 15:00:42 +0200 Subject: [PATCH 03/12] Update pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go Co-authored-by: Dr. Stefan Schimanski --- deploy/crd/kube-bind.io_apiservicebindings.yaml | 8 ++++---- .../crd/kube-bind.io_apiserviceexportrequests.yaml | 14 +++++++------- deploy/crd/kube-bind.io_apiserviceexports.yaml | 8 ++++---- .../kubebind/v1alpha1/apiservicebinding_types.go | 6 +++--- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/deploy/crd/kube-bind.io_apiservicebindings.yaml b/deploy/crd/kube-bind.io_apiservicebindings.yaml index bc67a56cf..0526187ff 100644 --- a/deploy/crd/kube-bind.io_apiservicebindings.yaml +++ b/deploy/crd/kube-bind.io_apiservicebindings.yaml @@ -144,10 +144,10 @@ spec: type: object read: description: read claims read access to matching objects for - the provider. reading of the claimed object(s) is always claimed. - By default no labels and annotations are read. Reading of - labels and annotations can be claimed optionally by adding - labels and annotations items. If labels on consumer owned + the provider. Reading of the claimed object(s) is always claimed. + By default, no labels and annotations can be read by the provider. + Reading of labels and annotations can be claimed in addition + by specifying them explicitly. If labels on consumer owned objects that are set by the consumer are read, labelsOnProviderOwnedObjects and annotationsOnProviderOwnedObjects can be set. properties: diff --git a/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml b/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml index bbddb1d1d..ab624a6ba 100644 --- a/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml +++ b/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml @@ -126,13 +126,13 @@ spec: type: object read: description: read claims read access to matching objects - for the provider. reading of the claimed object(s) is - always claimed. By default no labels and annotations - are read. Reading of labels and annotations can be claimed - optionally by adding labels and annotations items. If - labels on consumer owned objects that are set by the - consumer are read, labelsOnProviderOwnedObjects and - annotationsOnProviderOwnedObjects can be set. + for the provider. Reading of the claimed object(s) is + always claimed. By default, no labels and annotations + can be read by the provider. Reading of labels and annotations + can be claimed in addition by specifying them explicitly. + If labels on consumer owned objects that are set by + the consumer are read, labelsOnProviderOwnedObjects + and annotationsOnProviderOwnedObjects can be set. properties: annotations: description: annotations is a list of claimed annotation diff --git a/deploy/crd/kube-bind.io_apiserviceexports.yaml b/deploy/crd/kube-bind.io_apiserviceexports.yaml index d99e6bfc6..e4bfbc48a 100644 --- a/deploy/crd/kube-bind.io_apiserviceexports.yaml +++ b/deploy/crd/kube-bind.io_apiserviceexports.yaml @@ -163,10 +163,10 @@ spec: type: object read: description: read claims read access to matching objects for - the provider. reading of the claimed object(s) is always claimed. - By default no labels and annotations are read. Reading of - labels and annotations can be claimed optionally by adding - labels and annotations items. If labels on consumer owned + the provider. Reading of the claimed object(s) is always claimed. + By default, no labels and annotations can be read by the provider. + Reading of labels and annotations can be claimed in addition + by specifying them explicitly. If labels on consumer owned objects that are set by the consumer are read, labelsOnProviderOwnedObjects and annotationsOnProviderOwnedObjects can be set. properties: diff --git a/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go b/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go index 47c37ae9b..1e68ee027 100644 --- a/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go +++ b/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go @@ -140,9 +140,9 @@ type PermissionClaim struct { Required bool `json:"required"` // read claims read access to matching objects for the provider. - // reading of the claimed object(s) is always claimed. - // By default no labels and annotations are read. Reading of labels and annotations can be claimed - // optionally by adding labels and annotations items. + // Reading of the claimed object(s) is always claimed. + // By default, no labels and annotations can be read by the provider. + // Reading of labels and annotations can be claimed in addition by specifying them explicitly. // If labels on consumer owned objects that are set by the consumer are read, labelsOnProviderOwnedObjects and // annotationsOnProviderOwnedObjects can be set. // From 3b991fb2efc4bd53fc5f1f8b90926fed2b1ff48b Mon Sep 17 00:00:00 2001 From: lhaendler <94445906+lhaendler@users.noreply.github.com> Date: Wed, 18 Oct 2023 15:03:15 +0200 Subject: [PATCH 04/12] Update pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go Co-authored-by: Dr. Stefan Schimanski --- deploy/crd/kube-bind.io_apiservicebindings.yaml | 4 ++-- deploy/crd/kube-bind.io_apiserviceexportrequests.yaml | 2 +- deploy/crd/kube-bind.io_apiserviceexports.yaml | 4 ++-- pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/deploy/crd/kube-bind.io_apiservicebindings.yaml b/deploy/crd/kube-bind.io_apiservicebindings.yaml index 0526187ff..3ae4f79a3 100644 --- a/deploy/crd/kube-bind.io_apiservicebindings.yaml +++ b/deploy/crd/kube-bind.io_apiservicebindings.yaml @@ -114,8 +114,8 @@ spec: replaceExisting: description: "replaceExisting means that an existing object owned by the consumer will be replaced by the provider - object. \n If set to false, and a conflicting consumer - object exists, it is not touched." + object. \n If not true, and a conflicting consumer object + exists, it is not touched." type: boolean type: object group: diff --git a/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml b/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml index ab624a6ba..4cc667492 100644 --- a/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml +++ b/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml @@ -95,7 +95,7 @@ spec: replaceExisting: description: "replaceExisting means that an existing object owned by the consumer will be replaced by - the provider object. \n If set to false, and a conflicting + the provider object. \n If not true, and a conflicting consumer object exists, it is not touched." type: boolean type: object diff --git a/deploy/crd/kube-bind.io_apiserviceexports.yaml b/deploy/crd/kube-bind.io_apiserviceexports.yaml index e4bfbc48a..299177a5c 100644 --- a/deploy/crd/kube-bind.io_apiserviceexports.yaml +++ b/deploy/crd/kube-bind.io_apiserviceexports.yaml @@ -133,8 +133,8 @@ spec: replaceExisting: description: "replaceExisting means that an existing object owned by the consumer will be replaced by the provider - object. \n If set to false, and a conflicting consumer - object exists, it is not touched." + object. \n If not true, and a conflicting consumer object + exists, it is not touched." type: boolean type: object group: diff --git a/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go b/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go index 1e68ee027..3d9d69121 100644 --- a/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go +++ b/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go @@ -236,7 +236,7 @@ type OnConflictOptions struct { type CreateOptions struct { // replaceExisting means that an existing object owned by the consumer will be replaced by the provider object. // - // If set to false, and a conflicting consumer object exists, it is not touched. + // If not true, and a conflicting consumer object exists, it is not touched. // // +optional ReplaceExisting bool `json:"replaceExisting,omitempty"` From 977be3127f8e2b7f08fe2ea5d07e35a789397045 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lenny=20H=C3=A4ndler?= Date: Wed, 18 Oct 2023 15:36:09 +0200 Subject: [PATCH 05/12] Remove redundant paragraph --- deploy/crd/kube-bind.io_apiservicebindings.yaml | 6 +----- deploy/crd/kube-bind.io_apiserviceexportrequests.yaml | 7 +------ deploy/crd/kube-bind.io_apiserviceexports.yaml | 6 +----- pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go | 4 ---- 4 files changed, 3 insertions(+), 20 deletions(-) diff --git a/deploy/crd/kube-bind.io_apiservicebindings.yaml b/deploy/crd/kube-bind.io_apiservicebindings.yaml index 3ae4f79a3..d1a27c04e 100644 --- a/deploy/crd/kube-bind.io_apiservicebindings.yaml +++ b/deploy/crd/kube-bind.io_apiservicebindings.yaml @@ -135,11 +135,7 @@ spec: in case the object is missing on the consumer cluster, but has been synchronized before. \n If set to false, deleted provider-owned objects get deleted on the provider - cluster as well. \n Even if the consumer mistakenly or - intentionally deletes the object, the provider will recreate - it. If the field is set as false, the provider will not - recreate the object in case the object is deleted on the - consumer cluster." + cluster as well." type: boolean type: object read: diff --git a/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml b/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml index 4cc667492..509cd1784 100644 --- a/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml +++ b/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml @@ -116,12 +116,7 @@ spec: the object in case the object is missing on the consumer cluster, but has been synchronized before. \n If set to false, deleted provider-owned objects - get deleted on the provider cluster as well. \n - Even if the consumer mistakenly or intentionally - deletes the object, the provider will recreate it. - If the field is set as false, the provider will - not recreate the object in case the object is deleted - on the consumer cluster." + get deleted on the provider cluster as well." type: boolean type: object read: diff --git a/deploy/crd/kube-bind.io_apiserviceexports.yaml b/deploy/crd/kube-bind.io_apiserviceexports.yaml index 299177a5c..f1a8d6c33 100644 --- a/deploy/crd/kube-bind.io_apiserviceexports.yaml +++ b/deploy/crd/kube-bind.io_apiserviceexports.yaml @@ -154,11 +154,7 @@ spec: in case the object is missing on the consumer cluster, but has been synchronized before. \n If set to false, deleted provider-owned objects get deleted on the provider - cluster as well. \n Even if the consumer mistakenly or - intentionally deletes the object, the provider will recreate - it. If the field is set as false, the provider will not - recreate the object in case the object is deleted on the - consumer cluster." + cluster as well." type: boolean type: object read: diff --git a/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go b/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go index 3d9d69121..cc306946a 100644 --- a/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go +++ b/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go @@ -225,10 +225,6 @@ type OnConflictOptions struct { // // If set to false, deleted provider-owned objects get deleted on the provider cluster as well. // - // Even if the consumer mistakenly or intentionally - // deletes the object, the provider will recreate it. If the field is set as false, - // the provider will not recreate the object in case the object is deleted on the consumer cluster. - // // +kubebuilder:default:=true RecreateWhenConsumerSideDeleted bool `json:"recreateWhenConsumerSideDeleted"` } From 0e45d826a34ed61c5e86ddb28a955117bbf8bc98 Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Mon, 23 Oct 2023 16:44:06 +0200 Subject: [PATCH 06/12] apis: move permission claims to their own file Signed-off-by: Dr. Stefan Schimanski --- .../v1alpha1/apiservicebinding_types.go | 226 ---------------- .../v1alpha1/permissionclaims_types.go | 243 ++++++++++++++++++ 2 files changed, 243 insertions(+), 226 deletions(-) create mode 100644 pkg/apis/kubebind/v1alpha1/permissionclaims_types.go diff --git a/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go b/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go index cc306946a..9d6ecf460 100644 --- a/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go +++ b/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go @@ -116,232 +116,6 @@ const ( ClaimRejected AcceptablePermissionClaimState = "Rejected" ) -// permissionClaim selects objects of a GVR that a service provider may -// request and that a consumer may accept and allow the service provider access to. -// -// +kubebuilder:validation:XValidation:rule="!(has(self.autoDonate) && self.autoDonate && has(self.autoAdopt) && self.autoAdopt)",message="donate and adopt are mutually exclusive" -type PermissionClaim struct { - GroupResource `json:","` - - // version is the version of the claimed resource. - // - // +kubebuilder:validation:Required - // +kubebuilder:validation:MinLength:=1 - Version string `json:"version"` - - // selector selects which resources are being claimed. - // If unset, all resources across all namespaces are being claimed. - // - // +optional - // +kubebuilder:default:={} - Selector *ResourceSelector `json:"selector,omitempty"` - - // required indicates whether the APIServiceBinding will work if this claim is not accepted. If a required claim is denied, the binding is aborted. - Required bool `json:"required"` - - // read claims read access to matching objects for the provider. - // Reading of the claimed object(s) is always claimed. - // By default, no labels and annotations can be read by the provider. - // Reading of labels and annotations can be claimed in addition by specifying them explicitly. - // If labels on consumer owned objects that are set by the consumer are read, labelsOnProviderOwnedObjects and - // annotationsOnProviderOwnedObjects can be set. - // - // +optional - // +kubebuilder:default={} - Read *ReadOptions `json:"read,omitempty"` - - // create determines whether the kube-bind konnector will sync matching objects from the - // provider cluster down to the consumer cluster. - // only for owner Provider - // - // +optional - Create *CreateOptions `json:"create,omitempty"` - - // autoAdopt set to true means that objects created by the consumer are adopted by the provider. - // i.e. the provider will become the owner. - // Mutually exclusive with autoDonate. - // - // +optional - AutoAdopt bool `json:"autoAdopt,omitempty"` - - // autoDonate set to true means that a newly created object by the provider is immediately owned by the consumer. - // If false, the object stays in ownership of the provider. - // Mutually exclusive with autoDonate. - // - // +optional - AutoDonate bool `json:"autoDonate,omitempty"` - - // onConflict determines how the conflicts between objects on the consumer cluster will be resolved. - // - // +optional - // +kubebuilder:default:={} - OnConflict *OnConflictOptions `json:"onConflict,omitempty"` - - // update lists which updates to objects on the consumer cluster are claimed. - // By default, the whole object is synced, but metadata is not. - // - // +optional - Update *UpdateOptions `json:"update,omitempty"` -} - -type ReadOptions struct { - // labels is a list of claimed label key wildcard patterns - // that are synchronized from the consumer cluster to the provider on - // objects that are owned by the consumer. - // - // +optional - Labels []Matcher `json:"labels,omitempty"` - - // labelsOnProviderOwnedObjects is a list of claimed label key wildcard - // patterns that are synchronized from the consumer cluster - // to the provider on objects owned by the provider. - // - // +optional - LabelsOnProviderOwnedObjects []Matcher `json:"labelsOnProviderOwnedObjects,omitempty"` - - // annotations is a list of claimed annotation key wildcard patterns - // that are synchronized from the consumer cluster to the provider on - // objects that are owned by the consumer. - // - // +optional - Annotations []Matcher `json:"annotations,omitempty"` - - // overrideAnnotations is a list of claimed annotation key wildcard - // patterns that are synchronized from the consumer cluster - // to the provider on objects owned by the provider. - // - // +optional - OverrideAnnotations []Matcher `json:"overrideAnnotations,omitempty"` -} - -type Matcher struct { - // +optional - Pattern string `json:"pattern,omitempty"` -} - -type OnConflictOptions struct { - // recreateWhenConsumerSideDeleted set to true (the default) means the provider will recreate the object - // in case the object is missing on the consumer cluster, but has been synchronized before. - // - // If set to false, deleted provider-owned objects get deleted on the provider cluster as well. - // - // +kubebuilder:default:=true - RecreateWhenConsumerSideDeleted bool `json:"recreateWhenConsumerSideDeleted"` -} - -type CreateOptions struct { - // replaceExisting means that an existing object owned by the consumer will be replaced by the provider object. - // - // If not true, and a conflicting consumer object exists, it is not touched. - // - // +optional - ReplaceExisting bool `json:"replaceExisting,omitempty"` -} - -type UpdateOptions struct { - // fields are a list of JSON Paths describing which parts of an object the provider wants to control. - // - // This field is ignored if the owner in the claim selector is set to "Provider". - // - // +optional - Fields []string `json:"fields,omitempty"` - - // preserving is a list of JSON Paths describing which parts of an object owned by the provider the consumer keeps controlling. - // - // This field is ignored if the owner in the claim selector is set to "Consumer". - // - // +optional - Preserving []string `json:"preserving,omitempty"` - - // alwaysRecreate, when true will delete the old object and create new ones - // instead of updating. Useful for immutable objects. - // - // This does not apply to metadata field updates. - // - // +optional - AlwaysRecreate bool `json:"alwaysRecreate,omitempty"` - - // labels is a list of claimed label keys or label wildcard patterns that are synchronized from the provider to the consumer for objects owned by the provider. - // - // By default, no labels are synced. - // - // +optional - Labels []Matcher `json:"labels,omitempty"` - - // labelsOnConsumerOwnedObjects is a list of claimed label key wildcard patterns that are synchronized from the provider to the consumer for objects owned by the consumer. - // - // By default, no labels are synced. - // - // +optional - LabelsOnConsumerOwnedObjects []Matcher `json:"labelsOnConsumerOwnedObjects,omitempty"` - - // annotations is a list of claimed annotation keys or annotation wildcard patterns that are synchronized from the provider to the consumer for objects owned by the provider. - // - // By default, no annotations are synced. - // - // +optional - Annotations []Matcher `json:"annotations,omitempty"` - - // annotationsOnConsumerOwnedObjects is a list of claimed annotation key wildcard patterns that are synchronized from the provider to the consumer for objects owned by the consumer. - // - // By default, no annotations are synced. - // - // +optional - AnnotationsOnConsumerOwnedObjects []Matcher `json:"annotationsOnConsumerOwnedObjects,omitempty"` -} - -type ResourceSelector struct { - // names is a list of specific resource names to select. - // Names matches the metadata.name field of the underlying object. - // An entry of "*" anywhere in the list means all object names of the group/resource within the "namespaces" field are claimed. - // Wildcard entries other than "*" and regular expressions are currently unsupported. - // If a resources name matches any value in names, the resource name is considered matching. - // - // // +kubebuilder:validation:XValidation:rule="self.all(n, n.matches('^[A-z-]+|[*]$'))",message="only names or * are allowed" - // +kubebuilder:default:={"*"} - // +optional - Names []string `json:"names,omitempty"` - - // namespaces represents namespaces where an object of the given group/resource may be managed. - // Namespaces matches against the metadata.namespace field. A value of "*" matches namespaced objects across all namespaces. - // If a resources namespace matches any value in namespaces, the resource namespace is considered matching. - // If the claim is for a cluster-scoped resource, namespaces has to explicitly be set to an empty array to prevent defaulting to "*". - // If the "names" field is unset, all objects of the group/resource within the listed namespaces (or cluster) will be claimed. - // - // // +kubebuilder:validation:XValidation:rule="self.all(n, n.matches('^[A-z-]+|[*]$'))",message="only names or * are allowed" - // +kubebuilder:default:={"*"} - // +optional - Namespaces []string `json:"namespaces,omitempty"` - - // labelSelectors is a list of label selectors matching selected resources. label selectors follow the same rules as kubernetes label selectors, - // see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. - LabelSelectors []map[string]string `json:"labelSelectors,omitempty"` - - // fieldSelectors is a list of field selectors matching selected resources, - // see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/. - FieldSelectors []string `json:"fieldSelectors,omitempty"` - - // owner matches the resource's owner. If an owner selector is set, resources owned by other owners will not be claimed. - // Resources without a present owner will be considered, if configured owner could be the owner of the object. - // For example, if the consumer creates a resource that is claimed by the provider for reading. In this case the resource - // will be marked as owned by the consumer, and handled as such in further reconciliations. - // An unset owner selector means objects from both sides are considered. - // - // +kubebuilder:validation:Enum=Provider;Consumer - // +optional - Owner Owner `json:"owner,omitempty"` -} - -type Owner string - -const ( - // provider means that the owner of the resource is the Provider. - Provider Owner = "Provider" - - // consumer means that the owner of the resource is the Consumer. - Consumer Owner = "Consumer" -) - type APIServiceBindingStatus struct { // providerPrettyName is the pretty name of the service provider cluster. This // can be shared among different APIServiceBindings. diff --git a/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go b/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go new file mode 100644 index 000000000..8f857ab69 --- /dev/null +++ b/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go @@ -0,0 +1,243 @@ +/* +Copyright 2022 The Kube Bind Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package v1alpha1 + +// PermissionClaim selects objects of a GVR that a service provider may +// request and that a consumer may accept and allow the service provider access to. +// +// +kubebuilder:validation:XValidation:rule="!(has(self.autoDonate) && self.autoDonate && has(self.autoAdopt) && self.autoAdopt)",message="donate and adopt are mutually exclusive" +type PermissionClaim struct { + GroupResource `json:","` + + // version is the version of the claimed resource. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength:=1 + Version string `json:"version"` + + // selector selects which resources are being claimed. + // If unset, all resources across all namespaces are being claimed. + // + // +optional + // +kubebuilder:default:={} + Selector *ResourceSelector `json:"selector,omitempty"` + + // required indicates whether the APIServiceBinding will work if this claim is not accepted. If a required claim is denied, the binding is aborted. + Required bool `json:"required"` + + // read claims read access to matching objects for the provider. + // Reading of the claimed object(s) is always claimed. + // By default, no labels and annotations can be read by the provider. + // Reading of labels and annotations can be claimed in addition by specifying them explicitly. + // If labels on consumer owned objects that are set by the consumer are read, labelsOnProviderOwnedObjects and + // annotationsOnProviderOwnedObjects can be set. + // + // +optional + // +kubebuilder:default={} + Read *ReadOptions `json:"read,omitempty"` + + // create determines whether the kube-bind konnector will sync matching objects from the + // provider cluster down to the consumer cluster. + // only for owner Provider + // + // +optional + Create *CreateOptions `json:"create,omitempty"` + + // autoAdopt set to true means that objects created by the consumer are adopted by the provider. + // i.e. the provider will become the owner. + // Mutually exclusive with autoDonate. + // + // +optional + AutoAdopt bool `json:"autoAdopt,omitempty"` + + // autoDonate set to true means that a newly created object by the provider is immediately owned by the consumer. + // If false, the object stays in ownership of the provider. + // Mutually exclusive with autoDonate. + // + // +optional + AutoDonate bool `json:"autoDonate,omitempty"` + + // onConflict determines how the conflicts between objects on the consumer cluster will be resolved. + // + // +optional + // +kubebuilder:default:={} + OnConflict *OnConflictOptions `json:"onConflict,omitempty"` + + // update lists which updates to objects on the consumer cluster are claimed. + // By default, the whole object is synced, but metadata is not. + // + // +optional + Update *UpdateOptions `json:"update,omitempty"` +} + +type ReadOptions struct { + // labels is a list of claimed label key wildcard patterns + // that are synchronized from the consumer cluster to the provider on + // objects that are owned by the consumer. + // + // +optional + Labels []Matcher `json:"labels,omitempty"` + + // labelsOnProviderOwnedObjects is a list of claimed label key wildcard + // patterns that are synchronized from the consumer cluster + // to the provider on objects owned by the provider. + // + // +optional + LabelsOnProviderOwnedObjects []Matcher `json:"labelsOnProviderOwnedObjects,omitempty"` + + // annotations is a list of claimed annotation key wildcard patterns + // that are synchronized from the consumer cluster to the provider on + // objects that are owned by the consumer. + // + // +optional + Annotations []Matcher `json:"annotations,omitempty"` + + // overrideAnnotations is a list of claimed annotation key wildcard + // patterns that are synchronized from the consumer cluster + // to the provider on objects owned by the provider. + // + // +optional + OverrideAnnotations []Matcher `json:"overrideAnnotations,omitempty"` +} + +type Matcher struct { + // +optional + Pattern string `json:"pattern,omitempty"` +} + +type OnConflictOptions struct { + // recreateWhenConsumerSideDeleted set to true (the default) means the provider will recreate the object + // in case the object is missing on the consumer cluster, but has been synchronized before. + // + // If set to false, deleted provider-owned objects get deleted on the provider cluster as well. + // + // +kubebuilder:default:=true + RecreateWhenConsumerSideDeleted bool `json:"recreateWhenConsumerSideDeleted"` +} + +type CreateOptions struct { + // replaceExisting means that an existing object owned by the consumer will be replaced by the provider object. + // + // If not true, and a conflicting consumer object exists, it is not touched. + // + // +optional + ReplaceExisting bool `json:"replaceExisting,omitempty"` +} + +type UpdateOptions struct { + // fields are a list of JSON Paths describing which parts of an object the provider wants to control. + // + // This field is ignored if the owner in the claim selector is set to "Provider". + // + // +optional + Fields []string `json:"fields,omitempty"` + + // preserving is a list of JSON Paths describing which parts of an object owned by the provider the consumer keeps controlling. + // + // This field is ignored if the owner in the claim selector is set to "Consumer". + // + // +optional + Preserving []string `json:"preserving,omitempty"` + + // alwaysRecreate, when true will delete the old object and create new ones + // instead of updating. Useful for immutable objects. + // + // This does not apply to metadata field updates. + // + // +optional + AlwaysRecreate bool `json:"alwaysRecreate,omitempty"` + + // labels is a list of claimed label keys or label wildcard patterns that are synchronized from the provider to the consumer for objects owned by the provider. + // + // By default, no labels are synced. + // + // +optional + Labels []Matcher `json:"labels,omitempty"` + + // labelsOnConsumerOwnedObjects is a list of claimed label key wildcard patterns that are synchronized from the provider to the consumer for objects owned by the consumer. + // + // By default, no labels are synced. + // + // +optional + LabelsOnConsumerOwnedObjects []Matcher `json:"labelsOnConsumerOwnedObjects,omitempty"` + + // annotations is a list of claimed annotation keys or annotation wildcard patterns that are synchronized from the provider to the consumer for objects owned by the provider. + // + // By default, no annotations are synced. + // + // +optional + Annotations []Matcher `json:"annotations,omitempty"` + + // annotationsOnConsumerOwnedObjects is a list of claimed annotation key wildcard patterns that are synchronized from the provider to the consumer for objects owned by the consumer. + // + // By default, no annotations are synced. + // + // +optional + AnnotationsOnConsumerOwnedObjects []Matcher `json:"annotationsOnConsumerOwnedObjects,omitempty"` +} + +type ResourceSelector struct { + // names is a list of specific resource names to select. + // Names matches the metadata.name field of the underlying object. + // An entry of "*" anywhere in the list means all object names of the group/resource within the "namespaces" field are claimed. + // Wildcard entries other than "*" and regular expressions are currently unsupported. + // If a resources name matches any value in names, the resource name is considered matching. + // + // // +kubebuilder:validation:XValidation:rule="self.all(n, n.matches('^[A-z-]+|[*]$'))",message="only names or * are allowed" + // +kubebuilder:default:={"*"} + // +optional + Names []string `json:"names,omitempty"` + + // namespaces represents namespaces where an object of the given group/resource may be managed. + // Namespaces matches against the metadata.namespace field. A value of "*" matches namespaced objects across all namespaces. + // If a resources namespace matches any value in namespaces, the resource namespace is considered matching. + // If the claim is for a cluster-scoped resource, namespaces has to explicitly be set to an empty array to prevent defaulting to "*". + // If the "names" field is unset, all objects of the group/resource within the listed namespaces (or cluster) will be claimed. + // + // // +kubebuilder:validation:XValidation:rule="self.all(n, n.matches('^[A-z-]+|[*]$'))",message="only names or * are allowed" + // +kubebuilder:default:={"*"} + // +optional + Namespaces []string `json:"namespaces,omitempty"` + + // labelSelectors is a list of label selectors matching selected resources. label selectors follow the same rules as kubernetes label selectors, + // see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. + LabelSelectors []map[string]string `json:"labelSelectors,omitempty"` + + // fieldSelectors is a list of field selectors matching selected resources, + // see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/. + FieldSelectors []string `json:"fieldSelectors,omitempty"` + + // owner matches the resource's owner. If an owner selector is set, resources owned by other owners will not be claimed. + // Resources without a present owner will be considered, if configured owner could be the owner of the object. + // For example, if the consumer creates a resource that is claimed by the provider for reading. In this case the resource + // will be marked as owned by the consumer, and handled as such in further reconciliations. + // An unset owner selector means objects from both sides are considered. + // + // +kubebuilder:validation:Enum=Provider;Consumer + // +optional + Owner Owner `json:"owner,omitempty"` +} + +type Owner string + +const ( + // provider means that the owner of the resource is the Provider. + Provider Owner = "Provider" + + // consumer means that the owner of the resource is the Consumer. + Consumer Owner = "Consumer" +) From fbb4984c2d516c616e5d1ff22fb193291b362b74 Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Mon, 23 Oct 2023 16:48:21 +0200 Subject: [PATCH 07/12] apis: qualify permission claim types Signed-off-by: Dr. Stefan Schimanski --- .../v1alpha1/permissionclaims_types.go | 24 +++++----- .../v1alpha1/zz_generated.deepcopy.go | 40 ++++++++-------- .../bind-apiservice/plugin/servicebindings.go | 2 +- .../plugin/servicebindings_test.go | 46 +++++++++---------- 4 files changed, 56 insertions(+), 56 deletions(-) diff --git a/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go b/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go index 8f857ab69..72029aa49 100644 --- a/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go +++ b/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go @@ -48,14 +48,14 @@ type PermissionClaim struct { // // +optional // +kubebuilder:default={} - Read *ReadOptions `json:"read,omitempty"` + Read *PermissionClaimReadOptions `json:"read,omitempty"` // create determines whether the kube-bind konnector will sync matching objects from the // provider cluster down to the consumer cluster. // only for owner Provider // // +optional - Create *CreateOptions `json:"create,omitempty"` + Create *PermissionClaimCreateOptions `json:"create,omitempty"` // autoAdopt set to true means that objects created by the consumer are adopted by the provider. // i.e. the provider will become the owner. @@ -75,16 +75,16 @@ type PermissionClaim struct { // // +optional // +kubebuilder:default:={} - OnConflict *OnConflictOptions `json:"onConflict,omitempty"` + OnConflict *PermissionClaimOnConflictOptions `json:"onConflict,omitempty"` // update lists which updates to objects on the consumer cluster are claimed. // By default, the whole object is synced, but metadata is not. // // +optional - Update *UpdateOptions `json:"update,omitempty"` + Update *PermissionClaimUpdateOptions `json:"update,omitempty"` } -type ReadOptions struct { +type PermissionClaimReadOptions struct { // labels is a list of claimed label key wildcard patterns // that are synchronized from the consumer cluster to the provider on // objects that are owned by the consumer. @@ -119,7 +119,7 @@ type Matcher struct { Pattern string `json:"pattern,omitempty"` } -type OnConflictOptions struct { +type PermissionClaimOnConflictOptions struct { // recreateWhenConsumerSideDeleted set to true (the default) means the provider will recreate the object // in case the object is missing on the consumer cluster, but has been synchronized before. // @@ -129,7 +129,7 @@ type OnConflictOptions struct { RecreateWhenConsumerSideDeleted bool `json:"recreateWhenConsumerSideDeleted"` } -type CreateOptions struct { +type PermissionClaimCreateOptions struct { // replaceExisting means that an existing object owned by the consumer will be replaced by the provider object. // // If not true, and a conflicting consumer object exists, it is not touched. @@ -138,7 +138,7 @@ type CreateOptions struct { ReplaceExisting bool `json:"replaceExisting,omitempty"` } -type UpdateOptions struct { +type PermissionClaimUpdateOptions struct { // fields are a list of JSON Paths describing which parts of an object the provider wants to control. // // This field is ignored if the owner in the claim selector is set to "Provider". @@ -229,15 +229,15 @@ type ResourceSelector struct { // // +kubebuilder:validation:Enum=Provider;Consumer // +optional - Owner Owner `json:"owner,omitempty"` + Owner PermissionCaimResourceOwner `json:"owner,omitempty"` } -type Owner string +type PermissionCaimResourceOwner string const ( // provider means that the owner of the resource is the Provider. - Provider Owner = "Provider" + Provider PermissionCaimResourceOwner = "Provider" // consumer means that the owner of the resource is the Consumer. - Consumer Owner = "Consumer" + Consumer PermissionCaimResourceOwner = "Consumer" ) diff --git a/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go index b1bb2ca50..2889da312 100644 --- a/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go @@ -848,17 +848,17 @@ func (in *ClusterSecretKeyRef) DeepCopy() *ClusterSecretKeyRef { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *CreateOptions) DeepCopyInto(out *CreateOptions) { +func (in *PermissionClaimCreateOptions) DeepCopyInto(out *PermissionClaimCreateOptions) { *out = *in return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CreateOptions. -func (in *CreateOptions) DeepCopy() *CreateOptions { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PermissionClaimCreateOptions. +func (in *PermissionClaimCreateOptions) DeepCopy() *PermissionClaimCreateOptions { if in == nil { return nil } - out := new(CreateOptions) + out := new(PermissionClaimCreateOptions) in.DeepCopyInto(out) return out } @@ -944,17 +944,17 @@ func (in *OAuth2CodeGrant) DeepCopy() *OAuth2CodeGrant { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *OnConflictOptions) DeepCopyInto(out *OnConflictOptions) { +func (in *PermissionClaimOnConflictOptions) DeepCopyInto(out *PermissionClaimOnConflictOptions) { *out = *in return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OnConflictOptions. -func (in *OnConflictOptions) DeepCopy() *OnConflictOptions { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PermissionClaimOnConflictOptions. +func (in *PermissionClaimOnConflictOptions) DeepCopy() *PermissionClaimOnConflictOptions { if in == nil { return nil } - out := new(OnConflictOptions) + out := new(PermissionClaimOnConflictOptions) in.DeepCopyInto(out) return out } @@ -970,22 +970,22 @@ func (in *PermissionClaim) DeepCopyInto(out *PermissionClaim) { } if in.Read != nil { in, out := &in.Read, &out.Read - *out = new(ReadOptions) + *out = new(PermissionClaimReadOptions) (*in).DeepCopyInto(*out) } if in.Create != nil { in, out := &in.Create, &out.Create - *out = new(CreateOptions) + *out = new(PermissionClaimCreateOptions) **out = **in } if in.OnConflict != nil { in, out := &in.OnConflict, &out.OnConflict - *out = new(OnConflictOptions) + *out = new(PermissionClaimOnConflictOptions) **out = **in } if in.Update != nil { in, out := &in.Update, &out.Update - *out = new(UpdateOptions) + *out = new(PermissionClaimUpdateOptions) (*in).DeepCopyInto(*out) } return @@ -1002,7 +1002,7 @@ func (in *PermissionClaim) DeepCopy() *PermissionClaim { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ReadOptions) DeepCopyInto(out *ReadOptions) { +func (in *PermissionClaimReadOptions) DeepCopyInto(out *PermissionClaimReadOptions) { *out = *in if in.Labels != nil { in, out := &in.Labels, &out.Labels @@ -1027,12 +1027,12 @@ func (in *ReadOptions) DeepCopyInto(out *ReadOptions) { return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ReadOptions. -func (in *ReadOptions) DeepCopy() *ReadOptions { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PermissionClaimReadOptions. +func (in *PermissionClaimReadOptions) DeepCopy() *PermissionClaimReadOptions { if in == nil { return nil } - out := new(ReadOptions) + out := new(PermissionClaimReadOptions) in.DeepCopyInto(out) return out } @@ -1082,7 +1082,7 @@ func (in *ResourceSelector) DeepCopy() *ResourceSelector { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *UpdateOptions) DeepCopyInto(out *UpdateOptions) { +func (in *PermissionClaimUpdateOptions) DeepCopyInto(out *PermissionClaimUpdateOptions) { *out = *in if in.Fields != nil { in, out := &in.Fields, &out.Fields @@ -1117,12 +1117,12 @@ func (in *UpdateOptions) DeepCopyInto(out *UpdateOptions) { return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UpdateOptions. -func (in *UpdateOptions) DeepCopy() *UpdateOptions { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PermissionClaimUpdateOptions. +func (in *PermissionClaimUpdateOptions) DeepCopy() *PermissionClaimUpdateOptions { if in == nil { return nil } - out := new(UpdateOptions) + out := new(PermissionClaimUpdateOptions) in.DeepCopyInto(out) return out } diff --git a/pkg/kubectl/bind-apiservice/plugin/servicebindings.go b/pkg/kubectl/bind-apiservice/plugin/servicebindings.go index a66b804af..4c97b442f 100644 --- a/pkg/kubectl/bind-apiservice/plugin/servicebindings.go +++ b/pkg/kubectl/bind-apiservice/plugin/servicebindings.go @@ -162,7 +162,7 @@ func writeFirstLines(b *bytes.Buffer, groupResource string, claim kubebindv1alph adopt := claim.AutoAdopt var names []string - var owner kubebindv1alpha1.Owner + var owner kubebindv1alpha1.PermissionCaimResourceOwner if claim.Selector != nil { names = claim.Selector.Names owner = claim.Selector.Owner diff --git a/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go b/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go index 48384643b..b9158ee8c 100644 --- a/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go +++ b/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go @@ -131,7 +131,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Provider, }, Required: true, - Create: &kubebindv1alpha1.CreateOptions{}, + Create: &kubebindv1alpha1.PermissionClaimCreateOptions{}, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + @@ -182,7 +182,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Provider, }, Required: true, - OnConflict: &kubebindv1alpha1.OnConflictOptions{}, + OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{}, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + @@ -199,7 +199,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Provider, }, Required: true, - Create: &kubebindv1alpha1.CreateOptions{ + Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ ReplaceExisting: false, }, }, @@ -218,7 +218,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Provider, }, Required: true, - Create: &kubebindv1alpha1.CreateOptions{ + Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ ReplaceExisting: true, }, }, @@ -238,7 +238,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Provider, }, Required: true, - OnConflict: &kubebindv1alpha1.OnConflictOptions{ + OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{ RecreateWhenConsumerSideDeleted: false, }, }, @@ -257,7 +257,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Provider, }, Required: true, - OnConflict: &kubebindv1alpha1.OnConflictOptions{ + OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{ RecreateWhenConsumerSideDeleted: true, }, }, @@ -277,7 +277,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Provider, }, Required: true, - Update: &kubebindv1alpha1.UpdateOptions{}, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{}, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + @@ -294,7 +294,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Provider, }, Required: true, - Update: &kubebindv1alpha1.UpdateOptions{ + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Fields: []string{"foo", "bar"}, }, }, @@ -316,7 +316,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Provider, }, Required: true, - Update: &kubebindv1alpha1.UpdateOptions{ + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Preserving: []string{"foo", "bar"}, }, }, @@ -338,7 +338,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Provider, }, Required: true, - Update: &kubebindv1alpha1.UpdateOptions{ + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ AlwaysRecreate: true, }, }, @@ -359,7 +359,7 @@ func TestHumanReadablePromt(t *testing.T) { }, Required: true, AutoDonate: true, - Update: &kubebindv1alpha1.UpdateOptions{ + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Fields: []string{"foo", "bar"}, }, }, @@ -382,7 +382,7 @@ func TestHumanReadablePromt(t *testing.T) { }, Required: true, AutoDonate: true, - Update: &kubebindv1alpha1.UpdateOptions{ + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Preserving: []string{"foo", "bar"}, }, }, @@ -511,7 +511,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Consumer, }, Required: true, - OnConflict: &kubebindv1alpha1.OnConflictOptions{}, + OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{}, }, "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + @@ -528,7 +528,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Consumer, }, Required: true, - Create: &kubebindv1alpha1.CreateOptions{ + Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ ReplaceExisting: false, }, }, @@ -547,7 +547,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Consumer, }, Required: true, - Create: &kubebindv1alpha1.CreateOptions{ + Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ ReplaceExisting: true, }, }, @@ -567,7 +567,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Consumer, }, Required: true, - Update: &kubebindv1alpha1.UpdateOptions{}, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{}, }, "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + @@ -584,7 +584,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Consumer, }, Required: true, - Update: &kubebindv1alpha1.UpdateOptions{ + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Fields: []string{"foo", "bar"}, }, }, @@ -606,7 +606,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Consumer, }, Required: true, - Update: &kubebindv1alpha1.UpdateOptions{ + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Preserving: []string{"foo", "bar"}, }, }, @@ -628,7 +628,7 @@ func TestHumanReadablePromt(t *testing.T) { Owner: kubebindv1alpha1.Consumer, }, Required: true, - Update: &kubebindv1alpha1.UpdateOptions{ + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ AlwaysRecreate: true, }, }, @@ -649,7 +649,7 @@ func TestHumanReadablePromt(t *testing.T) { }, Required: true, AutoAdopt: true, - Update: &kubebindv1alpha1.UpdateOptions{ + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Fields: []string{"foo", "bar"}, }, }, @@ -672,7 +672,7 @@ func TestHumanReadablePromt(t *testing.T) { }, Required: true, AutoAdopt: true, - Update: &kubebindv1alpha1.UpdateOptions{ + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Preserving: []string{"foo", "bar"}, }, }, @@ -738,7 +738,7 @@ func TestHumanReadablePromt(t *testing.T) { Version: "v1", Selector: &kubebindv1alpha1.ResourceSelector{}, AutoDonate: true, - Update: &kubebindv1alpha1.UpdateOptions{ + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Fields: []string{"spec"}, }, }, @@ -772,7 +772,7 @@ func TestHumanReadablePromt(t *testing.T) { Version: "v1", Selector: &kubebindv1alpha1.ResourceSelector{}, AutoAdopt: true, - Update: &kubebindv1alpha1.UpdateOptions{ + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Fields: []string{"spec"}, }, }, From dc307ba9862d44dc47f6254adaba318356da2bd4 Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Mon, 23 Oct 2023 18:38:47 +0200 Subject: [PATCH 08/12] apis: an attempt on more precise permission claim docs Signed-off-by: Dr. Stefan Schimanski --- .../v1alpha1/apiservicebinding_types.go | 2 +- .../v1alpha1/apiserviceexport_types.go | 18 +- .../v1alpha1/permissionclaims_types.go | 164 +++++++++++------- 3 files changed, 115 insertions(+), 69 deletions(-) diff --git a/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go b/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go index 9d6ecf460..f8522d695 100644 --- a/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go +++ b/pkg/apis/kubebind/v1alpha1/apiservicebinding_types.go @@ -97,7 +97,7 @@ type APIServiceBindingSpec struct { PermissionClaims []AcceptablePermissionClaim `json:"permissionClaims,omitempty"` } -// acceptablePermissionClaim is a permission claim that stores the users acceptance in the field state. Only accepted permission claims are reconciled. +// AcceptablePermissionClaim is a permission claim that stores the users acceptance in the field state. Only accepted permission claims are reconciled. type AcceptablePermissionClaim struct { PermissionClaim `json:",inline"` diff --git a/pkg/apis/kubebind/v1alpha1/apiserviceexport_types.go b/pkg/apis/kubebind/v1alpha1/apiserviceexport_types.go index 74d226191..0a61d9ce3 100644 --- a/pkg/apis/kubebind/v1alpha1/apiserviceexport_types.go +++ b/pkg/apis/kubebind/v1alpha1/apiserviceexport_types.go @@ -79,8 +79,16 @@ func (in *APIServiceExport) SetConditions(conditions conditionsapi.Conditions) { type APIServiceExportSpec struct { APIServiceExportCRDSpec `json:",inline"` + // permissionClaims is a list of permission claims that the service provider + // asks the consumer to accept in the consumer cluster binding to this export. + // The consumer can accept or deny each claim. Some claims are required and + // with that a successful binding is not possible. Others are optional. + // + // Note that a claim added at a later point is not guaranteed to be seen and + // processed (accepted or rejected) by the consumer. + // // +optional - PermissionClaims []PermissionClaim `json:"permissionClaims,omitempty"` + PermissionClaims []ExportPermissionClaim `json:"permissionClaims,omitempty"` // informerScope is the scope of the APIServiceExport. It can be either Cluster or Namespace. // @@ -95,6 +103,14 @@ type APIServiceExportSpec struct { InformerScope Scope `json:"informerScope"` } +type ExportPermissionClaim struct { + PermissionClaim `json:",inline"` + + // required indicates whether the APIServiceBinding will work if this claim + // is not accepted. If a required claim is denied, the binding is aborted. + Required bool `json:"required"` +} + type APIServiceExportCRDSpec struct { // group is the API group of the defined custom resource. Empty string means the // core API group. The resources are served under `/apis//...` or `/api` for the core group. diff --git a/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go b/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go index 72029aa49..eab840518 100644 --- a/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go +++ b/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go @@ -16,8 +16,23 @@ limitations under the License. package v1alpha1 -// PermissionClaim selects objects of a GVR that a service provider may -// request and that a consumer may accept and allow the service provider access to. +// PermissionClaim specifies permissions for a service provider to access +// resources and fields in a consumer cluster. A PermissionClaim must be +// accepted before the specified permissions are effective. Permission claims +// are implemented through the konnector by syncing the right objects and +// fields in the right direction. +// +// Permission claims distinguish objects owned by the provider and objects +// owned by the consumer. The owner of an object determines which side is the +// source of truth for the object, i.e. whether the object is synced from the +// consumer to the provider cluster or vice versa. Exceptions can be specified +// for individual JSON Paths to be owned by the other side. Metadata in general +// is not synced. Exceptions for labels and annotations can be specified. +// +// Ownership of an object is determined by the `kube-bind.io/owner` annotation. +// Objects on the consumer cluster are owned by the consumer by default. Objects +// on the provider cluster are owned by the provider by default. The annotation +// is only set if the object is owned by the respective other side. // // +kubebuilder:validation:XValidation:rule="!(has(self.autoDonate) && self.autoDonate && has(self.autoAdopt) && self.autoAdopt)",message="donate and adopt are mutually exclusive" type PermissionClaim struct { @@ -29,49 +44,53 @@ type PermissionClaim struct { // +kubebuilder:validation:MinLength:=1 Version string `json:"version"` - // selector selects which resources are being claimed. - // If unset, all resources across all namespaces are being claimed. + // selector restricts which objects of the given resource are being claimed. + // If unset, all objects across all namespaces are being claimed, both + // consumer- and provider owned. // // +optional // +kubebuilder:default:={} Selector *ResourceSelector `json:"selector,omitempty"` - // required indicates whether the APIServiceBinding will work if this claim is not accepted. If a required claim is denied, the binding is aborted. - Required bool `json:"required"` - - // read claims read access to matching objects for the provider. - // Reading of the claimed object(s) is always claimed. - // By default, no labels and annotations can be read by the provider. - // Reading of labels and annotations can be claimed in addition by specifying them explicitly. - // If labels on consumer owned objects that are set by the consumer are read, labelsOnProviderOwnedObjects and - // annotationsOnProviderOwnedObjects can be set. + // read claims read access for the provider to matching objects, excluding + // labels and annotations by default. Read access is realized by syncing + // the objects or fields from the consumer cluster to the provider cluster. // // +optional // +kubebuilder:default={} Read *PermissionClaimReadOptions `json:"read,omitempty"` - // create determines whether the kube-bind konnector will sync matching objects from the - // provider cluster down to the consumer cluster. - // only for owner Provider + // create determines whether the provider can create new objects in the + // consumer cluster by syncing a provider-owned source to the consumer + // cluster. Created objects on the consumer cluster are marked as owned by + // the provider by default. + // + // Note that create permissions do not imply update permissions. // // +optional Create *PermissionClaimCreateOptions `json:"create,omitempty"` - // autoAdopt set to true means that objects created by the consumer are adopted by the provider. - // i.e. the provider will become the owner. - // Mutually exclusive with autoDonate. + // autoAdopt set to true means that objects created by the consumer on the + // consumer cluster are immediately adopted by the provider by syncing them + // to the provider side and then marking them as owned by the provider on + // both sides. + // + // autoAdopt is mutually exclusive with autoDonate. // // +optional AutoAdopt bool `json:"autoAdopt,omitempty"` - // autoDonate set to true means that a newly created object by the provider is immediately owned by the consumer. - // If false, the object stays in ownership of the provider. - // Mutually exclusive with autoDonate. + // autoDonate set to true means that a newly created object synced from the + // provider to the consumer cluster is immediately donated to the consumer + // by marking it as owned by the consumer on both sides. + // + // autoDonate is mutually exclusive with autoAdopt. // // +optional AutoDonate bool `json:"autoDonate,omitempty"` - // onConflict determines how the conflicts between objects on the consumer cluster will be resolved. + // onConflict determines how conflicts between objects on the consumer + // and provider clusters will be resolved. // // +optional // +kubebuilder:default:={} @@ -80,21 +99,22 @@ type PermissionClaim struct { // update lists which updates to objects on the consumer cluster are claimed. // By default, the whole object is synced, but metadata is not. // + // Note that update permissions do not imply create permissions. + // // +optional Update *PermissionClaimUpdateOptions `json:"update,omitempty"` } type PermissionClaimReadOptions struct { - // labels is a list of claimed label key wildcard patterns - // that are synchronized from the consumer cluster to the provider on - // objects that are owned by the consumer. + // labels is a list of label key wildcard patterns that are synchronized + // from the consumer to the provider on consumer-owned objects. // // +optional Labels []Matcher `json:"labels,omitempty"` - // labelsOnProviderOwnedObjects is a list of claimed label key wildcard - // patterns that are synchronized from the consumer cluster - // to the provider on objects owned by the provider. + // LabelsOnProviderOwnedObjects is a list of claimed label key wildcard + // patterns that are synchronized from the consumer cluster to the provider + // on objects owned by the provider. // // +optional LabelsOnProviderOwnedObjects []Matcher `json:"labelsOnProviderOwnedObjects,omitempty"` @@ -107,15 +127,20 @@ type PermissionClaimReadOptions struct { Annotations []Matcher `json:"annotations,omitempty"` // overrideAnnotations is a list of claimed annotation key wildcard - // patterns that are synchronized from the consumer cluster - // to the provider on objects owned by the provider. + // patterns that are synchronized from the consumer cluster to the provider + // on provider-owned objects. // // +optional - OverrideAnnotations []Matcher `json:"overrideAnnotations,omitempty"` + AnnotationsOnProviderOwnedObjects []Matcher `json:"annotationsOnProviderOwnedObjects,omitempty"` } type Matcher struct { - // +optional + // pattern is a wildcard pattern that is matched against the key. This means + // it is either a literal string or starts or ends in `*` but is not '*' + // itself. + // + // +kubebuilder:validation:Required + // +kubebuilder:validation:MinLength:=1 Pattern string `json:"pattern,omitempty"` } @@ -130,7 +155,8 @@ type PermissionClaimOnConflictOptions struct { } type PermissionClaimCreateOptions struct { - // replaceExisting means that an existing object owned by the consumer will be replaced by the provider object. + // replaceExisting means that an existing object owned by the consumer will + // be replaced by the provider object. // // If not true, and a conflicting consumer object exists, it is not touched. // @@ -139,50 +165,59 @@ type PermissionClaimCreateOptions struct { } type PermissionClaimUpdateOptions struct { - // fields are a list of JSON Paths describing which parts of an object the provider wants to control. + // fields are a list of JSON Paths in consumer-owned objects on the consumer + // cluster that the provider wants to control. // - // This field is ignored if the owner in the claim selector is set to "Provider". + // This is ignored for provider-owned objects. // // +optional Fields []string `json:"fields,omitempty"` - // preserving is a list of JSON Paths describing which parts of an object owned by the provider the consumer keeps controlling. + // preserving is a list of JSON Paths in provider-owned objects on the + // consumer cluster that the consumer keeps controlling, i.e. that are not + // overwritten by the provider, but synced back to the provider side. // - // This field is ignored if the owner in the claim selector is set to "Consumer". + // This is ignored for consumer-owned objects.. // // +optional Preserving []string `json:"preserving,omitempty"` - // alwaysRecreate, when true will delete the old object and create new ones - // instead of updating. Useful for immutable objects. + // alwaysRecreate set to true means that matching objects will be deleted + // and recreated on update. This is useful for immutable objects. // // This does not apply to metadata field updates. // // +optional AlwaysRecreate bool `json:"alwaysRecreate,omitempty"` - // labels is a list of claimed label keys or label wildcard patterns that are synchronized from the provider to the consumer for objects owned by the provider. + // labels is a list of label key wildcard patterns that are synced from the + // provider to the consumer for provider-owned objects. // // By default, no labels are synced. // // +optional Labels []Matcher `json:"labels,omitempty"` - // labelsOnConsumerOwnedObjects is a list of claimed label key wildcard patterns that are synchronized from the provider to the consumer for objects owned by the consumer. + // labelsOnConsumerOwnedObjects is a list of label key wildcard patterns + // that are synced from the provider to the consumer for consumer-owner + // objects. // // By default, no labels are synced. // // +optional LabelsOnConsumerOwnedObjects []Matcher `json:"labelsOnConsumerOwnedObjects,omitempty"` - // annotations is a list of claimed annotation keys or annotation wildcard patterns that are synchronized from the provider to the consumer for objects owned by the provider. + // annotations is a list of annotation key wildcard patterns that are synced + // from the provider to the consumer for provider-owned objects. // // By default, no annotations are synced. // // +optional Annotations []Matcher `json:"annotations,omitempty"` - // annotationsOnConsumerOwnedObjects is a list of claimed annotation key wildcard patterns that are synchronized from the provider to the consumer for objects owned by the consumer. + // annotationsOnConsumerOwnedObjects is a list of annotation key wildcard + // patterns that are synchronized from the provider to the consumer for + // consumer-owned objects. // // By default, no annotations are synced. // @@ -191,41 +226,36 @@ type PermissionClaimUpdateOptions struct { } type ResourceSelector struct { - // names is a list of specific resource names to select. - // Names matches the metadata.name field of the underlying object. - // An entry of "*" anywhere in the list means all object names of the group/resource within the "namespaces" field are claimed. - // Wildcard entries other than "*" and regular expressions are currently unsupported. - // If a resources name matches any value in names, the resource name is considered matching. + // names is a list of values selecting by metadata.name, or "*" which + // matches all names. // - // // +kubebuilder:validation:XValidation:rule="self.all(n, n.matches('^[A-z-]+|[*]$'))",message="only names or * are allowed" + // +kubebuilder:validation:XValidation:rule="self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]$'))",message="only names or * are allowed" // +kubebuilder:default:={"*"} // +optional Names []string `json:"names,omitempty"` - // namespaces represents namespaces where an object of the given group/resource may be managed. - // Namespaces matches against the metadata.namespace field. A value of "*" matches namespaced objects across all namespaces. - // If a resources namespace matches any value in namespaces, the resource namespace is considered matching. - // If the claim is for a cluster-scoped resource, namespaces has to explicitly be set to an empty array to prevent defaulting to "*". - // If the "names" field is unset, all objects of the group/resource within the listed namespaces (or cluster) will be claimed. + // namespaces is a list of values selecting by metadata.namespace, or "*" + // which matches all namespaces, or empty string that matches cluster-scoped + // resources. // - // // +kubebuilder:validation:XValidation:rule="self.all(n, n.matches('^[A-z-]+|[*]$'))",message="only names or * are allowed" + // +kubebuilder:validation:XValidation:rule="self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]?$'))",message="only namespace names,* or empty string are allowed" // +kubebuilder:default:={"*"} // +optional Namespaces []string `json:"namespaces,omitempty"` - // labelSelectors is a list of label selectors matching selected resources. label selectors follow the same rules as kubernetes label selectors, - // see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. + // labelSelectors is a disjunctive list of label selectors, following the + // same rules as kubernetes label selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. LabelSelectors []map[string]string `json:"labelSelectors,omitempty"` - // fieldSelectors is a list of field selectors matching selected resources, - // see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/. + // fieldSelectors is a disjunctive list of field selectors, following the + // same rules as kubernetes field selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/, + // i.e. each field selector can be a conjunction of requirements. FieldSelectors []string `json:"fieldSelectors,omitempty"` - // owner matches the resource's owner. If an owner selector is set, resources owned by other owners will not be claimed. - // Resources without a present owner will be considered, if configured owner could be the owner of the object. - // For example, if the consumer creates a resource that is claimed by the provider for reading. In this case the resource - // will be marked as owned by the consumer, and handled as such in further reconciliations. - // An unset owner selector means objects from both sides are considered. + // owner set means that resources of a specific owner are selected and those + // owned by the other side are ignored. A resource on the consumer cluster + // is owned by the consumer by default, if not marked as owned by the + // provider through the `kube-bind.io/owner=provider` annotation. // // +kubebuilder:validation:Enum=Provider;Consumer // +optional @@ -235,9 +265,9 @@ type ResourceSelector struct { type PermissionCaimResourceOwner string const ( - // provider means that the owner of the resource is the Provider. + // Provider means that the owner of the resource is the Provider. Provider PermissionCaimResourceOwner = "Provider" - // consumer means that the owner of the resource is the Consumer. + // Consumer means that the owner of the resource is the Consumer. Consumer PermissionCaimResourceOwner = "Consumer" ) From b67ec95da701bf92ca55b2a81738286e5eab5a9e Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Mon, 23 Oct 2023 18:39:27 +0200 Subject: [PATCH 09/12] codegen Signed-off-by: Dr. Stefan Schimanski --- .../crd/kube-bind.io_apiservicebindings.yaml | 251 ++++++++------- ...kube-bind.io_apiserviceexportrequests.yaml | 296 +++++++++++------- .../crd/kube-bind.io_apiserviceexports.yaml | 254 +++++++++------ .../v1alpha1/zz_generated.deepcopy.go | 151 +++++---- 4 files changed, 557 insertions(+), 395 deletions(-) diff --git a/deploy/crd/kube-bind.io_apiservicebindings.yaml b/deploy/crd/kube-bind.io_apiservicebindings.yaml index d1a27c04e..dfa186378 100644 --- a/deploy/crd/kube-bind.io_apiservicebindings.yaml +++ b/deploy/crd/kube-bind.io_apiservicebindings.yaml @@ -91,25 +91,30 @@ spec: the requested access to the specified resources in this workspace. Access is granted per GroupResource and other properties like selectors. items: - description: acceptablePermissionClaim is a permission claim that + description: AcceptablePermissionClaim is a permission claim that stores the users acceptance in the field state. Only accepted permission claims are reconciled. properties: autoAdopt: - description: autoAdopt set to true means that objects created - by the consumer are adopted by the provider. i.e. the provider - will become the owner. Mutually exclusive with autoDonate. + description: "autoAdopt set to true means that objects created + by the consumer on the consumer cluster are immediately adopted + by the provider by syncing them to the provider side and then + marking them as owned by the provider on both sides. \n autoAdopt + is mutually exclusive with autoDonate." type: boolean autoDonate: - description: autoDonate set to true means that a newly created - object by the provider is immediately owned by the consumer. - If false, the object stays in ownership of the provider. Mutually - exclusive with autoDonate. + description: "autoDonate set to true means that a newly created + object synced from the provider to the consumer cluster is + immediately donated to the consumer by marking it as owned + by the consumer on both sides. \n autoDonate is mutually exclusive + with autoAdopt." type: boolean create: - description: create determines whether the kube-bind konnector - will sync matching objects from the provider cluster down - to the consumer cluster. only for owner Provider + description: "create determines whether the provider can create + new objects in the consumer cluster by syncing a provider-owned + source to the consumer cluster. Created objects on the consumer + cluster are marked as owned by the provider by default. \n + Note that create permissions do not imply update permissions." properties: replaceExisting: description: "replaceExisting means that an existing object @@ -125,8 +130,8 @@ spec: pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9](\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)?)$ type: string onConflict: - description: onConflict determines how the conflicts between - objects on the consumer cluster will be resolved. + description: onConflict determines how conflicts between objects + on the consumer and provider clusters will be resolved. properties: recreateWhenConsumerSideDeleted: default: true @@ -139,13 +144,10 @@ spec: type: boolean type: object read: - description: read claims read access to matching objects for - the provider. Reading of the claimed object(s) is always claimed. - By default, no labels and annotations can be read by the provider. - Reading of labels and annotations can be claimed in addition - by specifying them explicitly. If labels on consumer owned - objects that are set by the consumer are read, labelsOnProviderOwnedObjects - and annotationsOnProviderOwnedObjects can be set. + description: read claims read access for the provider to matching + objects, excluding labels and annotations by default. Read + access is realized by syncing the objects or fields from the + consumer cluster to the provider cluster. properties: annotations: description: annotations is a list of claimed annotation @@ -155,46 +157,69 @@ spec: items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array - labels: - description: labels is a list of claimed label key wildcard - patterns that are synchronized from the consumer cluster - to the provider on objects that are owned by the consumer. + annotationsOnProviderOwnedObjects: + description: overrideAnnotations is a list of claimed annotation + key wildcard patterns that are synchronized from the consumer + cluster to the provider on provider-owned objects. items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array - labelsOnProviderOwnedObjects: - description: labelsOnProviderOwnedObjects is a list of claimed - label key wildcard patterns that are synchronized from - the consumer cluster to the provider on objects owned - by the provider. + labels: + description: labels is a list of label key wildcard patterns + that are synchronized from the consumer to the provider + on consumer-owned objects. items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array - overrideAnnotations: - description: overrideAnnotations is a list of claimed annotation - key wildcard patterns that are synchronized from the consumer - cluster to the provider on objects owned by the provider. + labelsOnProviderOwnedObjects: + description: LabelsOnProviderOwnedObjects is a list of claimed + label key wildcard patterns that are synchronized from + the consumer cluster to the provider on objects owned + by the provider. items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array type: object - required: - description: required indicates whether the APIServiceBinding - will work if this claim is not accepted. If a required claim - is denied, the binding is aborted. - type: boolean resource: description: 'resource is the name of the resource. Note: it is worth noting that you can not ask for permissions for resource @@ -202,19 +227,22 @@ spec: pattern: ^[a-z][-a-z0-9]*[a-z0-9]$ type: string selector: - description: selector selects which resources are being claimed. - If unset, all resources across all namespaces are being claimed. + description: selector restricts which objects of the given resource + are being claimed. If unset, all objects across all namespaces + are being claimed, both consumer- and provider owned. properties: fieldSelectors: - description: fieldSelectors is a list of field selectors - matching selected resources, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/. + description: fieldSelectors is a disjunctive list of field + selectors, following the same rules as kubernetes field + selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/, + i.e. each field selector can be a conjunction of requirements. items: type: string type: array labelSelectors: - description: labelSelectors is a list of label selectors - matching selected resources. label selectors follow the - same rules as kubernetes label selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. + description: labelSelectors is a disjunctive list of label + selectors, following the same rules as kubernetes label + selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. items: additionalProperties: type: string @@ -223,49 +251,32 @@ spec: names: default: - '*' - description: "names is a list of specific resource names - to select. Names matches the metadata.name field of the - underlying object. An entry of \"*\" anywhere in the list - means all object names of the group/resource within the - \"namespaces\" field are claimed. Wildcard entries other - than \"*\" and regular expressions are currently unsupported. - If a resources name matches any value in names, the resource - name is considered matching. \n // +kubebuilder:validation:XValidation:rule=\"self.all(n, - n.matches('^[A-z-]+|[*]$'))\",message=\"only names or - * are allowed\"" + description: names is a list of values selecting by metadata.name, + or "*" which matches all names. items: type: string type: array + x-kubernetes-validations: + - message: only names or * are allowed + rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]$')) namespaces: default: - '*' - description: "namespaces represents namespaces where an - object of the given group/resource may be managed. Namespaces - matches against the metadata.namespace field. A value - of \"*\" matches namespaced objects across all namespaces. - If a resources namespace matches any value in namespaces, - the resource namespace is considered matching. If the - claim is for a cluster-scoped resource, namespaces has - to explicitly be set to an empty array to prevent defaulting - to \"*\". If the \"names\" field is unset, all objects - of the group/resource within the listed namespaces (or - cluster) will be claimed. \n // +kubebuilder:validation:XValidation:rule=\"self.all(n, - n.matches('^[A-z-]+|[*]$'))\",message=\"only names or - * are allowed\"" + description: namespaces is a list of values selecting by + metadata.namespace, or "*" which matches all namespaces, + or empty string that matches cluster-scoped resources. items: type: string type: array + x-kubernetes-validations: + - message: only namespace names,* or empty string are allowed + rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]?$')) owner: - description: owner matches the resource's owner. If an owner - selector is set, resources owned by other owners will - not be claimed. Resources without a present owner will - be considered, if configured owner could be the owner - of the object. For example, if the consumer creates a - resource that is claimed by the provider for reading. - In this case the resource will be marked as owned by the - consumer, and handled as such in further reconciliations. - An unset owner selector means objects from both sides - are considered. + description: owner set means that resources of a specific + owner are selected and those owned by the other side are + ignored. A resource on the consumer cluster is owned by + the consumer by default, if not marked as owned by the + provider through the `kube-bind.io/owner=provider` annotation. enum: - Provider - Consumer @@ -278,73 +289,101 @@ spec: - Rejected type: string update: - description: update lists which updates to objects on the consumer + description: "update lists which updates to objects on the consumer cluster are claimed. By default, the whole object is synced, - but metadata is not. + but metadata is not. \n Note that update permissions do not + imply create permissions." properties: alwaysRecreate: - description: "alwaysRecreate, when true will delete the - old object and create new ones instead of updating. Useful - for immutable objects. \n This does not apply to metadata - field updates." + description: "alwaysRecreate set to true means that matching + objects will be deleted and recreated on update. This + is useful for immutable objects. \n This does not apply + to metadata field updates." type: boolean annotations: - description: "annotations is a list of claimed annotation - keys or annotation wildcard patterns that are synchronized - from the provider to the consumer for objects owned by - the provider. \n By default, no annotations are synced." + description: "annotations is a list of annotation key wildcard + patterns that are synced from the provider to the consumer + for provider-owned objects. \n By default, no annotations + are synced." items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array annotationsOnConsumerOwnedObjects: description: "annotationsOnConsumerOwnedObjects is a list - of claimed annotation key wildcard patterns that are synchronized - from the provider to the consumer for objects owned by - the consumer. \n By default, no annotations are synced." + of annotation key wildcard patterns that are synchronized + from the provider to the consumer for consumer-owned objects. + \n By default, no annotations are synced." items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array fields: - description: "fields are a list of JSON Paths describing - which parts of an object the provider wants to control. - \n This field is ignored if the owner in the claim selector - is set to \"Provider\"." + description: "fields are a list of JSON Paths in consumer-owned + objects on the consumer cluster that the provider wants + to control. \n This is ignored for provider-owned objects." items: type: string type: array labels: - description: "labels is a list of claimed label keys or - label wildcard patterns that are synchronized from the - provider to the consumer for objects owned by the provider. - \n By default, no labels are synced." + description: "labels is a list of label key wildcard patterns + that are synced from the provider to the consumer for + provider-owned objects. \n By default, no labels are synced." items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array labelsOnConsumerOwnedObjects: description: "labelsOnConsumerOwnedObjects is a list of - claimed label key wildcard patterns that are synchronized - from the provider to the consumer for objects owned by - the consumer. \n By default, no labels are synced." + label key wildcard patterns that are synced from the provider + to the consumer for consumer-owner objects. \n By default, + no labels are synced." items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array preserving: - description: "preserving is a list of JSON Paths describing - which parts of an object owned by the provider the consumer - keeps controlling. \n This field is ignored if the owner - in the claim selector is set to \"Consumer\"." + description: "preserving is a list of JSON Paths in provider-owned + objects on the consumer cluster that the consumer keeps + controlling, i.e. that are not overwritten by the provider, + but synced back to the provider side. \n This is ignored + for consumer-owned objects.." items: type: string type: array diff --git a/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml b/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml index 509cd1784..ef8431db2 100644 --- a/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml +++ b/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml @@ -71,26 +71,48 @@ spec: in this workspace. Access is granted per GroupResource, identity, and other properties. items: - description: permissionClaim selects objects of a GVR that - a service provider may request and that a consumer may accept - and allow the service provider access to. + description: "PermissionClaim specifies permissions for a + service provider to access resources and fields in a consumer + cluster. A PermissionClaim must be accepted before the specified + permissions are effective. Permission claims are implemented + through the konnector by syncing the right objects and fields + in the right direction. \n Permission claims distinguish + objects owned by the provider and objects owned by the consumer. + The owner of an object determines which side is the source + of truth for the object, i.e. whether the object is synced + from the consumer to the provider cluster or vice versa. + Exceptions can be specified for individual JSON Paths to + be owned by the other side. Metadata in general is not synced. + Exceptions for labels and annotations can be specified. + \n Ownership of an object is determined by the `kube-bind.io/owner` + annotation. Objects on the consumer cluster are owned by + the consumer by default. Objects on the provider cluster + are owned by the provider by default. The annotation is + only set if the object is owned by the respective other + side." properties: autoAdopt: - description: autoAdopt set to true means that objects - created by the consumer are adopted by the provider. - i.e. the provider will become the owner. Mutually exclusive - with autoDonate. + description: "autoAdopt set to true means that objects + created by the consumer on the consumer cluster are + immediately adopted by the provider by syncing them + to the provider side and then marking them as owned + by the provider on both sides. \n autoAdopt is mutually + exclusive with autoDonate." type: boolean autoDonate: - description: autoDonate set to true means that a newly - created object by the provider is immediately owned - by the consumer. If false, the object stays in ownership - of the provider. Mutually exclusive with autoDonate. + description: "autoDonate set to true means that a newly + created object synced from the provider to the consumer + cluster is immediately donated to the consumer by marking + it as owned by the consumer on both sides. \n autoDonate + is mutually exclusive with autoAdopt." type: boolean create: - description: create determines whether the kube-bind konnector - will sync matching objects from the provider cluster - down to the consumer cluster. only for owner Provider + description: "create determines whether the provider can + create new objects in the consumer cluster by syncing + a provider-owned source to the consumer cluster. Created + objects on the consumer cluster are marked as owned + by the provider by default. \n Note that create permissions + do not imply update permissions." properties: replaceExisting: description: "replaceExisting means that an existing @@ -106,8 +128,9 @@ spec: pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9](\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)?)$ type: string onConflict: - description: onConflict determines how the conflicts between - objects on the consumer cluster will be resolved. + description: onConflict determines how conflicts between + objects on the consumer and provider clusters will be + resolved. properties: recreateWhenConsumerSideDeleted: default: true @@ -120,14 +143,11 @@ spec: type: boolean type: object read: - description: read claims read access to matching objects - for the provider. Reading of the claimed object(s) is - always claimed. By default, no labels and annotations - can be read by the provider. Reading of labels and annotations - can be claimed in addition by specifying them explicitly. - If labels on consumer owned objects that are set by - the consumer are read, labelsOnProviderOwnedObjects - and annotationsOnProviderOwnedObjects can be set. + description: read claims read access for the provider + to matching objects, excluding labels and annotations + by default. Read access is realized by syncing the objects + or fields from the consumer cluster to the provider + cluster. properties: annotations: description: annotations is a list of claimed annotation @@ -137,48 +157,70 @@ spec: items: properties: pattern: + description: pattern is a wildcard pattern that + is matched against the key. This means it + is either a literal string or starts or ends + in `*` but is not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array - labels: - description: labels is a list of claimed label key - wildcard patterns that are synchronized from the - consumer cluster to the provider on objects that - are owned by the consumer. + annotationsOnProviderOwnedObjects: + description: overrideAnnotations is a list of claimed + annotation key wildcard patterns that are synchronized + from the consumer cluster to the provider on provider-owned + objects. items: properties: pattern: + description: pattern is a wildcard pattern that + is matched against the key. This means it + is either a literal string or starts or ends + in `*` but is not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array - labelsOnProviderOwnedObjects: - description: labelsOnProviderOwnedObjects is a list - of claimed label key wildcard patterns that are - synchronized from the consumer cluster to the provider - on objects owned by the provider. + labels: + description: labels is a list of label key wildcard + patterns that are synchronized from the consumer + to the provider on consumer-owned objects. items: properties: pattern: + description: pattern is a wildcard pattern that + is matched against the key. This means it + is either a literal string or starts or ends + in `*` but is not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array - overrideAnnotations: - description: overrideAnnotations is a list of claimed - annotation key wildcard patterns that are synchronized - from the consumer cluster to the provider on objects - owned by the provider. + labelsOnProviderOwnedObjects: + description: LabelsOnProviderOwnedObjects is a list + of claimed label key wildcard patterns that are + synchronized from the consumer cluster to the provider + on objects owned by the provider. items: properties: pattern: + description: pattern is a wildcard pattern that + is matched against the key. This means it + is either a literal string or starts or ends + in `*` but is not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array type: object - required: - description: required indicates whether the APIServiceBinding - will work if this claim is not accepted. If a required - claim is denied, the binding is aborted. - type: boolean resource: description: 'resource is the name of the resource. Note: it is worth noting that you can not ask for permissions @@ -187,21 +229,24 @@ spec: pattern: ^[a-z][-a-z0-9]*[a-z0-9]$ type: string selector: - description: selector selects which resources are being - claimed. If unset, all resources across all namespaces - are being claimed. + description: selector restricts which objects of the given + resource are being claimed. If unset, all objects across + all namespaces are being claimed, both consumer- and + provider owned. properties: fieldSelectors: - description: fieldSelectors is a list of field selectors - matching selected resources, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/. + description: fieldSelectors is a disjunctive list + of field selectors, following the same rules as + kubernetes field selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/, + i.e. each field selector can be a conjunction of + requirements. items: type: string type: array labelSelectors: - description: labelSelectors is a list of label selectors - matching selected resources. label selectors follow - the same rules as kubernetes label selectors, see - https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. + description: labelSelectors is a disjunctive list + of label selectors, following the same rules as + kubernetes label selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. items: additionalProperties: type: string @@ -210,127 +255,140 @@ spec: names: default: - '*' - description: "names is a list of specific resource - names to select. Names matches the metadata.name - field of the underlying object. An entry of \"*\" - anywhere in the list means all object names of the - group/resource within the \"namespaces\" field are - claimed. Wildcard entries other than \"*\" and regular - expressions are currently unsupported. If a resources - name matches any value in names, the resource name - is considered matching. \n // +kubebuilder:validation:XValidation:rule=\"self.all(n, - n.matches('^[A-z-]+|[*]$'))\",message=\"only names - or * are allowed\"" + description: names is a list of values selecting by + metadata.name, or "*" which matches all names. items: type: string type: array + x-kubernetes-validations: + - message: only names or * are allowed + rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]$')) namespaces: default: - '*' - description: "namespaces represents namespaces where - an object of the given group/resource may be managed. - Namespaces matches against the metadata.namespace - field. A value of \"*\" matches namespaced objects - across all namespaces. If a resources namespace - matches any value in namespaces, the resource namespace - is considered matching. If the claim is for a cluster-scoped - resource, namespaces has to explicitly be set to - an empty array to prevent defaulting to \"*\". If - the \"names\" field is unset, all objects of the - group/resource within the listed namespaces (or - cluster) will be claimed. \n // +kubebuilder:validation:XValidation:rule=\"self.all(n, - n.matches('^[A-z-]+|[*]$'))\",message=\"only names - or * are allowed\"" + description: namespaces is a list of values selecting + by metadata.namespace, or "*" which matches all + namespaces, or empty string that matches cluster-scoped + resources. items: type: string type: array + x-kubernetes-validations: + - message: only namespace names,* or empty string + are allowed + rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]?$')) owner: - description: owner matches the resource's owner. If - an owner selector is set, resources owned by other - owners will not be claimed. Resources without a - present owner will be considered, if configured - owner could be the owner of the object. For example, - if the consumer creates a resource that is claimed - by the provider for reading. In this case the resource - will be marked as owned by the consumer, and handled - as such in further reconciliations. An unset owner - selector means objects from both sides are considered. + description: owner set means that resources of a specific + owner are selected and those owned by the other + side are ignored. A resource on the consumer cluster + is owned by the consumer by default, if not marked + as owned by the provider through the `kube-bind.io/owner=provider` + annotation. enum: - Provider - Consumer type: string type: object update: - description: update lists which updates to objects on + description: "update lists which updates to objects on the consumer cluster are claimed. By default, the whole - object is synced, but metadata is not. + object is synced, but metadata is not. \n Note that + update permissions do not imply create permissions." properties: alwaysRecreate: - description: "alwaysRecreate, when true will delete - the old object and create new ones instead of updating. - Useful for immutable objects. \n This does not apply - to metadata field updates." + description: "alwaysRecreate set to true means that + matching objects will be deleted and recreated on + update. This is useful for immutable objects. \n + This does not apply to metadata field updates." type: boolean annotations: - description: "annotations is a list of claimed annotation - keys or annotation wildcard patterns that are synchronized - from the provider to the consumer for objects owned - by the provider. \n By default, no annotations are - synced." + description: "annotations is a list of annotation + key wildcard patterns that are synced from the provider + to the consumer for provider-owned objects. \n By + default, no annotations are synced." items: properties: pattern: + description: pattern is a wildcard pattern that + is matched against the key. This means it + is either a literal string or starts or ends + in `*` but is not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array annotationsOnConsumerOwnedObjects: description: "annotationsOnConsumerOwnedObjects is - a list of claimed annotation key wildcard patterns - that are synchronized from the provider to the consumer - for objects owned by the consumer. \n By default, - no annotations are synced." + a list of annotation key wildcard patterns that + are synchronized from the provider to the consumer + for consumer-owned objects. \n By default, no annotations + are synced." items: properties: pattern: + description: pattern is a wildcard pattern that + is matched against the key. This means it + is either a literal string or starts or ends + in `*` but is not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array fields: - description: "fields are a list of JSON Paths describing - which parts of an object the provider wants to control. - \n This field is ignored if the owner in the claim - selector is set to \"Provider\"." + description: "fields are a list of JSON Paths in consumer-owned + objects on the consumer cluster that the provider + wants to control. \n This is ignored for provider-owned + objects." items: type: string type: array labels: - description: "labels is a list of claimed label keys - or label wildcard patterns that are synchronized - from the provider to the consumer for objects owned - by the provider. \n By default, no labels are synced." + description: "labels is a list of label key wildcard + patterns that are synced from the provider to the + consumer for provider-owned objects. \n By default, + no labels are synced." items: properties: pattern: + description: pattern is a wildcard pattern that + is matched against the key. This means it + is either a literal string or starts or ends + in `*` but is not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array labelsOnConsumerOwnedObjects: description: "labelsOnConsumerOwnedObjects is a list - of claimed label key wildcard patterns that are - synchronized from the provider to the consumer for - objects owned by the consumer. \n By default, no - labels are synced." + of label key wildcard patterns that are synced from + the provider to the consumer for consumer-owner + objects. \n By default, no labels are synced." items: properties: pattern: + description: pattern is a wildcard pattern that + is matched against the key. This means it + is either a literal string or starts or ends + in `*` but is not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array preserving: - description: "preserving is a list of JSON Paths describing - which parts of an object owned by the provider the - consumer keeps controlling. \n This field is ignored - if the owner in the claim selector is set to \"Consumer\"." + description: "preserving is a list of JSON Paths in + provider-owned objects on the consumer cluster that + the consumer keeps controlling, i.e. that are not + overwritten by the provider, but synced back to + the provider side. \n This is ignored for consumer-owned + objects.." items: type: string type: array diff --git a/deploy/crd/kube-bind.io_apiserviceexports.yaml b/deploy/crd/kube-bind.io_apiserviceexports.yaml index f1a8d6c33..b7f2668f1 100644 --- a/deploy/crd/kube-bind.io_apiserviceexports.yaml +++ b/deploy/crd/kube-bind.io_apiserviceexports.yaml @@ -109,26 +109,35 @@ spec: - plural type: object permissionClaims: + description: "permissionClaims is a list of permission claims that + the service provider asks the consumer to accept in the consumer + cluster binding to this export. The consumer can accept or deny + each claim. Some claims are required and with that a successful + binding is not possible. Others are optional. \n Note that a claim + added at a later point is not guaranteed to be seen and processed + (accepted or rejected) by the consumer." items: - description: permissionClaim selects objects of a GVR that a service - provider may request and that a consumer may accept and allow - the service provider access to. properties: autoAdopt: - description: autoAdopt set to true means that objects created - by the consumer are adopted by the provider. i.e. the provider - will become the owner. Mutually exclusive with autoDonate. + description: "autoAdopt set to true means that objects created + by the consumer on the consumer cluster are immediately adopted + by the provider by syncing them to the provider side and then + marking them as owned by the provider on both sides. \n autoAdopt + is mutually exclusive with autoDonate." type: boolean autoDonate: - description: autoDonate set to true means that a newly created - object by the provider is immediately owned by the consumer. - If false, the object stays in ownership of the provider. Mutually - exclusive with autoDonate. + description: "autoDonate set to true means that a newly created + object synced from the provider to the consumer cluster is + immediately donated to the consumer by marking it as owned + by the consumer on both sides. \n autoDonate is mutually exclusive + with autoAdopt." type: boolean create: - description: create determines whether the kube-bind konnector - will sync matching objects from the provider cluster down - to the consumer cluster. only for owner Provider + description: "create determines whether the provider can create + new objects in the consumer cluster by syncing a provider-owned + source to the consumer cluster. Created objects on the consumer + cluster are marked as owned by the provider by default. \n + Note that create permissions do not imply update permissions." properties: replaceExisting: description: "replaceExisting means that an existing object @@ -144,8 +153,8 @@ spec: pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9](\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)?)$ type: string onConflict: - description: onConflict determines how the conflicts between - objects on the consumer cluster will be resolved. + description: onConflict determines how conflicts between objects + on the consumer and provider clusters will be resolved. properties: recreateWhenConsumerSideDeleted: default: true @@ -158,13 +167,10 @@ spec: type: boolean type: object read: - description: read claims read access to matching objects for - the provider. Reading of the claimed object(s) is always claimed. - By default, no labels and annotations can be read by the provider. - Reading of labels and annotations can be claimed in addition - by specifying them explicitly. If labels on consumer owned - objects that are set by the consumer are read, labelsOnProviderOwnedObjects - and annotationsOnProviderOwnedObjects can be set. + description: read claims read access for the provider to matching + objects, excluding labels and annotations by default. Read + access is realized by syncing the objects or fields from the + consumer cluster to the provider cluster. properties: annotations: description: annotations is a list of claimed annotation @@ -174,38 +180,66 @@ spec: items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array - labels: - description: labels is a list of claimed label key wildcard - patterns that are synchronized from the consumer cluster - to the provider on objects that are owned by the consumer. + annotationsOnProviderOwnedObjects: + description: overrideAnnotations is a list of claimed annotation + key wildcard patterns that are synchronized from the consumer + cluster to the provider on provider-owned objects. items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array - labelsOnProviderOwnedObjects: - description: labelsOnProviderOwnedObjects is a list of claimed - label key wildcard patterns that are synchronized from - the consumer cluster to the provider on objects owned - by the provider. + labels: + description: labels is a list of label key wildcard patterns + that are synchronized from the consumer to the provider + on consumer-owned objects. items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array - overrideAnnotations: - description: overrideAnnotations is a list of claimed annotation - key wildcard patterns that are synchronized from the consumer - cluster to the provider on objects owned by the provider. + labelsOnProviderOwnedObjects: + description: LabelsOnProviderOwnedObjects is a list of claimed + label key wildcard patterns that are synchronized from + the consumer cluster to the provider on objects owned + by the provider. items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array type: object @@ -221,19 +255,22 @@ spec: pattern: ^[a-z][-a-z0-9]*[a-z0-9]$ type: string selector: - description: selector selects which resources are being claimed. - If unset, all resources across all namespaces are being claimed. + description: selector restricts which objects of the given resource + are being claimed. If unset, all objects across all namespaces + are being claimed, both consumer- and provider owned. properties: fieldSelectors: - description: fieldSelectors is a list of field selectors - matching selected resources, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/. + description: fieldSelectors is a disjunctive list of field + selectors, following the same rules as kubernetes field + selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/, + i.e. each field selector can be a conjunction of requirements. items: type: string type: array labelSelectors: - description: labelSelectors is a list of label selectors - matching selected resources. label selectors follow the - same rules as kubernetes label selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. + description: labelSelectors is a disjunctive list of label + selectors, following the same rules as kubernetes label + selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. items: additionalProperties: type: string @@ -242,122 +279,133 @@ spec: names: default: - '*' - description: "names is a list of specific resource names - to select. Names matches the metadata.name field of the - underlying object. An entry of \"*\" anywhere in the list - means all object names of the group/resource within the - \"namespaces\" field are claimed. Wildcard entries other - than \"*\" and regular expressions are currently unsupported. - If a resources name matches any value in names, the resource - name is considered matching. \n // +kubebuilder:validation:XValidation:rule=\"self.all(n, - n.matches('^[A-z-]+|[*]$'))\",message=\"only names or - * are allowed\"" + description: names is a list of values selecting by metadata.name, + or "*" which matches all names. items: type: string type: array + x-kubernetes-validations: + - message: only names or * are allowed + rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]$')) namespaces: default: - '*' - description: "namespaces represents namespaces where an - object of the given group/resource may be managed. Namespaces - matches against the metadata.namespace field. A value - of \"*\" matches namespaced objects across all namespaces. - If a resources namespace matches any value in namespaces, - the resource namespace is considered matching. If the - claim is for a cluster-scoped resource, namespaces has - to explicitly be set to an empty array to prevent defaulting - to \"*\". If the \"names\" field is unset, all objects - of the group/resource within the listed namespaces (or - cluster) will be claimed. \n // +kubebuilder:validation:XValidation:rule=\"self.all(n, - n.matches('^[A-z-]+|[*]$'))\",message=\"only names or - * are allowed\"" + description: namespaces is a list of values selecting by + metadata.namespace, or "*" which matches all namespaces, + or empty string that matches cluster-scoped resources. items: type: string type: array + x-kubernetes-validations: + - message: only namespace names,* or empty string are allowed + rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]?$')) owner: - description: owner matches the resource's owner. If an owner - selector is set, resources owned by other owners will - not be claimed. Resources without a present owner will - be considered, if configured owner could be the owner - of the object. For example, if the consumer creates a - resource that is claimed by the provider for reading. - In this case the resource will be marked as owned by the - consumer, and handled as such in further reconciliations. - An unset owner selector means objects from both sides - are considered. + description: owner set means that resources of a specific + owner are selected and those owned by the other side are + ignored. A resource on the consumer cluster is owned by + the consumer by default, if not marked as owned by the + provider through the `kube-bind.io/owner=provider` annotation. enum: - Provider - Consumer type: string type: object update: - description: update lists which updates to objects on the consumer + description: "update lists which updates to objects on the consumer cluster are claimed. By default, the whole object is synced, - but metadata is not. + but metadata is not. \n Note that update permissions do not + imply create permissions." properties: alwaysRecreate: - description: "alwaysRecreate, when true will delete the - old object and create new ones instead of updating. Useful - for immutable objects. \n This does not apply to metadata - field updates." + description: "alwaysRecreate set to true means that matching + objects will be deleted and recreated on update. This + is useful for immutable objects. \n This does not apply + to metadata field updates." type: boolean annotations: - description: "annotations is a list of claimed annotation - keys or annotation wildcard patterns that are synchronized - from the provider to the consumer for objects owned by - the provider. \n By default, no annotations are synced." + description: "annotations is a list of annotation key wildcard + patterns that are synced from the provider to the consumer + for provider-owned objects. \n By default, no annotations + are synced." items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array annotationsOnConsumerOwnedObjects: description: "annotationsOnConsumerOwnedObjects is a list - of claimed annotation key wildcard patterns that are synchronized - from the provider to the consumer for objects owned by - the consumer. \n By default, no annotations are synced." + of annotation key wildcard patterns that are synchronized + from the provider to the consumer for consumer-owned objects. + \n By default, no annotations are synced." items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array fields: - description: "fields are a list of JSON Paths describing - which parts of an object the provider wants to control. - \n This field is ignored if the owner in the claim selector - is set to \"Provider\"." + description: "fields are a list of JSON Paths in consumer-owned + objects on the consumer cluster that the provider wants + to control. \n This is ignored for provider-owned objects." items: type: string type: array labels: - description: "labels is a list of claimed label keys or - label wildcard patterns that are synchronized from the - provider to the consumer for objects owned by the provider. - \n By default, no labels are synced." + description: "labels is a list of label key wildcard patterns + that are synced from the provider to the consumer for + provider-owned objects. \n By default, no labels are synced." items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array labelsOnConsumerOwnedObjects: description: "labelsOnConsumerOwnedObjects is a list of - claimed label key wildcard patterns that are synchronized - from the provider to the consumer for objects owned by - the consumer. \n By default, no labels are synced." + label key wildcard patterns that are synced from the provider + to the consumer for consumer-owner objects. \n By default, + no labels are synced." items: properties: pattern: + description: pattern is a wildcard pattern that is + matched against the key. This means it is either + a literal string or starts or ends in `*` but is + not '*' itself. + minLength: 1 type: string + required: + - pattern type: object type: array preserving: - description: "preserving is a list of JSON Paths describing - which parts of an object owned by the provider the consumer - keeps controlling. \n This field is ignored if the owner - in the claim selector is set to \"Consumer\"." + description: "preserving is a list of JSON Paths in provider-owned + objects on the consumer cluster that the consumer keeps + controlling, i.e. that are not overwritten by the provider, + but synced back to the provider side. \n This is ignored + for consumer-owned objects.." items: type: string type: array diff --git a/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go index 2889da312..8074155c9 100644 --- a/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go @@ -413,7 +413,7 @@ func (in *APIServiceExportSpec) DeepCopyInto(out *APIServiceExportSpec) { in.APIServiceExportCRDSpec.DeepCopyInto(&out.APIServiceExportCRDSpec) if in.PermissionClaims != nil { in, out := &in.PermissionClaims, &out.PermissionClaims - *out = make([]PermissionClaim, len(*in)) + *out = make([]ExportPermissionClaim, len(*in)) for i := range *in { (*in)[i].DeepCopyInto(&(*out)[i]) } @@ -848,17 +848,18 @@ func (in *ClusterSecretKeyRef) DeepCopy() *ClusterSecretKeyRef { } // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PermissionClaimCreateOptions) DeepCopyInto(out *PermissionClaimCreateOptions) { +func (in *ExportPermissionClaim) DeepCopyInto(out *ExportPermissionClaim) { *out = *in + in.PermissionClaim.DeepCopyInto(&out.PermissionClaim) return } -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PermissionClaimCreateOptions. -func (in *PermissionClaimCreateOptions) DeepCopy() *PermissionClaimCreateOptions { +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ExportPermissionClaim. +func (in *ExportPermissionClaim) DeepCopy() *ExportPermissionClaim { if in == nil { return nil } - out := new(PermissionClaimCreateOptions) + out := new(ExportPermissionClaim) in.DeepCopyInto(out) return out } @@ -943,22 +944,6 @@ func (in *OAuth2CodeGrant) DeepCopy() *OAuth2CodeGrant { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *PermissionClaimOnConflictOptions) DeepCopyInto(out *PermissionClaimOnConflictOptions) { - *out = *in - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PermissionClaimOnConflictOptions. -func (in *PermissionClaimOnConflictOptions) DeepCopy() *PermissionClaimOnConflictOptions { - if in == nil { - return nil - } - out := new(PermissionClaimOnConflictOptions) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PermissionClaim) DeepCopyInto(out *PermissionClaim) { *out = *in @@ -1001,6 +986,38 @@ func (in *PermissionClaim) DeepCopy() *PermissionClaim { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PermissionClaimCreateOptions) DeepCopyInto(out *PermissionClaimCreateOptions) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PermissionClaimCreateOptions. +func (in *PermissionClaimCreateOptions) DeepCopy() *PermissionClaimCreateOptions { + if in == nil { + return nil + } + out := new(PermissionClaimCreateOptions) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PermissionClaimOnConflictOptions) DeepCopyInto(out *PermissionClaimOnConflictOptions) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PermissionClaimOnConflictOptions. +func (in *PermissionClaimOnConflictOptions) DeepCopy() *PermissionClaimOnConflictOptions { + if in == nil { + return nil + } + out := new(PermissionClaimOnConflictOptions) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PermissionClaimReadOptions) DeepCopyInto(out *PermissionClaimReadOptions) { *out = *in @@ -1019,8 +1036,8 @@ func (in *PermissionClaimReadOptions) DeepCopyInto(out *PermissionClaimReadOptio *out = make([]Matcher, len(*in)) copy(*out, *in) } - if in.OverrideAnnotations != nil { - in, out := &in.OverrideAnnotations, &out.OverrideAnnotations + if in.AnnotationsOnProviderOwnedObjects != nil { + in, out := &in.AnnotationsOnProviderOwnedObjects, &out.AnnotationsOnProviderOwnedObjects *out = make([]Matcher, len(*in)) copy(*out, *in) } @@ -1037,50 +1054,6 @@ func (in *PermissionClaimReadOptions) DeepCopy() *PermissionClaimReadOptions { return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ResourceSelector) DeepCopyInto(out *ResourceSelector) { - *out = *in - if in.Names != nil { - in, out := &in.Names, &out.Names - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Namespaces != nil { - in, out := &in.Namespaces, &out.Namespaces - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.LabelSelectors != nil { - in, out := &in.LabelSelectors, &out.LabelSelectors - *out = make([]map[string]string, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - } - } - if in.FieldSelectors != nil { - in, out := &in.FieldSelectors, &out.FieldSelectors - *out = make([]string, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSelector. -func (in *ResourceSelector) DeepCopy() *ResourceSelector { - if in == nil { - return nil - } - out := new(ResourceSelector) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PermissionClaimUpdateOptions) DeepCopyInto(out *PermissionClaimUpdateOptions) { *out = *in @@ -1126,3 +1099,47 @@ func (in *PermissionClaimUpdateOptions) DeepCopy() *PermissionClaimUpdateOptions in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceSelector) DeepCopyInto(out *ResourceSelector) { + *out = *in + if in.Names != nil { + in, out := &in.Names, &out.Names + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Namespaces != nil { + in, out := &in.Namespaces, &out.Namespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.LabelSelectors != nil { + in, out := &in.LabelSelectors, &out.LabelSelectors + *out = make([]map[string]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + } + if in.FieldSelectors != nil { + in, out := &in.FieldSelectors, &out.FieldSelectors + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSelector. +func (in *ResourceSelector) DeepCopy() *ResourceSelector { + if in == nil { + return nil + } + out := new(ResourceSelector) + in.DeepCopyInto(out) + return out +} From 31c7f3c445626869d0b8218cef22d5c576596cbb Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Mon, 23 Oct 2023 18:50:51 +0200 Subject: [PATCH 10/12] Update tests Signed-off-by: Dr. Stefan Schimanski --- .../bind-apiservice/plugin/servicebindings.go | 12 +- .../plugin/servicebindings_test.go | 898 ++++++++++-------- 2 files changed, 496 insertions(+), 414 deletions(-) diff --git a/pkg/kubectl/bind-apiservice/plugin/servicebindings.go b/pkg/kubectl/bind-apiservice/plugin/servicebindings.go index 4c97b442f..901e07bff 100644 --- a/pkg/kubectl/bind-apiservice/plugin/servicebindings.go +++ b/pkg/kubectl/bind-apiservice/plugin/servicebindings.go @@ -120,7 +120,7 @@ func (b *BindAPIServiceOptions) createAPIServiceBindings(ctx context.Context, co return bindings, nil } -func printPermissionClaim(w io.Writer, p kubebindv1alpha1.PermissionClaim) error { +func printPermissionClaim(w io.Writer, p kubebindv1alpha1.ExportPermissionClaim) error { var b bytes.Buffer var groupResource string @@ -130,19 +130,19 @@ func printPermissionClaim(w io.Writer, p kubebindv1alpha1.PermissionClaim) error groupResource = fmt.Sprintf("%s objects (apiVersion: \"%s\")", p.GroupResource.Resource, p.Version) } - if err := writeFirstLines(&b, groupResource, p); err != nil { + if err := writeFirstLines(&b, groupResource, p.PermissionClaim); err != nil { return err } - if err := writeCreate(&b, p); err != nil { + if err := writeCreate(&b, p.PermissionClaim); err != nil { return err } - if err := writeOnConflict(&b, p); err != nil { + if err := writeOnConflict(&b, p.PermissionClaim); err != nil { return err } - if err := writeUpdateClause(&b, p); err != nil { + if err := writeUpdateClause(&b, p.PermissionClaim); err != nil { return err } @@ -274,7 +274,7 @@ func writeRequiredAndAcceptance(b *bytes.Buffer, required bool) error { return err } -func (opt BindAPIServiceOptions) promptYesNo(p kubebindv1alpha1.PermissionClaim) (bool, error) { +func (opt BindAPIServiceOptions) promptYesNo(p kubebindv1alpha1.ExportPermissionClaim) (bool, error) { reader := bufio.NewReader(opt.Options.IOStreams.In) diff --git a/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go b/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go index b9158ee8c..3889ecbb4 100644 --- a/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go +++ b/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go @@ -31,18 +31,20 @@ func TestHumanReadablePromt(t *testing.T) { tests := []struct { name string - testData kubebindv1alpha1.PermissionClaim + testData kubebindv1alpha1.ExportPermissionClaim expectedOutput string }{ {"Owner=Provider", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, }, Required: true, }, @@ -51,14 +53,16 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,Required=false", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, }, Required: false, }, @@ -67,15 +71,17 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,Selector.Names={foo}", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Names: []string{"bar"}, - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar"}, + Owner: kubebindv1alpha1.Provider, + }, }, Required: true, }, @@ -86,14 +92,16 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,GroupResource.Group", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "example.com", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "example.com", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, }, Required: true, }, @@ -102,15 +110,17 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,Selector.Names={bar},GroupResource.Group", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "example.com", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Names: []string{"bar"}, - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "example.com", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar"}, + Owner: kubebindv1alpha1.Provider, + }, }, Required: true, }, @@ -121,106 +131,118 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,CreateOptions={}", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Create: &kubebindv1alpha1.PermissionClaimCreateOptions{}, }, Required: true, - Create: &kubebindv1alpha1.PermissionClaimCreateOptions{}, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,AutoDonate=false", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + AutoDonate: false, }, - Required: true, - AutoDonate: false, + Required: true, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,AutoDonate=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + AutoDonate: true, }, - Required: true, - AutoDonate: true, + Required: true, }, "The provider wants to create user owned foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,OnConflict={}", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{}, }, - Required: true, - OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{}, + Required: true, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,Create.ReplaceExisting=false", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ + ReplaceExisting: false, + }, }, Required: true, - Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ - ReplaceExisting: false, - }, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,Create.ReplaceExisting=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ + ReplaceExisting: true, + }, }, Required: true, - Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ - ReplaceExisting: true, - }, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "Conflicting objects will be replaced by the provider. " + @@ -228,38 +250,42 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,OnConflict.RecreateWhenConsumerSideDeleted=false", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{ + RecreateWhenConsumerSideDeleted: false, + }, }, Required: true, - OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{ - RecreateWhenConsumerSideDeleted: false, - }, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,OnConflict.RecreateWhenConsumerSideDeleted=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{ + RecreateWhenConsumerSideDeleted: true, + }, }, Required: true, - OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{ - RecreateWhenConsumerSideDeleted: true, - }, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "Created objects will be recreated upon deletion. " + @@ -267,36 +293,40 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,UpdateOptions={}", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{}, }, Required: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{}, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,UpdateOptions.Fields", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ + Fields: []string{"foo", "bar"}, + }, }, Required: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ - Fields: []string{"foo", "bar"}, - }, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "The following fields of the objects will still be able to be changed by the provider:\n" + // TODO @@ -306,19 +336,21 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,UpdateOptions.Preserving", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ + Preserving: []string{"foo", "bar"}, + }, }, Required: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ - Preserving: []string{"foo", "bar"}, - }, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "The following fields of the objects will be preserved by the provider:\n" + @@ -328,19 +360,21 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,UpdateOptions.AlwaysRecreate=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ + AlwaysRecreate: true, + }, }, Required: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ - AlwaysRecreate: true, - }, }, "The provider wants to write foo objects (apiVersion: \"v1\") on your cluster.\n" + "Modification of said objects will by handled by deletion and recreation of said objects.\n" + @@ -348,20 +382,22 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,UpdateOptions.Fields,AutoDonate=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, - }, - Required: true, - AutoDonate: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ - Fields: []string{"foo", "bar"}, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + AutoDonate: true, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ + Fields: []string{"foo", "bar"}, + }, }, + Required: true, }, "The provider wants to create user owned foo objects (apiVersion: \"v1\") on your cluster.\n" + "The following fields of the objects will still be able to be changed by the provider:\n" + @@ -371,20 +407,22 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,UpdateOptions.Preserving,AutoDonate=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Provider, - }, - Required: true, - AutoDonate: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ - Preserving: []string{"foo", "bar"}, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Provider, + }, + AutoDonate: true, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ + Preserving: []string{"foo", "bar"}, + }, }, + Required: true, }, "The provider wants to create user owned foo objects (apiVersion: \"v1\") on your cluster.\n" + "The following fields of the objects will be preserved by the provider:\n" + @@ -394,14 +432,16 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Consumer, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, }, Required: true, }, @@ -410,15 +450,17 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,Selector.Names={bar}", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Names: []string{"bar"}, - Owner: kubebindv1alpha1.Consumer, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar"}, + Owner: kubebindv1alpha1.Consumer, + }, }, Required: true, }, @@ -429,14 +471,16 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,GroupResource.Group", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "example.com", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Consumer, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "example.com", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, }, Required: true, }, @@ -445,15 +489,17 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,Selector.Names={bar},GroupResource.Group", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "example.com", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Names: []string{"bar"}, - Owner: kubebindv1alpha1.Consumer, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "example.com", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar"}, + Owner: kubebindv1alpha1.Consumer, + }, }, Required: true, }, @@ -464,35 +510,39 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,Adopt=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + AutoAdopt: true, }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Consumer, - }, - AutoAdopt: true, - Required: true, + Required: true, }, "The provider wants to have ownership of foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,Selector.Names={bar},Adopt=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar"}, + Owner: kubebindv1alpha1.Consumer, + }, + AutoAdopt: true, }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Names: []string{"bar"}, - Owner: kubebindv1alpha1.Consumer, - }, - AutoAdopt: true, - Required: true, + Required: true, }, "The provider wants to have ownership of foo objects (apiVersion: \"v1\") which are referenced with:\n" + "\t- name: \"bar\"\n" + @@ -501,55 +551,61 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,OnConflict={}", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{}, }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Consumer, - }, - Required: true, - OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{}, + Required: true, }, "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,Create.ReplaceExisting=false", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Consumer, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ + ReplaceExisting: false, + }, }, Required: true, - Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ - ReplaceExisting: false, - }, }, "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,Create.ReplaceExisting=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Consumer, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ + ReplaceExisting: true, + }, }, Required: true, - Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ - ReplaceExisting: true, - }, }, "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + "Conflicting objects will be replaced by the provider. " + @@ -557,36 +613,40 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,UpdateOptions={}", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Consumer, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{}, }, Required: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{}, }, "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,UpdateOptions.Fields", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Consumer, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ + Fields: []string{"foo", "bar"}, + }, }, Required: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ - Fields: []string{"foo", "bar"}, - }, }, "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + "The following fields of the objects will still be able to be changed by the provider:\n" + @@ -596,19 +656,21 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,UpdateOptions.Preserving", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Consumer, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ + Preserving: []string{"foo", "bar"}, + }, }, Required: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ - Preserving: []string{"foo", "bar"}, - }, }, "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + "The following fields of the objects will be preserved by the provider:\n" + @@ -618,19 +680,21 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,UpdateOptions.AlwaysRecreate=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Consumer, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ + AlwaysRecreate: true, + }, }, Required: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ - AlwaysRecreate: true, - }, }, "The provider wants to read foo objects (apiVersion: \"v1\") on your cluster.\n" + "Modification of said objects will by handled by deletion and recreation of said objects.\n" + @@ -638,20 +702,22 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,UpdateOptions.Fields,Adopt=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Consumer, - }, - Required: true, - AutoAdopt: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ - Fields: []string{"foo", "bar"}, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + AutoAdopt: true, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ + Fields: []string{"foo", "bar"}, + }, }, + Required: true, }, "The provider wants to have ownership of foo objects (apiVersion: \"v1\") on your cluster.\n" + "The following fields of the objects will still be able to be changed by the provider:\n" + @@ -661,20 +727,22 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Consumer,UpdateOptions.Preserving,Adopt=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Owner: kubebindv1alpha1.Consumer, - }, - Required: true, - AutoAdopt: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ - Preserving: []string{"foo", "bar"}, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Owner: kubebindv1alpha1.Consumer, + }, + AutoAdopt: true, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ + Preserving: []string{"foo", "bar"}, + }, }, + Required: true, }, "The provider wants to have ownership of foo objects (apiVersion: \"v1\") on your cluster.\n" + "The following fields of the objects will be preserved by the provider:\n" + " \"foo\"\n" + @@ -683,13 +751,15 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Selector={}", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{}, }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{}, Required: true, }, "The provider wants to read and write foo objects (apiVersion: \"v1\") on your cluster.\n" + @@ -697,14 +767,16 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Selector.Owner=\"\",Selector.Names={bar}", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Names: []string{"bar"}, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar"}, + }, }, Required: true, }, @@ -715,31 +787,35 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Selector={},AutoDonate=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{}, + AutoDonate: true, }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{}, - Required: true, - AutoDonate: true, + Required: true, }, "The provider wants to create user owned foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + "Do you accept this Permission? [No,Yes]\n", }, {"Selector={},AutoDonate=true,update.Fields=[\"spec\"]", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{}, - AutoDonate: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ - Fields: []string{"spec"}, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{}, + AutoDonate: true, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ + Fields: []string{"spec"}, + }, }, }, "The provider wants to create user owned foo objects (apiVersion: \"v1\") on your cluster.\n" + @@ -749,31 +825,35 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Selector={},adopt=true", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{}, + AutoAdopt: true, }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{}, - Required: true, - AutoAdopt: true, + Required: true, }, "The provider wants to have ownership of foo objects (apiVersion: \"v1\") on your cluster.\n" + "Accepting this Permission is required in order to proceed.\n" + "Do you accept this Permission? [No,Yes]\n", }, {"Selector={},adopt=true,update.Fields=[\"spec\"]", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{}, - AutoAdopt: true, - Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ - Fields: []string{"spec"}, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{}, + AutoAdopt: true, + Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ + Fields: []string{"spec"}, + }, }, }, "The provider wants to have ownership of foo objects (apiVersion: \"v1\") on your cluster.\n" + @@ -783,15 +863,17 @@ func TestHumanReadablePromt(t *testing.T) { "Do you accept this Permission? [No,Yes]\n", }, {"Owner=Provider,Selector.Names={bar,baz}", - kubebindv1alpha1.PermissionClaim{ - GroupResource: kubebindv1alpha1.GroupResource{ - Group: "", - Resource: "foo", - }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ - Names: []string{"bar", "baz"}, - Owner: kubebindv1alpha1.Provider, + kubebindv1alpha1.ExportPermissionClaim{ + PermissionClaim: kubebindv1alpha1.PermissionClaim{ + GroupResource: kubebindv1alpha1.GroupResource{ + Group: "", + Resource: "foo", + }, + Version: "v1", + Selector: &kubebindv1alpha1.ResourceSelector{ + Names: []string{"bar", "baz"}, + Owner: kubebindv1alpha1.Provider, + }, }, Required: true, }, From 1ab45c3550aa73b4087b2b4d9987c31efeba92f5 Mon Sep 17 00:00:00 2001 From: "Dr. Stefan Schimanski" Date: Tue, 24 Oct 2023 09:58:37 +0200 Subject: [PATCH 11/12] Address comments Signed-off-by: Dr. Stefan Schimanski --- .../crd/kube-bind.io_apiservicebindings.yaml | 146 ++++++++-------- ...kube-bind.io_apiserviceexportrequests.yaml | 158 +++++++++--------- .../crd/kube-bind.io_apiserviceexports.yaml | 146 ++++++++-------- .../v1alpha1/permissionclaims_types.go | 55 +++--- .../v1alpha1/zz_generated.deepcopy.go | 94 +++++------ .../bind-apiservice/plugin/servicebindings.go | 13 +- .../plugin/servicebindings_test.go | 116 ++++++------- 7 files changed, 357 insertions(+), 371 deletions(-) diff --git a/deploy/crd/kube-bind.io_apiservicebindings.yaml b/deploy/crd/kube-bind.io_apiservicebindings.yaml index dfa186378..dd4fe66bc 100644 --- a/deploy/crd/kube-bind.io_apiservicebindings.yaml +++ b/deploy/crd/kube-bind.io_apiservicebindings.yaml @@ -95,20 +95,6 @@ spec: stores the users acceptance in the field state. Only accepted permission claims are reconciled. properties: - autoAdopt: - description: "autoAdopt set to true means that objects created - by the consumer on the consumer cluster are immediately adopted - by the provider by syncing them to the provider side and then - marking them as owned by the provider on both sides. \n autoAdopt - is mutually exclusive with autoDonate." - type: boolean - autoDonate: - description: "autoDonate set to true means that a newly created - object synced from the provider to the consumer cluster is - immediately donated to the consumer by marking it as owned - by the consumer on both sides. \n autoDonate is mutually exclusive - with autoAdopt." - type: boolean create: description: "create determines whether the provider can create new objects in the consumer cluster by syncing a provider-owned @@ -129,6 +115,62 @@ spec: this is the empty string '""'. pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9](\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)?)$ type: string + objectSelector: + description: selector restricts which objects of the given resource + are being claimed. If unset, all objects across all namespaces + are being claimed, both consumer- and provider owned. + properties: + fieldSelectors: + description: fieldSelectors is a disjunctive list of field + selectors, following the same rules as kubernetes field + selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/, + i.e. each field selector can be a conjunction of requirements. + items: + type: string + type: array + labelSelectors: + description: labelSelectors is a disjunctive list of label + selectors, following the same rules as kubernetes label + selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. + items: + additionalProperties: + type: string + type: object + type: array + names: + default: + - '*' + description: names is a list of values selecting by metadata.name, + or "*" which matches all names. + items: + type: string + type: array + x-kubernetes-validations: + - message: only names or * are allowed + rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]$')) + namespaces: + default: + - '*' + description: namespaces is a list of values selecting by + metadata.namespace, or "*" which matches all namespaces, + or empty string that matches cluster-scoped resources. + items: + type: string + type: array + x-kubernetes-validations: + - message: only namespace names,* or empty string are allowed + rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]?$')) + owner: + description: owner set means that resources of a specific + owner are selected and those owned by the other side are + ignored. A resource on the consumer cluster is owned by + the consumer by default, if not marked as owned by the + provider through the `kube-bind.io/owner=provider` annotation. + enum: + - Provider + - Consumer + type: string + type: object onConflict: description: onConflict determines how conflicts between objects on the consumer and provider clusters will be resolved. @@ -143,6 +185,20 @@ spec: cluster as well." type: boolean type: object + ownerTransfer: + description: ownerTransfer determines how ownership of objects + is transferred between the consumer and the provider. By default, + no transfer happens. If set to Donate, objects created by + the provider on the consumer cluster are immediately donated + to the consumer. If set to Adopt, objects created by the consumer + on the consumer cluster are immediately owned by the provider + and synced to the provider cluster. Ownership determines the + direction of synchronization. + enum: + - Donate + - Adopt + - "" + type: string read: description: read claims read access for the provider to matching objects, excluding labels and annotations by default. Read @@ -226,62 +282,6 @@ spec: provided by a CRD not provided by an service binding export.' pattern: ^[a-z][-a-z0-9]*[a-z0-9]$ type: string - selector: - description: selector restricts which objects of the given resource - are being claimed. If unset, all objects across all namespaces - are being claimed, both consumer- and provider owned. - properties: - fieldSelectors: - description: fieldSelectors is a disjunctive list of field - selectors, following the same rules as kubernetes field - selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/, - i.e. each field selector can be a conjunction of requirements. - items: - type: string - type: array - labelSelectors: - description: labelSelectors is a disjunctive list of label - selectors, following the same rules as kubernetes label - selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. - items: - additionalProperties: - type: string - type: object - type: array - names: - default: - - '*' - description: names is a list of values selecting by metadata.name, - or "*" which matches all names. - items: - type: string - type: array - x-kubernetes-validations: - - message: only names or * are allowed - rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]$')) - namespaces: - default: - - '*' - description: namespaces is a list of values selecting by - metadata.namespace, or "*" which matches all namespaces, - or empty string that matches cluster-scoped resources. - items: - type: string - type: array - x-kubernetes-validations: - - message: only namespace names,* or empty string are allowed - rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]?$')) - owner: - description: owner set means that resources of a specific - owner are selected and those owned by the other side are - ignored. A resource on the consumer cluster is owned by - the consumer by default, if not marked as owned by the - provider through the `kube-bind.io/owner=provider` annotation. - enum: - - Provider - - Consumer - type: string - type: object state: description: state indicates if the claim is accepted or rejected. enum: @@ -383,7 +383,7 @@ spec: objects on the consumer cluster that the consumer keeps controlling, i.e. that are not overwritten by the provider, but synced back to the provider side. \n This is ignored - for consumer-owned objects.." + for consumer-owned objects." items: type: string type: array @@ -397,10 +397,6 @@ spec: - state - version type: object - x-kubernetes-validations: - - message: donate and adopt are mutually exclusive - rule: '!(has(self.autoDonate) && self.autoDonate && has(self.autoAdopt) - && self.autoAdopt)' type: array required: - kubeconfigSecretRef diff --git a/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml b/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml index ef8431db2..7a7771fcc 100644 --- a/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml +++ b/deploy/crd/kube-bind.io_apiserviceexportrequests.yaml @@ -91,21 +91,6 @@ spec: only set if the object is owned by the respective other side." properties: - autoAdopt: - description: "autoAdopt set to true means that objects - created by the consumer on the consumer cluster are - immediately adopted by the provider by syncing them - to the provider side and then marking them as owned - by the provider on both sides. \n autoAdopt is mutually - exclusive with autoDonate." - type: boolean - autoDonate: - description: "autoDonate set to true means that a newly - created object synced from the provider to the consumer - cluster is immediately donated to the consumer by marking - it as owned by the consumer on both sides. \n autoDonate - is mutually exclusive with autoAdopt." - type: boolean create: description: "create determines whether the provider can create new objects in the consumer cluster by syncing @@ -127,6 +112,67 @@ spec: groups this is the empty string '""'. pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9](\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)?)$ type: string + objectSelector: + description: selector restricts which objects of the given + resource are being claimed. If unset, all objects across + all namespaces are being claimed, both consumer- and + provider owned. + properties: + fieldSelectors: + description: fieldSelectors is a disjunctive list + of field selectors, following the same rules as + kubernetes field selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/, + i.e. each field selector can be a conjunction of + requirements. + items: + type: string + type: array + labelSelectors: + description: labelSelectors is a disjunctive list + of label selectors, following the same rules as + kubernetes label selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. + items: + additionalProperties: + type: string + type: object + type: array + names: + default: + - '*' + description: names is a list of values selecting by + metadata.name, or "*" which matches all names. + items: + type: string + type: array + x-kubernetes-validations: + - message: only names or * are allowed + rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]$')) + namespaces: + default: + - '*' + description: namespaces is a list of values selecting + by metadata.namespace, or "*" which matches all + namespaces, or empty string that matches cluster-scoped + resources. + items: + type: string + type: array + x-kubernetes-validations: + - message: only namespace names,* or empty string + are allowed + rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]?$')) + owner: + description: owner set means that resources of a specific + owner are selected and those owned by the other + side are ignored. A resource on the consumer cluster + is owned by the consumer by default, if not marked + as owned by the provider through the `kube-bind.io/owner=provider` + annotation. + enum: + - Provider + - Consumer + type: string + type: object onConflict: description: onConflict determines how conflicts between objects on the consumer and provider clusters will be @@ -142,6 +188,21 @@ spec: get deleted on the provider cluster as well." type: boolean type: object + ownerTransfer: + description: ownerTransfer determines how ownership of + objects is transferred between the consumer and the + provider. By default, no transfer happens. If set to + Donate, objects created by the provider on the consumer + cluster are immediately donated to the consumer. If + set to Adopt, objects created by the consumer on the + consumer cluster are immediately owned by the provider + and synced to the provider cluster. Ownership determines + the direction of synchronization. + enum: + - Donate + - Adopt + - "" + type: string read: description: read claims read access for the provider to matching objects, excluding labels and annotations @@ -228,67 +289,6 @@ spec: binding export.' pattern: ^[a-z][-a-z0-9]*[a-z0-9]$ type: string - selector: - description: selector restricts which objects of the given - resource are being claimed. If unset, all objects across - all namespaces are being claimed, both consumer- and - provider owned. - properties: - fieldSelectors: - description: fieldSelectors is a disjunctive list - of field selectors, following the same rules as - kubernetes field selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/, - i.e. each field selector can be a conjunction of - requirements. - items: - type: string - type: array - labelSelectors: - description: labelSelectors is a disjunctive list - of label selectors, following the same rules as - kubernetes label selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. - items: - additionalProperties: - type: string - type: object - type: array - names: - default: - - '*' - description: names is a list of values selecting by - metadata.name, or "*" which matches all names. - items: - type: string - type: array - x-kubernetes-validations: - - message: only names or * are allowed - rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]$')) - namespaces: - default: - - '*' - description: namespaces is a list of values selecting - by metadata.namespace, or "*" which matches all - namespaces, or empty string that matches cluster-scoped - resources. - items: - type: string - type: array - x-kubernetes-validations: - - message: only namespace names,* or empty string - are allowed - rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]?$')) - owner: - description: owner set means that resources of a specific - owner are selected and those owned by the other - side are ignored. A resource on the consumer cluster - is owned by the consumer by default, if not marked - as owned by the provider through the `kube-bind.io/owner=provider` - annotation. - enum: - - Provider - - Consumer - type: string - type: object update: description: "update lists which updates to objects on the consumer cluster are claimed. By default, the whole @@ -388,7 +388,7 @@ spec: the consumer keeps controlling, i.e. that are not overwritten by the provider, but synced back to the provider side. \n This is ignored for consumer-owned - objects.." + objects." items: type: string type: array @@ -401,10 +401,6 @@ spec: - resource - version type: object - x-kubernetes-validations: - - message: donate and adopt are mutually exclusive - rule: '!(has(self.autoDonate) && self.autoDonate && has(self.autoAdopt) - && self.autoAdopt)' type: array resource: description: 'resource is the name of the resource. Note: it diff --git a/deploy/crd/kube-bind.io_apiserviceexports.yaml b/deploy/crd/kube-bind.io_apiserviceexports.yaml index b7f2668f1..f83a94964 100644 --- a/deploy/crd/kube-bind.io_apiserviceexports.yaml +++ b/deploy/crd/kube-bind.io_apiserviceexports.yaml @@ -118,20 +118,6 @@ spec: (accepted or rejected) by the consumer." items: properties: - autoAdopt: - description: "autoAdopt set to true means that objects created - by the consumer on the consumer cluster are immediately adopted - by the provider by syncing them to the provider side and then - marking them as owned by the provider on both sides. \n autoAdopt - is mutually exclusive with autoDonate." - type: boolean - autoDonate: - description: "autoDonate set to true means that a newly created - object synced from the provider to the consumer cluster is - immediately donated to the consumer by marking it as owned - by the consumer on both sides. \n autoDonate is mutually exclusive - with autoAdopt." - type: boolean create: description: "create determines whether the provider can create new objects in the consumer cluster by syncing a provider-owned @@ -152,6 +138,62 @@ spec: this is the empty string '""'. pattern: ^(|[a-z0-9]([-a-z0-9]*[a-z0-9](\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*)?)$ type: string + objectSelector: + description: selector restricts which objects of the given resource + are being claimed. If unset, all objects across all namespaces + are being claimed, both consumer- and provider owned. + properties: + fieldSelectors: + description: fieldSelectors is a disjunctive list of field + selectors, following the same rules as kubernetes field + selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/, + i.e. each field selector can be a conjunction of requirements. + items: + type: string + type: array + labelSelectors: + description: labelSelectors is a disjunctive list of label + selectors, following the same rules as kubernetes label + selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. + items: + additionalProperties: + type: string + type: object + type: array + names: + default: + - '*' + description: names is a list of values selecting by metadata.name, + or "*" which matches all names. + items: + type: string + type: array + x-kubernetes-validations: + - message: only names or * are allowed + rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]$')) + namespaces: + default: + - '*' + description: namespaces is a list of values selecting by + metadata.namespace, or "*" which matches all namespaces, + or empty string that matches cluster-scoped resources. + items: + type: string + type: array + x-kubernetes-validations: + - message: only namespace names,* or empty string are allowed + rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]?$')) + owner: + description: owner set means that resources of a specific + owner are selected and those owned by the other side are + ignored. A resource on the consumer cluster is owned by + the consumer by default, if not marked as owned by the + provider through the `kube-bind.io/owner=provider` annotation. + enum: + - Provider + - Consumer + type: string + type: object onConflict: description: onConflict determines how conflicts between objects on the consumer and provider clusters will be resolved. @@ -166,6 +208,20 @@ spec: cluster as well." type: boolean type: object + ownerTransfer: + description: ownerTransfer determines how ownership of objects + is transferred between the consumer and the provider. By default, + no transfer happens. If set to Donate, objects created by + the provider on the consumer cluster are immediately donated + to the consumer. If set to Adopt, objects created by the consumer + on the consumer cluster are immediately owned by the provider + and synced to the provider cluster. Ownership determines the + direction of synchronization. + enum: + - Donate + - Adopt + - "" + type: string read: description: read claims read access for the provider to matching objects, excluding labels and annotations by default. Read @@ -254,62 +310,6 @@ spec: provided by a CRD not provided by an service binding export.' pattern: ^[a-z][-a-z0-9]*[a-z0-9]$ type: string - selector: - description: selector restricts which objects of the given resource - are being claimed. If unset, all objects across all namespaces - are being claimed, both consumer- and provider owned. - properties: - fieldSelectors: - description: fieldSelectors is a disjunctive list of field - selectors, following the same rules as kubernetes field - selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/, - i.e. each field selector can be a conjunction of requirements. - items: - type: string - type: array - labelSelectors: - description: labelSelectors is a disjunctive list of label - selectors, following the same rules as kubernetes label - selectors, see https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/. - items: - additionalProperties: - type: string - type: object - type: array - names: - default: - - '*' - description: names is a list of values selecting by metadata.name, - or "*" which matches all names. - items: - type: string - type: array - x-kubernetes-validations: - - message: only names or * are allowed - rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]$')) - namespaces: - default: - - '*' - description: namespaces is a list of values selecting by - metadata.namespace, or "*" which matches all namespaces, - or empty string that matches cluster-scoped resources. - items: - type: string - type: array - x-kubernetes-validations: - - message: only namespace names,* or empty string are allowed - rule: self.all(n, n.matches('^[a-z0-9]([-a-z0-9]*[a-z0-9])?|[*]?$')) - owner: - description: owner set means that resources of a specific - owner are selected and those owned by the other side are - ignored. A resource on the consumer cluster is owned by - the consumer by default, if not marked as owned by the - provider through the `kube-bind.io/owner=provider` annotation. - enum: - - Provider - - Consumer - type: string - type: object update: description: "update lists which updates to objects on the consumer cluster are claimed. By default, the whole object is synced, @@ -405,7 +405,7 @@ spec: objects on the consumer cluster that the consumer keeps controlling, i.e. that are not overwritten by the provider, but synced back to the provider side. \n This is ignored - for consumer-owned objects.." + for consumer-owned objects." items: type: string type: array @@ -418,10 +418,6 @@ spec: - resource - version type: object - x-kubernetes-validations: - - message: donate and adopt are mutually exclusive - rule: '!(has(self.autoDonate) && self.autoDonate && has(self.autoAdopt) - && self.autoAdopt)' type: array scope: description: scope indicates whether the defined custom resource is diff --git a/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go b/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go index eab840518..2863e74d2 100644 --- a/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go +++ b/pkg/apis/kubebind/v1alpha1/permissionclaims_types.go @@ -33,8 +33,6 @@ package v1alpha1 // Objects on the consumer cluster are owned by the consumer by default. Objects // on the provider cluster are owned by the provider by default. The annotation // is only set if the object is owned by the respective other side. -// -// +kubebuilder:validation:XValidation:rule="!(has(self.autoDonate) && self.autoDonate && has(self.autoAdopt) && self.autoAdopt)",message="donate and adopt are mutually exclusive" type PermissionClaim struct { GroupResource `json:","` @@ -50,7 +48,7 @@ type PermissionClaim struct { // // +optional // +kubebuilder:default:={} - Selector *ResourceSelector `json:"selector,omitempty"` + ObjectSelector *ObjectSelector `json:"objectSelector,omitempty"` // read claims read access for the provider to matching objects, excluding // labels and annotations by default. Read access is realized by syncing @@ -70,25 +68,6 @@ type PermissionClaim struct { // +optional Create *PermissionClaimCreateOptions `json:"create,omitempty"` - // autoAdopt set to true means that objects created by the consumer on the - // consumer cluster are immediately adopted by the provider by syncing them - // to the provider side and then marking them as owned by the provider on - // both sides. - // - // autoAdopt is mutually exclusive with autoDonate. - // - // +optional - AutoAdopt bool `json:"autoAdopt,omitempty"` - - // autoDonate set to true means that a newly created object synced from the - // provider to the consumer cluster is immediately donated to the consumer - // by marking it as owned by the consumer on both sides. - // - // autoDonate is mutually exclusive with autoAdopt. - // - // +optional - AutoDonate bool `json:"autoDonate,omitempty"` - // onConflict determines how conflicts between objects on the consumer // and provider clusters will be resolved. // @@ -103,8 +82,28 @@ type PermissionClaim struct { // // +optional Update *PermissionClaimUpdateOptions `json:"update,omitempty"` + + // ownerTransfer determines how ownership of objects is transferred between + // the consumer and the provider. By default, no transfer happens. If set to + // Donate, objects created by the provider on the consumer cluster are + // immediately donated to the consumer. If set to Adopt, objects created by + // the consumer on the consumer cluster are immediately owned by the + // provider and synced to the provider cluster. Ownership determines the + // direction of synchronization. + // + // +kubebuilder:validation:Enum=Donate;Adopt;"" + // +optional + OwnerTransfer OwnerTransfer `json:"ownerTransfer,omitempty"` } +type OwnerTransfer string + +const ( + OwnerTransferNone OwnerTransfer = "" + OwnerTransferDonate OwnerTransfer = "Donate" + OwnerTransferAdopt OwnerTransfer = "Adopt" +) + type PermissionClaimReadOptions struct { // labels is a list of label key wildcard patterns that are synchronized // from the consumer to the provider on consumer-owned objects. @@ -177,7 +176,7 @@ type PermissionClaimUpdateOptions struct { // consumer cluster that the consumer keeps controlling, i.e. that are not // overwritten by the provider, but synced back to the provider side. // - // This is ignored for consumer-owned objects.. + // This is ignored for consumer-owned objects. // // +optional Preserving []string `json:"preserving,omitempty"` @@ -225,7 +224,7 @@ type PermissionClaimUpdateOptions struct { AnnotationsOnConsumerOwnedObjects []Matcher `json:"annotationsOnConsumerOwnedObjects,omitempty"` } -type ResourceSelector struct { +type ObjectSelector struct { // names is a list of values selecting by metadata.name, or "*" which // matches all names. // @@ -259,15 +258,15 @@ type ResourceSelector struct { // // +kubebuilder:validation:Enum=Provider;Consumer // +optional - Owner PermissionCaimResourceOwner `json:"owner,omitempty"` + Owner PermissionClaimResourceOwner `json:"owner,omitempty"` } -type PermissionCaimResourceOwner string +type PermissionClaimResourceOwner string const ( // Provider means that the owner of the resource is the Provider. - Provider PermissionCaimResourceOwner = "Provider" + Provider PermissionClaimResourceOwner = "Provider" // Consumer means that the owner of the resource is the Consumer. - Consumer PermissionCaimResourceOwner = "Consumer" + Consumer PermissionClaimResourceOwner = "Consumer" ) diff --git a/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go index 8074155c9..910deaa77 100644 --- a/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/kubebind/v1alpha1/zz_generated.deepcopy.go @@ -944,13 +944,57 @@ func (in *OAuth2CodeGrant) DeepCopy() *OAuth2CodeGrant { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ObjectSelector) DeepCopyInto(out *ObjectSelector) { + *out = *in + if in.Names != nil { + in, out := &in.Names, &out.Names + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Namespaces != nil { + in, out := &in.Namespaces, &out.Namespaces + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.LabelSelectors != nil { + in, out := &in.LabelSelectors, &out.LabelSelectors + *out = make([]map[string]string, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + } + } + if in.FieldSelectors != nil { + in, out := &in.FieldSelectors, &out.FieldSelectors + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ObjectSelector. +func (in *ObjectSelector) DeepCopy() *ObjectSelector { + if in == nil { + return nil + } + out := new(ObjectSelector) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PermissionClaim) DeepCopyInto(out *PermissionClaim) { *out = *in out.GroupResource = in.GroupResource - if in.Selector != nil { - in, out := &in.Selector, &out.Selector - *out = new(ResourceSelector) + if in.ObjectSelector != nil { + in, out := &in.ObjectSelector, &out.ObjectSelector + *out = new(ObjectSelector) (*in).DeepCopyInto(*out) } if in.Read != nil { @@ -1099,47 +1143,3 @@ func (in *PermissionClaimUpdateOptions) DeepCopy() *PermissionClaimUpdateOptions in.DeepCopyInto(out) return out } - -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *ResourceSelector) DeepCopyInto(out *ResourceSelector) { - *out = *in - if in.Names != nil { - in, out := &in.Names, &out.Names - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.Namespaces != nil { - in, out := &in.Namespaces, &out.Namespaces - *out = make([]string, len(*in)) - copy(*out, *in) - } - if in.LabelSelectors != nil { - in, out := &in.LabelSelectors, &out.LabelSelectors - *out = make([]map[string]string, len(*in)) - for i := range *in { - if (*in)[i] != nil { - in, out := &(*in)[i], &(*out)[i] - *out = make(map[string]string, len(*in)) - for key, val := range *in { - (*out)[key] = val - } - } - } - } - if in.FieldSelectors != nil { - in, out := &in.FieldSelectors, &out.FieldSelectors - *out = make([]string, len(*in)) - copy(*out, *in) - } - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSelector. -func (in *ResourceSelector) DeepCopy() *ResourceSelector { - if in == nil { - return nil - } - out := new(ResourceSelector) - in.DeepCopyInto(out) - return out -} diff --git a/pkg/kubectl/bind-apiservice/plugin/servicebindings.go b/pkg/kubectl/bind-apiservice/plugin/servicebindings.go index 901e07bff..edafa0be9 100644 --- a/pkg/kubectl/bind-apiservice/plugin/servicebindings.go +++ b/pkg/kubectl/bind-apiservice/plugin/servicebindings.go @@ -157,15 +157,14 @@ func printPermissionClaim(w io.Writer, p kubebindv1alpha1.ExportPermissionClaim) func writeFirstLines(b *bytes.Buffer, groupResource string, claim kubebindv1alpha1.PermissionClaim) error { var err error - donate := claim.AutoDonate - - adopt := claim.AutoAdopt + donate := claim.OwnerTransfer == kubebindv1alpha1.OwnerTransferDonate + adopt := claim.OwnerTransfer == kubebindv1alpha1.OwnerTransferAdopt var names []string - var owner kubebindv1alpha1.PermissionCaimResourceOwner - if claim.Selector != nil { - names = claim.Selector.Names - owner = claim.Selector.Owner + var owner kubebindv1alpha1.PermissionClaimResourceOwner + if claim.ObjectSelector != nil { + names = claim.ObjectSelector.Names + owner = claim.ObjectSelector.Owner } var verb string diff --git a/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go b/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go index 3889ecbb4..d59a62a36 100644 --- a/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go +++ b/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go @@ -42,7 +42,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, }, @@ -60,7 +60,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, }, @@ -78,7 +78,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Names: []string{"bar"}, Owner: kubebindv1alpha1.Provider, }, @@ -99,7 +99,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, }, @@ -117,7 +117,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Names: []string{"bar"}, Owner: kubebindv1alpha1.Provider, }, @@ -138,7 +138,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, Create: &kubebindv1alpha1.PermissionClaimCreateOptions{}, @@ -157,10 +157,10 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, - AutoDonate: false, + OwnerTransfer: kubebindv1alpha1.OwnerTransferDonate, }, Required: true, }, @@ -176,10 +176,10 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, - AutoDonate: true, + OwnerTransfer: kubebindv1alpha1.OwnerTransferDonate, }, Required: true, }, @@ -195,7 +195,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{}, @@ -214,7 +214,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ @@ -235,7 +235,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ @@ -257,7 +257,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{ @@ -278,7 +278,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{ @@ -300,7 +300,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{}, @@ -319,7 +319,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ @@ -343,7 +343,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ @@ -367,7 +367,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ @@ -389,13 +389,13 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, - AutoDonate: true, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Fields: []string{"foo", "bar"}, }, + OwnerTransfer: kubebindv1alpha1.OwnerTransferDonate, }, Required: true, }, @@ -414,13 +414,13 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, - AutoDonate: true, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Preserving: []string{"foo", "bar"}, }, + OwnerTransfer: kubebindv1alpha1.OwnerTransferDonate, }, Required: true, }, @@ -439,7 +439,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Consumer, }, }, @@ -457,7 +457,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Names: []string{"bar"}, Owner: kubebindv1alpha1.Consumer, }, @@ -478,7 +478,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Consumer, }, }, @@ -496,7 +496,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Names: []string{"bar"}, Owner: kubebindv1alpha1.Consumer, }, @@ -517,10 +517,10 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Consumer, }, - AutoAdopt: true, + OwnerTransfer: kubebindv1alpha1.OwnerTransferAdopt, }, Required: true, }, @@ -536,11 +536,11 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Names: []string{"bar"}, Owner: kubebindv1alpha1.Consumer, }, - AutoAdopt: true, + OwnerTransfer: kubebindv1alpha1.OwnerTransferAdopt, }, Required: true, }, @@ -558,7 +558,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Consumer, }, OnConflict: &kubebindv1alpha1.PermissionClaimOnConflictOptions{}, @@ -577,7 +577,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Consumer, }, Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ @@ -598,7 +598,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Consumer, }, Create: &kubebindv1alpha1.PermissionClaimCreateOptions{ @@ -620,7 +620,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Consumer, }, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{}, @@ -639,7 +639,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Consumer, }, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ @@ -663,7 +663,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Consumer, }, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ @@ -687,7 +687,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Consumer, }, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ @@ -709,13 +709,13 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Consumer, }, - AutoAdopt: true, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Fields: []string{"foo", "bar"}, }, + OwnerTransfer: kubebindv1alpha1.OwnerTransferAdopt, }, Required: true, }, @@ -734,13 +734,13 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Consumer, }, - AutoAdopt: true, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Preserving: []string{"foo", "bar"}, }, + OwnerTransfer: kubebindv1alpha1.OwnerTransferAdopt, }, Required: true, }, @@ -757,8 +757,8 @@ func TestHumanReadablePromt(t *testing.T) { Group: "", Resource: "foo", }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{}, + Version: "v1", + ObjectSelector: &kubebindv1alpha1.ObjectSelector{}, }, Required: true, }, @@ -774,7 +774,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Names: []string{"bar"}, }, }, @@ -793,9 +793,9 @@ func TestHumanReadablePromt(t *testing.T) { Group: "", Resource: "foo", }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{}, - AutoDonate: true, + Version: "v1", + ObjectSelector: &kubebindv1alpha1.ObjectSelector{}, + OwnerTransfer: kubebindv1alpha1.OwnerTransferDonate, }, Required: true, }, @@ -810,12 +810,12 @@ func TestHumanReadablePromt(t *testing.T) { Group: "", Resource: "foo", }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{}, - AutoDonate: true, + Version: "v1", + ObjectSelector: &kubebindv1alpha1.ObjectSelector{}, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Fields: []string{"spec"}, }, + OwnerTransfer: kubebindv1alpha1.OwnerTransferDonate, }, }, "The provider wants to create user owned foo objects (apiVersion: \"v1\") on your cluster.\n" + @@ -831,9 +831,9 @@ func TestHumanReadablePromt(t *testing.T) { Group: "", Resource: "foo", }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{}, - AutoAdopt: true, + Version: "v1", + ObjectSelector: &kubebindv1alpha1.ObjectSelector{}, + OwnerTransfer: kubebindv1alpha1.OwnerTransferAdopt, }, Required: true, }, @@ -848,12 +848,12 @@ func TestHumanReadablePromt(t *testing.T) { Group: "", Resource: "foo", }, - Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{}, - AutoAdopt: true, + Version: "v1", + ObjectSelector: &kubebindv1alpha1.ObjectSelector{}, Update: &kubebindv1alpha1.PermissionClaimUpdateOptions{ Fields: []string{"spec"}, }, + OwnerTransfer: kubebindv1alpha1.OwnerTransferAdopt, }, }, "The provider wants to have ownership of foo objects (apiVersion: \"v1\") on your cluster.\n" + @@ -870,7 +870,7 @@ func TestHumanReadablePromt(t *testing.T) { Resource: "foo", }, Version: "v1", - Selector: &kubebindv1alpha1.ResourceSelector{ + ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Names: []string{"bar", "baz"}, Owner: kubebindv1alpha1.Provider, }, From 81872fbf9cf547b2d2ffa80ddded7c7110ed1670 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lenny=20H=C3=A4ndler?= Date: Mon, 20 Nov 2023 10:46:59 +0100 Subject: [PATCH 12/12] Small fixes --- pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go b/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go index d59a62a36..d38aab910 100644 --- a/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go +++ b/pkg/kubectl/bind-apiservice/plugin/servicebindings_test.go @@ -26,7 +26,7 @@ import ( kubebindv1alpha1 "github.com/kube-bind/kube-bind/pkg/apis/kubebind/v1alpha1" ) -func TestHumanReadablePromt(t *testing.T) { +func TestHumanReadablePrompt(t *testing.T) { t.Parallel() tests := []struct { @@ -160,7 +160,7 @@ func TestHumanReadablePromt(t *testing.T) { ObjectSelector: &kubebindv1alpha1.ObjectSelector{ Owner: kubebindv1alpha1.Provider, }, - OwnerTransfer: kubebindv1alpha1.OwnerTransferDonate, + OwnerTransfer: kubebindv1alpha1.OwnerTransferNone, }, Required: true, },