diff --git a/api/v1/zz_generated.deepcopy.go b/api/v1/zz_generated.deepcopy.go index 8e73704a..03fd1a7c 100644 --- a/api/v1/zz_generated.deepcopy.go +++ b/api/v1/zz_generated.deepcopy.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 86815d6b..e1ddf333 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -1,5 +1,4 @@ //go:build !ignore_autogenerated -// +build !ignore_autogenerated /* diff --git a/config/crd/bases/services.cloud.sap.com_servicebindings.yaml b/config/crd/bases/services.cloud.sap.com_servicebindings.yaml index 1cccecbb..9f6384d3 100644 --- a/config/crd/bases/services.cloud.sap.com_servicebindings.yaml +++ b/config/crd/bases/services.cloud.sap.com_servicebindings.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.9.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.15.0 name: servicebindings.services.cloud.sap.com spec: group: services.cloud.sap.com @@ -42,14 +41,19 @@ spec: description: ServiceBinding is the Schema for the servicebindings API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -75,25 +79,30 @@ spec: description: The name of the binding in Service Manager type: string parameters: - description: "Parameters for the binding. \n The Parameters field - is NOT secret or secured in any way and should NEVER be used to - hold sensitive information. To set parameters that contain secret - information, you should ALWAYS store that information in a Secret - and use the ParametersFrom field." + description: |- + Parameters for the binding. + + + The Parameters field is NOT secret or secured in any way and should + NEVER be used to hold sensitive information. To set parameters that + contain secret information, you should ALWAYS store that information + in a Secret and use the ParametersFrom field. type: object x-kubernetes-preserve-unknown-fields: true parametersFrom: - description: List of sources to populate parameters. If a top-level - parameter name exists in multiples sources among `Parameters` and - `ParametersFrom` fields, it is considered to be a user error in - the specification + description: |- + List of sources to populate parameters. + If a top-level parameter name exists in multiples sources among + `Parameters` and `ParametersFrom` fields, it is + considered to be a user error in the specification items: description: ParametersFromSource represents the source of a set of Parameters properties: secretKeyRef: - description: The Secret key to select from. The value must be - a JSON object. + description: |- + The Secret key to select from. + The value must be a JSON object. properties: key: description: The key of the secret to select from. Must @@ -110,29 +119,31 @@ spec: type: object type: array secretKey: - description: SecretKey is used as the key inside the secret to store - the credentials returned by the broker encoded as json to support - complex data structures. If not specified, the credentials returned - by the broker will be used directly as the secrets data. + description: |- + SecretKey is used as the key inside the secret to store the credentials + returned by the broker encoded as json to support complex data structures. + If not specified, the credentials returned by the broker will be used + directly as the secrets data. type: string secretName: description: SecretName is the name of the secret where credentials will be stored type: string secretRootKey: - description: SecretRootKey is used as the key inside the secret to - store all binding data including credentials returned by the broker - and additional info under single key. Convenient way to store whole - binding data in single file when using `volumeMounts`. + description: |- + SecretRootKey is used as the key inside the secret to store all binding + data including credentials returned by the broker and additional info under single key. + Convenient way to store whole binding data in single file when using `volumeMounts`. type: string secretTemplate: - description: 'SecretTemplate is a Go template that generates a custom - Kubernetes v1/Secret based on data from the service binding returned - by Service Manager and the instance information. The generated secret - is used instead of the default secret. This is useful if the consumer - of service binding data expects them in a specific format. For Go - templates see https://pkg.go.dev/text/template. For supported funcs - see: https://pkg.go.dev/text/template#hdr-Functions, https://masterminds.github.io/sprig/' + description: |- + SecretTemplate is a Go template that generates a custom Kubernetes + v1/Secret based on data from the service binding returned by Service Manager and the instance information. + The generated secret is used instead of the default secret. + This is useful if the consumer of service binding data expects them in + a specific format. + For Go templates see https://pkg.go.dev/text/template. + For supported funcs see: https://pkg.go.dev/text/template#hdr-Functions, https://masterminds.github.io/sprig/ type: string x-kubernetes-preserve-unknown-fields: true serviceInstanceName: @@ -145,10 +156,10 @@ spec: namespace will be used type: string userInfo: - description: UserInfo contains information about the user that last - modified this instance. This field is set by the API server and - not settable by the end-user. User-provided values for this field - are not saved. + description: |- + UserInfo contains information about the user that last modified this + instance. This field is set by the API server and not settable by the + end-user. User-provided values for this field are not saved. properties: extra: additionalProperties: @@ -165,9 +176,10 @@ spec: type: array x-kubernetes-list-type: atomic uid: - description: A unique value that identifies this user across time. - If this user is deleted and another user by the same name is - added, they will have different UIDs. + description: |- + A unique value that identifies this user across time. If this user is + deleted and another user by the same name is added, they will have + different UIDs. type: string username: description: The name that uniquely identifies this user among @@ -188,42 +200,42 @@ spec: description: Service binding conditions items: description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -237,11 +249,12 @@ spec: - Unknown type: string type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string @@ -312,14 +325,19 @@ spec: description: ServiceBinding is the Schema for the servicebindings API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -345,25 +363,30 @@ spec: description: The name of the binding in Service Manager type: string parameters: - description: "Parameters for the binding. \n The Parameters field - is NOT secret or secured in any way and should NEVER be used to - hold sensitive information. To set parameters that contain secret - information, you should ALWAYS store that information in a Secret - and use the ParametersFrom field." + description: |- + Parameters for the binding. + + + The Parameters field is NOT secret or secured in any way and should + NEVER be used to hold sensitive information. To set parameters that + contain secret information, you should ALWAYS store that information + in a Secret and use the ParametersFrom field. type: object x-kubernetes-preserve-unknown-fields: true parametersFrom: - description: List of sources to populate parameters. If a top-level - parameter name exists in multiples sources among `Parameters` and - `ParametersFrom` fields, it is considered to be a user error in - the specification + description: |- + List of sources to populate parameters. + If a top-level parameter name exists in multiples sources among + `Parameters` and `ParametersFrom` fields, it is + considered to be a user error in the specification items: description: ParametersFromSource represents the source of a set of Parameters properties: secretKeyRef: - description: The Secret key to select from. The value must be - a JSON object. + description: |- + The Secret key to select from. + The value must be a JSON object. properties: key: description: The key of the secret to select from. Must @@ -380,20 +403,21 @@ spec: type: object type: array secretKey: - description: SecretKey is used as the key inside the secret to store - the credentials returned by the broker encoded as json to support - complex data structures. If not specified, the credentials returned - by the broker will be used directly as the secrets data. + description: |- + SecretKey is used as the key inside the secret to store the credentials + returned by the broker encoded as json to support complex data structures. + If not specified, the credentials returned by the broker will be used + directly as the secrets data. type: string secretName: description: SecretName is the name of the secret where credentials will be stored type: string secretRootKey: - description: SecretRootKey is used as the key inside the secret to - store all binding data including credentials returned by the broker - and additional info under single key. Convenient way to store whole - binding data in single file when using `volumeMounts`. + description: |- + SecretRootKey is used as the key inside the secret to store all binding + data including credentials returned by the broker and additional info under single key. + Convenient way to store whole binding data in single file when using `volumeMounts`. type: string serviceInstanceName: description: The k8s name of the service instance to bind, should @@ -401,10 +425,10 @@ spec: minLength: 1 type: string userInfo: - description: UserInfo contains information about the user that last - modified this instance. This field is set by the API server and - not settable by the end-user. User-provided values for this field - are not saved. + description: |- + UserInfo contains information about the user that last modified this + instance. This field is set by the API server and not settable by the + end-user. User-provided values for this field are not saved. properties: extra: additionalProperties: @@ -421,9 +445,10 @@ spec: type: array x-kubernetes-list-type: atomic uid: - description: A unique value that identifies this user across time. - If this user is deleted and another user by the same name is - added, they will have different UIDs. + description: |- + A unique value that identifies this user across time. If this user is + deleted and another user by the same name is added, they will have + different UIDs. type: string username: description: The name that uniquely identifies this user among @@ -444,42 +469,42 @@ spec: description: Service binding conditions items: description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -493,11 +518,12 @@ spec: - Unknown type: string type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string diff --git a/config/crd/bases/services.cloud.sap.com_serviceinstances.yaml b/config/crd/bases/services.cloud.sap.com_serviceinstances.yaml index d13b0b65..745cfde5 100644 --- a/config/crd/bases/services.cloud.sap.com_serviceinstances.yaml +++ b/config/crd/bases/services.cloud.sap.com_serviceinstances.yaml @@ -3,8 +3,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.9.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.15.0 name: serviceinstances.services.cloud.sap.com spec: group: services.cloud.sap.com @@ -51,14 +50,19 @@ spec: description: ServiceInstance is the Schema for the serviceinstances API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -82,25 +86,30 @@ spec: description: The name of the instance in Service Manager type: string parameters: - description: "Provisioning parameters for the instance. \n The Parameters - field is NOT secret or secured in any way and should NEVER be used - to hold sensitive information. To set parameters that contain secret - information, you should ALWAYS store that information in a Secret - and use the ParametersFrom field." + description: |- + Provisioning parameters for the instance. + + + The Parameters field is NOT secret or secured in any way and should + NEVER be used to hold sensitive information. To set parameters that + contain secret information, you should ALWAYS store that information + in a Secret and use the ParametersFrom field. type: object x-kubernetes-preserve-unknown-fields: true parametersFrom: - description: List of sources to populate parameters. If a top-level - parameter name exists in multiples sources among `Parameters` and - `ParametersFrom` fields, it is considered to be a user error in - the specification + description: |- + List of sources to populate parameters. + If a top-level parameter name exists in multiples sources among + `Parameters` and `ParametersFrom` fields, it is + considered to be a user error in the specification items: description: ParametersFromSource represents the source of a set of Parameters properties: secretKeyRef: - description: The Secret key to select from. The value must be - a JSON object. + description: |- + The Secret key to select from. + The value must be a JSON object. properties: key: description: The key of the secret to select from. Must @@ -132,10 +141,10 @@ spec: description: Indicates the desired shared state type: boolean userInfo: - description: UserInfo contains information about the user that last - modified this instance. This field is set by the API server and - not settable by the end-user. User-provided values for this field - are not saved. + description: |- + UserInfo contains information about the user that last modified this + instance. This field is set by the API server and not settable by the + end-user. User-provided values for this field are not saved. properties: extra: additionalProperties: @@ -152,9 +161,10 @@ spec: type: array x-kubernetes-list-type: atomic uid: - description: A unique value that identifies this user across time. - If this user is deleted and another user by the same name is - added, they will have different UIDs. + description: |- + A unique value that identifies this user across time. If this user is + deleted and another user by the same name is added, they will have + different UIDs. type: string username: description: The name that uniquely identifies this user among @@ -172,42 +182,42 @@ spec: description: Service instance conditions items: description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -221,11 +231,12 @@ spec: - Unknown type: string type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string @@ -306,14 +317,19 @@ spec: description: ServiceInstance is the Schema for the serviceinstances API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -330,25 +346,30 @@ spec: description: The name of the instance in Service Manager type: string parameters: - description: "Provisioning parameters for the instance. \n The Parameters - field is NOT secret or secured in any way and should NEVER be used - to hold sensitive information. To set parameters that contain secret - information, you should ALWAYS store that information in a Secret - and use the ParametersFrom field." + description: |- + Provisioning parameters for the instance. + + + The Parameters field is NOT secret or secured in any way and should + NEVER be used to hold sensitive information. To set parameters that + contain secret information, you should ALWAYS store that information + in a Secret and use the ParametersFrom field. type: object x-kubernetes-preserve-unknown-fields: true parametersFrom: - description: List of sources to populate parameters. If a top-level - parameter name exists in multiples sources among `Parameters` and - `ParametersFrom` fields, it is considered to be a user error in - the specification + description: |- + List of sources to populate parameters. + If a top-level parameter name exists in multiples sources among + `Parameters` and `ParametersFrom` fields, it is + considered to be a user error in the specification items: description: ParametersFromSource represents the source of a set of Parameters properties: secretKeyRef: - description: The Secret key to select from. The value must be - a JSON object. + description: |- + The Secret key to select from. + The value must be a JSON object. properties: key: description: The key of the secret to select from. Must @@ -380,10 +401,10 @@ spec: description: Indicates the desired shared state type: boolean userInfo: - description: UserInfo contains information about the user that last - modified this instance. This field is set by the API server and - not settable by the end-user. User-provided values for this field - are not saved. + description: |- + UserInfo contains information about the user that last modified this + instance. This field is set by the API server and not settable by the + end-user. User-provided values for this field are not saved. properties: extra: additionalProperties: @@ -400,9 +421,10 @@ spec: type: array x-kubernetes-list-type: atomic uid: - description: A unique value that identifies this user across time. - If this user is deleted and another user by the same name is - added, they will have different UIDs. + description: |- + A unique value that identifies this user across time. If this user is + deleted and another user by the same name is added, they will have + different UIDs. type: string username: description: The name that uniquely identifies this user among @@ -420,42 +442,42 @@ spec: description: Service instance conditions items: description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -469,11 +491,12 @@ spec: - Unknown type: string type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 19f5e777..de9857dc 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -2,7 +2,6 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - creationTimestamp: null name: manager-role rules: - apiGroups: diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml index 0d991b93..b158a1cb 100644 --- a/config/webhook/manifests.yaml +++ b/config/webhook/manifests.yaml @@ -2,7 +2,6 @@ apiVersion: admissionregistration.k8s.io/v1 kind: MutatingWebhookConfiguration metadata: - creationTimestamp: null name: mutating-webhook-configuration webhooks: - admissionReviewVersions: @@ -51,7 +50,6 @@ webhooks: apiVersion: admissionregistration.k8s.io/v1 kind: ValidatingWebhookConfiguration metadata: - creationTimestamp: null name: validating-webhook-configuration webhooks: - admissionReviewVersions: diff --git a/controllers/servicebinding_controller.go b/controllers/servicebinding_controller.go index e8ad11af..d2b5f7a3 100644 --- a/controllers/servicebinding_controller.go +++ b/controllers/servicebinding_controller.go @@ -38,7 +38,7 @@ import ( "k8s.io/client-go/util/workqueue" "sigs.k8s.io/controller-runtime/pkg/controller" - servicesv1 "github.com/SAP/sap-btp-service-operator/api/v1" + v1 "github.com/SAP/sap-btp-service-operator/api/v1" "k8s.io/apimachinery/pkg/api/meta" "k8s.io/apimachinery/pkg/runtime/schema" @@ -68,7 +68,7 @@ type ServiceBindingReconciler struct { client.Client Log logr.Logger Scheme *runtime.Scheme - GetSMClient func(ctx context.Context, resourceNamespace, btpAccessSecretName string) (sm.Client, error) + GetSMClient func(ctx context.Context, instance *v1.ServiceInstance) (sm.Client, error) Config config.Config Recorder record.EventRecorder } @@ -83,7 +83,7 @@ func (r *ServiceBindingReconciler) Reconcile(ctx context.Context, req ctrl.Reque log := r.Log.WithValues("servicebinding", req.NamespacedName).WithValues("correlation_id", uuid.New().String(), req.Name, req.Namespace) ctx = context.WithValue(ctx, utils.LogKey{}, log) - serviceBinding := &servicesv1.ServiceBinding{} + serviceBinding := &v1.ServiceBinding{} if err := r.Client.Get(ctx, req.NamespacedName, serviceBinding); err != nil { if !apierrors.IsNotFound(err) { log.Error(err, "unable to fetch ServiceBinding") @@ -121,12 +121,12 @@ func (r *ServiceBindingReconciler) Reconcile(ctx context.Context, req ctrl.Reque } if utils.IsMarkedForDeletion(serviceBinding.ObjectMeta) { - return r.delete(ctx, serviceBinding, serviceInstance.Spec.BTPAccessCredentialsSecret) + return r.delete(ctx, serviceBinding, serviceInstance) } if len(serviceBinding.Status.OperationURL) > 0 { // ongoing operation - poll status from SM - return r.poll(ctx, serviceBinding, serviceInstance.Spec.BTPAccessCredentialsSecret) + return r.poll(ctx, serviceBinding, serviceInstance) } if !controllerutil.ContainsFinalizer(serviceBinding, common.FinalizerName) { @@ -161,7 +161,7 @@ func (r *ServiceBindingReconciler) Reconcile(ctx context.Context, req ctrl.Reque } if meta.IsStatusConditionTrue(serviceBinding.Status.Conditions, common.ConditionCredRotationInProgress) { - if err := r.rotateCredentials(ctx, serviceBinding, serviceInstance.Spec.BTPAccessCredentialsSecret); err != nil { + if err := r.rotateCredentials(ctx, serviceBinding, serviceInstance); err != nil { return ctrl.Result{}, err } } @@ -204,7 +204,7 @@ func (r *ServiceBindingReconciler) Reconcile(ctx context.Context, req ctrl.Reque return ctrl.Result{}, utils.UpdateStatus(ctx, r.Client, serviceBinding) } - smClient, err := r.GetSMClient(ctx, getBTPAccessSecretNamespace(serviceBinding), serviceInstance.Spec.BTPAccessCredentialsSecret) + smClient, err := r.GetSMClient(ctx, serviceInstance) if err != nil { return utils.MarkAsTransientError(ctx, r.Client, common.Unknown, err, serviceBinding) } @@ -225,9 +225,9 @@ func (r *ServiceBindingReconciler) Reconcile(ctx context.Context, req ctrl.Reque return ctrl.Result{}, nil } -func (r *ServiceBindingReconciler) updateSecret(ctx context.Context, serviceBinding *servicesv1.ServiceBinding, serviceInstance *servicesv1.ServiceInstance, log logr.Logger) error { +func (r *ServiceBindingReconciler) updateSecret(ctx context.Context, serviceBinding *v1.ServiceBinding, serviceInstance *v1.ServiceInstance, log logr.Logger) error { log.Info("Updating secret according to the new template") - smClient, err := r.GetSMClient(ctx, getBTPAccessSecretNamespace(serviceBinding), serviceInstance.Spec.BTPAccessCredentialsSecret) + smClient, err := r.GetSMClient(ctx, serviceInstance) if err != nil { return err } @@ -250,12 +250,12 @@ func (r *ServiceBindingReconciler) updateSecret(ctx context.Context, serviceBind func (r *ServiceBindingReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&servicesv1.ServiceBinding{}). + For(&v1.ServiceBinding{}). WithOptions(controller.Options{RateLimiter: workqueue.NewItemExponentialFailureRateLimiter(r.Config.RetryBaseDelay, r.Config.RetryMaxDelay)}). Complete(r) } -func (r *ServiceBindingReconciler) createBinding(ctx context.Context, smClient sm.Client, serviceInstance *servicesv1.ServiceInstance, serviceBinding *servicesv1.ServiceBinding) (ctrl.Result, error) { +func (r *ServiceBindingReconciler) createBinding(ctx context.Context, smClient sm.Client, serviceInstance *v1.ServiceInstance, serviceBinding *v1.ServiceBinding) (ctrl.Result, error) { log := utils.GetLogger(ctx) log.Info("Creating smBinding in SM") serviceBinding.Status.InstanceID = serviceInstance.Status.InstanceID @@ -319,10 +319,10 @@ func (r *ServiceBindingReconciler) createBinding(ctx context.Context, smClient s return ctrl.Result{}, utils.UpdateStatus(ctx, r.Client, serviceBinding) } -func (r *ServiceBindingReconciler) delete(ctx context.Context, serviceBinding *servicesv1.ServiceBinding, btpAccessCredentialsSecret string) (ctrl.Result, error) { +func (r *ServiceBindingReconciler) delete(ctx context.Context, serviceBinding *v1.ServiceBinding, serviceInstance *v1.ServiceInstance) (ctrl.Result, error) { log := utils.GetLogger(ctx) if controllerutil.ContainsFinalizer(serviceBinding, common.FinalizerName) { - smClient, err := r.GetSMClient(ctx, getBTPAccessSecretNamespace(serviceBinding), btpAccessCredentialsSecret) + smClient, err := r.GetSMClient(ctx, serviceInstance) if err != nil { return utils.MarkAsTransientError(ctx, r.Client, common.Unknown, err, serviceBinding) } @@ -354,7 +354,7 @@ func (r *ServiceBindingReconciler) delete(ctx context.Context, serviceBinding *s if len(serviceBinding.Status.OperationURL) > 0 && serviceBinding.Status.OperationType == smClientTypes.DELETE { // ongoing delete operation - poll status from SM - return r.poll(ctx, serviceBinding, btpAccessCredentialsSecret) + return r.poll(ctx, serviceBinding, serviceInstance) } log.Info(fmt.Sprintf("Deleting binding with id %v from SM", serviceBinding.Status.BindingID)) @@ -381,11 +381,11 @@ func (r *ServiceBindingReconciler) delete(ctx context.Context, serviceBinding *s return ctrl.Result{}, nil } -func (r *ServiceBindingReconciler) poll(ctx context.Context, serviceBinding *servicesv1.ServiceBinding, btpAccessCredentialsSecret string) (ctrl.Result, error) { +func (r *ServiceBindingReconciler) poll(ctx context.Context, serviceBinding *v1.ServiceBinding, serviceInstance *v1.ServiceInstance) (ctrl.Result, error) { log := utils.GetLogger(ctx) log.Info(fmt.Sprintf("resource is in progress, found operation url %s", serviceBinding.Status.OperationURL)) - smClient, err := r.GetSMClient(ctx, getBTPAccessSecretNamespace(serviceBinding), btpAccessCredentialsSecret) + smClient, err := r.GetSMClient(ctx, serviceInstance) if err != nil { return utils.MarkAsTransientError(ctx, r.Client, common.Unknown, err, serviceBinding) } @@ -394,7 +394,7 @@ func (r *ServiceBindingReconciler) poll(ctx context.Context, serviceBinding *ser if statusErr != nil { log.Info(fmt.Sprintf("failed to fetch operation, got error from SM: %s", statusErr.Error()), "operationURL", serviceBinding.Status.OperationURL) utils.SetInProgressConditions(ctx, serviceBinding.Status.OperationType, string(smClientTypes.INPROGRESS), serviceBinding) - freshStatus := servicesv1.ServiceBindingStatus{ + freshStatus := v1.ServiceBindingStatus{ Conditions: serviceBinding.GetConditions(), } if utils.IsMarkedForDeletion(serviceBinding.ObjectMeta) { @@ -466,7 +466,7 @@ func (r *ServiceBindingReconciler) poll(ctx context.Context, serviceBinding *ser return ctrl.Result{}, utils.UpdateStatus(ctx, r.Client, serviceBinding) } -func (r *ServiceBindingReconciler) getBindingForRecovery(ctx context.Context, smClient sm.Client, serviceBinding *servicesv1.ServiceBinding) (*smClientTypes.ServiceBinding, error) { +func (r *ServiceBindingReconciler) getBindingForRecovery(ctx context.Context, smClient sm.Client, serviceBinding *v1.ServiceBinding) (*smClientTypes.ServiceBinding, error) { log := utils.GetLogger(ctx) nameQuery := fmt.Sprintf("name eq '%s'", serviceBinding.Spec.ExternalName) clusterIDQuery := fmt.Sprintf("context/clusterid eq '%s'", r.Config.ClusterID) @@ -493,7 +493,7 @@ func (r *ServiceBindingReconciler) getBindingForRecovery(ctx context.Context, sm return nil, nil } -func (r *ServiceBindingReconciler) maintain(ctx context.Context, binding *servicesv1.ServiceBinding) (ctrl.Result, error) { +func (r *ServiceBindingReconciler) maintain(ctx context.Context, binding *v1.ServiceBinding) (ctrl.Result, error) { log := utils.GetLogger(ctx) shouldUpdateStatus := false if binding.Generation != binding.Status.ObservedGeneration { @@ -536,9 +536,9 @@ func (r *ServiceBindingReconciler) maintain(ctx context.Context, binding *servic return ctrl.Result{}, nil } -func (r *ServiceBindingReconciler) getServiceInstanceForBinding(ctx context.Context, binding *servicesv1.ServiceBinding) (*servicesv1.ServiceInstance, error) { +func (r *ServiceBindingReconciler) getServiceInstanceForBinding(ctx context.Context, binding *v1.ServiceBinding) (*v1.ServiceInstance, error) { log := utils.GetLogger(ctx) - serviceInstance := &servicesv1.ServiceInstance{} + serviceInstance := &v1.ServiceInstance{} namespace := binding.Namespace if len(binding.Spec.ServiceInstanceNamespace) > 0 { namespace = binding.Spec.ServiceInstanceNamespace @@ -551,7 +551,7 @@ func (r *ServiceBindingReconciler) getServiceInstanceForBinding(ctx context.Cont return serviceInstance.DeepCopy(), nil } -func (r *ServiceBindingReconciler) setOwner(ctx context.Context, serviceInstance *servicesv1.ServiceInstance, serviceBinding *servicesv1.ServiceBinding) error { +func (r *ServiceBindingReconciler) setOwner(ctx context.Context, serviceInstance *v1.ServiceInstance, serviceBinding *v1.ServiceBinding) error { log := utils.GetLogger(ctx) log.Info("Binding instance as owner of binding", "bindingName", serviceBinding.Name, "instanceName", serviceInstance.Name) if err := controllerutil.SetControllerReference(serviceInstance, serviceBinding, r.Scheme); err != nil { @@ -565,7 +565,7 @@ func (r *ServiceBindingReconciler) setOwner(ctx context.Context, serviceInstance return nil } -func (r *ServiceBindingReconciler) resyncBindingStatus(ctx context.Context, k8sBinding *servicesv1.ServiceBinding, smBinding *smClientTypes.ServiceBinding) { +func (r *ServiceBindingReconciler) resyncBindingStatus(ctx context.Context, k8sBinding *v1.ServiceBinding, smBinding *smClientTypes.ServiceBinding) { k8sBinding.Status.ObservedGeneration = k8sBinding.Generation k8sBinding.Status.BindingID = smBinding.ID k8sBinding.Status.InstanceID = smBinding.ServiceInstanceID @@ -596,7 +596,7 @@ func (r *ServiceBindingReconciler) resyncBindingStatus(ctx context.Context, k8sB } } -func (r *ServiceBindingReconciler) storeBindingSecret(ctx context.Context, k8sBinding *servicesv1.ServiceBinding, smBinding *smClientTypes.ServiceBinding) error { +func (r *ServiceBindingReconciler) storeBindingSecret(ctx context.Context, k8sBinding *v1.ServiceBinding, smBinding *smClientTypes.ServiceBinding) error { log := utils.GetLogger(ctx) logger := log.WithValues("bindingName", k8sBinding.Name, "secretName", k8sBinding.Spec.SecretName) @@ -625,7 +625,7 @@ func (r *ServiceBindingReconciler) storeBindingSecret(ctx context.Context, k8sBi return r.createOrUpdateBindingSecret(ctx, k8sBinding, secret) } -func (r *ServiceBindingReconciler) createBindingSecret(ctx context.Context, k8sBinding *servicesv1.ServiceBinding, smBinding *smClientTypes.ServiceBinding) (*corev1.Secret, error) { +func (r *ServiceBindingReconciler) createBindingSecret(ctx context.Context, k8sBinding *v1.ServiceBinding, smBinding *smClientTypes.ServiceBinding) (*corev1.Secret, error) { credentialsMap, err := r.getSecretDefaultData(ctx, k8sBinding, smBinding) if err != nil { return nil, err @@ -643,7 +643,7 @@ func (r *ServiceBindingReconciler) createBindingSecret(ctx context.Context, k8sB return secret, nil } -func (r *ServiceBindingReconciler) getSecretDefaultData(ctx context.Context, k8sBinding *servicesv1.ServiceBinding, smBinding *smClientTypes.ServiceBinding) (map[string][]byte, error) { +func (r *ServiceBindingReconciler) getSecretDefaultData(ctx context.Context, k8sBinding *v1.ServiceBinding, smBinding *smClientTypes.ServiceBinding) (map[string][]byte, error) { log := utils.GetLogger(ctx).WithValues("bindingName", k8sBinding.Name, "secretName", k8sBinding.Spec.SecretName) var credentialsMap map[string][]byte @@ -698,7 +698,7 @@ func (r *ServiceBindingReconciler) getSecretDefaultData(ctx context.Context, k8s return credentialsMap, nil } -func (r *ServiceBindingReconciler) createBindingSecretFromSecretTemplate(ctx context.Context, k8sBinding *servicesv1.ServiceBinding, smBinding *smClientTypes.ServiceBinding) (*corev1.Secret, error) { +func (r *ServiceBindingReconciler) createBindingSecretFromSecretTemplate(ctx context.Context, k8sBinding *v1.ServiceBinding, smBinding *smClientTypes.ServiceBinding) (*corev1.Secret, error) { log := utils.GetLogger(ctx) logger := log.WithValues("bindingName", k8sBinding.Name, "secretName", k8sBinding.Spec.SecretName) @@ -744,7 +744,7 @@ func (r *ServiceBindingReconciler) createBindingSecretFromSecretTemplate(ctx con return secret, nil } -func (r *ServiceBindingReconciler) createOrUpdateBindingSecret(ctx context.Context, binding *servicesv1.ServiceBinding, secret *corev1.Secret) error { +func (r *ServiceBindingReconciler) createOrUpdateBindingSecret(ctx context.Context, binding *v1.ServiceBinding, secret *corev1.Secret) error { log := utils.GetLogger(ctx) dbSecret := &corev1.Secret{} create := false @@ -775,7 +775,7 @@ func (r *ServiceBindingReconciler) createOrUpdateBindingSecret(ctx context.Conte return r.Client.Update(ctx, dbSecret) } -func (r *ServiceBindingReconciler) deleteBindingSecret(ctx context.Context, binding *servicesv1.ServiceBinding) error { +func (r *ServiceBindingReconciler) deleteBindingSecret(ctx context.Context, binding *v1.ServiceBinding) error { log := utils.GetLogger(ctx) log.Info("Deleting binding secret") bindingSecret := &corev1.Secret{} @@ -803,7 +803,7 @@ func (r *ServiceBindingReconciler) deleteBindingSecret(ctx context.Context, bind return nil } -func (r *ServiceBindingReconciler) deleteSecretAndRemoveFinalizer(ctx context.Context, serviceBinding *servicesv1.ServiceBinding) (ctrl.Result, error) { +func (r *ServiceBindingReconciler) deleteSecretAndRemoveFinalizer(ctx context.Context, serviceBinding *v1.ServiceBinding) (ctrl.Result, error) { // delete binding secret if exist if err := r.deleteBindingSecret(ctx, serviceBinding); err != nil { return ctrl.Result{}, err @@ -818,7 +818,7 @@ func (r *ServiceBindingReconciler) getSecret(ctx context.Context, namespace stri return secret, err } -func (r *ServiceBindingReconciler) validateSecretNameIsAvailable(ctx context.Context, binding *servicesv1.ServiceBinding) error { +func (r *ServiceBindingReconciler) validateSecretNameIsAvailable(ctx context.Context, binding *v1.ServiceBinding) error { currentSecret, err := r.getSecret(ctx, binding.Namespace, binding.Spec.SecretName) if err != nil { return client.IgnoreNotFound(err) @@ -843,7 +843,7 @@ func (r *ServiceBindingReconciler) validateSecretNameIsAvailable(ctx context.Con return fmt.Errorf(secretNameTakenErrorFormat, binding.Spec.SecretName) } -func (r *ServiceBindingReconciler) handleSecretError(ctx context.Context, op smClientTypes.OperationCategory, err error, binding *servicesv1.ServiceBinding) (ctrl.Result, error) { +func (r *ServiceBindingReconciler) handleSecretError(ctx context.Context, op smClientTypes.OperationCategory, err error, binding *v1.ServiceBinding) (ctrl.Result, error) { log := utils.GetLogger(ctx) log.Error(err, fmt.Sprintf("failed to store secret %s for binding %s", binding.Spec.SecretName, binding.Name)) if apierrors.ReasonForError(err) == metav1.StatusReasonUnknown { @@ -852,7 +852,7 @@ func (r *ServiceBindingReconciler) handleSecretError(ctx context.Context, op smC return utils.MarkAsTransientError(ctx, r.Client, op, err, binding) } -func (r *ServiceBindingReconciler) getInstanceInfo(ctx context.Context, binding *servicesv1.ServiceBinding) (map[string]string, error) { +func (r *ServiceBindingReconciler) getInstanceInfo(ctx context.Context, binding *v1.ServiceBinding) (map[string]string, error) { instance, err := r.getServiceInstanceForBinding(ctx, binding) if err != nil { return nil, err @@ -870,7 +870,7 @@ func (r *ServiceBindingReconciler) getInstanceInfo(ctx context.Context, binding return instanceInfos, nil } -func (r *ServiceBindingReconciler) addInstanceInfo(ctx context.Context, binding *servicesv1.ServiceBinding, credentialsMap map[string][]byte) ([]utils.SecretMetadataProperty, error) { +func (r *ServiceBindingReconciler) addInstanceInfo(ctx context.Context, binding *v1.ServiceBinding, credentialsMap map[string][]byte) ([]utils.SecretMetadataProperty, error) { instance, err := r.getServiceInstanceForBinding(ctx, binding) if err != nil { return nil, err @@ -918,7 +918,7 @@ func (r *ServiceBindingReconciler) addInstanceInfo(ctx context.Context, binding return metadata, nil } -func (r *ServiceBindingReconciler) rotateCredentials(ctx context.Context, binding *servicesv1.ServiceBinding, btpAccessCredentialsSecret string) error { +func (r *ServiceBindingReconciler) rotateCredentials(ctx context.Context, binding *v1.ServiceBinding, serviceInstance *v1.ServiceInstance) error { suffix := "-" + utils.RandStringRunes(6) log := utils.GetLogger(ctx) if binding.Annotations != nil { @@ -952,14 +952,14 @@ func (r *ServiceBindingReconciler) rotateCredentials(ctx context.Context, bindin return r.stopRotation(ctx, binding) } - bindings := &servicesv1.ServiceBindingList{} + bindings := &v1.ServiceBindingList{} err := r.Client.List(ctx, bindings, client.MatchingLabels{common.StaleBindingIDLabel: binding.Status.BindingID}, client.InNamespace(binding.Namespace)) if err != nil { return err } if len(bindings.Items) == 0 { - smClient, err := r.GetSMClient(ctx, getBTPAccessSecretNamespace(binding), btpAccessCredentialsSecret) + smClient, err := r.GetSMClient(ctx, serviceInstance) if err != nil { return err } @@ -994,14 +994,14 @@ func (r *ServiceBindingReconciler) rotateCredentials(ctx context.Context, bindin return utils.UpdateStatus(ctx, r.Client, binding) } -func (r *ServiceBindingReconciler) stopRotation(ctx context.Context, binding *servicesv1.ServiceBinding) error { +func (r *ServiceBindingReconciler) stopRotation(ctx context.Context, binding *v1.ServiceBinding) error { conditions := binding.GetConditions() meta.RemoveStatusCondition(&conditions, common.ConditionCredRotationInProgress) binding.Status.Conditions = conditions return utils.UpdateStatus(ctx, r.Client, binding) } -func (r *ServiceBindingReconciler) createOldBinding(ctx context.Context, suffix string, binding *servicesv1.ServiceBinding) error { +func (r *ServiceBindingReconciler) createOldBinding(ctx context.Context, suffix string, binding *v1.ServiceBinding) error { oldBinding := newBindingObject(binding.Name+suffix, binding.Namespace) err := controllerutil.SetControllerReference(binding, oldBinding, r.Scheme) if err != nil { @@ -1019,7 +1019,7 @@ func (r *ServiceBindingReconciler) createOldBinding(ctx context.Context, suffix return r.Client.Create(ctx, oldBinding) } -func (r *ServiceBindingReconciler) handleStaleServiceBinding(ctx context.Context, serviceBinding *servicesv1.ServiceBinding) (ctrl.Result, error) { +func (r *ServiceBindingReconciler) handleStaleServiceBinding(ctx context.Context, serviceBinding *v1.ServiceBinding) (ctrl.Result, error) { log := utils.GetLogger(ctx) originalBindingName, ok := serviceBinding.Labels[common.StaleBindingRotationOfLabel] if !ok { @@ -1027,7 +1027,7 @@ func (r *ServiceBindingReconciler) handleStaleServiceBinding(ctx context.Context log.Info("missing rotationOf label, unable to fetch original binding, deleting stale") return ctrl.Result{}, r.Client.Delete(ctx, serviceBinding) } - origBinding := &servicesv1.ServiceBinding{} + origBinding := &v1.ServiceBinding{} if err := r.Client.Get(ctx, types.NamespacedName{Namespace: serviceBinding.Namespace, Name: originalBindingName}, origBinding); err != nil { if apierrors.IsNotFound(err) { log.Info("original binding not found, deleting stale binding") @@ -1054,7 +1054,7 @@ func (r *ServiceBindingReconciler) handleStaleServiceBinding(ctx context.Context return ctrl.Result{}, nil } -func (r *ServiceBindingReconciler) recover(ctx context.Context, serviceBinding *servicesv1.ServiceBinding, smBinding *smClientTypes.ServiceBinding) (ctrl.Result, error) { +func (r *ServiceBindingReconciler) recover(ctx context.Context, serviceBinding *v1.ServiceBinding, smBinding *smClientTypes.ServiceBinding) (ctrl.Result, error) { log := utils.GetLogger(ctx) log.Info(fmt.Sprintf("found existing smBinding in SM with id %s, updating status", smBinding.ID)) @@ -1072,7 +1072,7 @@ func (r *ServiceBindingReconciler) recover(ctx context.Context, serviceBinding * return ctrl.Result{}, utils.UpdateStatus(ctx, r.Client, serviceBinding) } -func isStaleServiceBinding(binding *servicesv1.ServiceBinding) bool { +func isStaleServiceBinding(binding *v1.ServiceBinding) bool { if utils.IsMarkedForDeletion(binding.ObjectMeta) { return false } @@ -1090,7 +1090,7 @@ func isStaleServiceBinding(binding *servicesv1.ServiceBinding) bool { return false } -func initCredRotationIfRequired(binding *servicesv1.ServiceBinding) bool { +func initCredRotationIfRequired(binding *v1.ServiceBinding) bool { if utils.IsFailed(binding) || !credRotationEnabled(binding) || meta.IsStatusConditionTrue(binding.Status.Conditions, common.ConditionCredRotationInProgress) { return false } @@ -1111,7 +1111,7 @@ func initCredRotationIfRequired(binding *servicesv1.ServiceBinding) bool { return false } -func credRotationEnabled(binding *servicesv1.ServiceBinding) bool { +func credRotationEnabled(binding *v1.ServiceBinding) bool { return binding.Spec.CredRotationPolicy != nil && binding.Spec.CredRotationPolicy.Enabled } @@ -1126,10 +1126,10 @@ func mergeInstanceTags(offeringTags, customTags []string) []string { return tags } -func newBindingObject(name, namespace string) *servicesv1.ServiceBinding { - return &servicesv1.ServiceBinding{ +func newBindingObject(name, namespace string) *v1.ServiceBinding { + return &v1.ServiceBinding{ TypeMeta: metav1.TypeMeta{ - APIVersion: servicesv1.GroupVersion.String(), + APIVersion: v1.GroupVersion.String(), Kind: "ServiceBinding", }, ObjectMeta: metav1.ObjectMeta{ @@ -1139,7 +1139,7 @@ func newBindingObject(name, namespace string) *servicesv1.ServiceBinding { } } -func bindingAlreadyOwnedByInstance(instance *servicesv1.ServiceInstance, binding *servicesv1.ServiceBinding) bool { +func bindingAlreadyOwnedByInstance(instance *v1.ServiceInstance, binding *v1.ServiceBinding) bool { if existing := metav1.GetControllerOf(binding); existing != nil { aGV, err := schema.ParseGroupVersion(existing.APIVersion) if err != nil { @@ -1156,7 +1156,7 @@ func bindingAlreadyOwnedByInstance(instance *servicesv1.ServiceInstance, binding return false } -func serviceNotUsable(instance *servicesv1.ServiceInstance) bool { +func serviceNotUsable(instance *v1.ServiceInstance) bool { if utils.IsMarkedForDeletion(instance.ObjectMeta) { return true } @@ -1166,7 +1166,7 @@ func serviceNotUsable(instance *servicesv1.ServiceInstance) bool { return false } -func getInstanceNameForSecretCredentials(instance *servicesv1.ServiceInstance) []byte { +func getInstanceNameForSecretCredentials(instance *v1.ServiceInstance) []byte { if useMetaName, ok := instance.Annotations[common.UseInstanceMetadataNameInSecret]; ok && useMetaName == "true" { return []byte(instance.Name) } @@ -1188,11 +1188,3 @@ func singleKeyMap(credentialsMap map[string][]byte, key string) (map[string][]by key: credBytes, }, nil } - -func getBTPAccessSecretNamespace(serviceBinding *servicesv1.ServiceBinding) string { - btpAccessSecretNamespace := serviceBinding.Namespace - if len(serviceBinding.Spec.ServiceInstanceNamespace) > 0 { - btpAccessSecretNamespace = serviceBinding.Spec.ServiceInstanceNamespace - } - return btpAccessSecretNamespace -} diff --git a/controllers/serviceinstance_controller.go b/controllers/serviceinstance_controller.go index f4a0ec04..c5cea1b6 100644 --- a/controllers/serviceinstance_controller.go +++ b/controllers/serviceinstance_controller.go @@ -36,7 +36,7 @@ import ( "k8s.io/client-go/util/workqueue" "sigs.k8s.io/controller-runtime/pkg/controller" - servicesv1 "github.com/SAP/sap-btp-service-operator/api/v1" + v1 "github.com/SAP/sap-btp-service-operator/api/v1" "k8s.io/apimachinery/pkg/api/meta" "github.com/google/uuid" @@ -55,7 +55,7 @@ type ServiceInstanceReconciler struct { client.Client Log logr.Logger Scheme *runtime.Scheme - GetSMClient func(ctx context.Context, resourceNamespace, btpAccessSecretName string) (sm.Client, error) + GetSMClient func(ctx context.Context, serviceInstance *v1.ServiceInstance) (sm.Client, error) Config config.Config Recorder record.EventRecorder } @@ -69,7 +69,7 @@ func (r *ServiceInstanceReconciler) Reconcile(ctx context.Context, req ctrl.Requ log := r.Log.WithValues("serviceinstance", req.NamespacedName).WithValues("correlation_id", uuid.New().String()) ctx = context.WithValue(ctx, utils.LogKey{}, log) - serviceInstance := &servicesv1.ServiceInstance{} + serviceInstance := &v1.ServiceInstance{} if err := r.Client.Get(ctx, req.NamespacedName, serviceInstance); err != nil { if !apierrors.IsNotFound(err) { log.Error(err, "unable to fetch ServiceInstance") @@ -122,7 +122,7 @@ func (r *ServiceInstanceReconciler) Reconcile(ctx context.Context, req ctrl.Requ log.Info(fmt.Sprintf("instance is not in final state, handling... (generation: %d, observedGen: %d", serviceInstance.Generation, serviceInstance.Status.ObservedGeneration)) serviceInstance.SetObservedGeneration(serviceInstance.Generation) - smClient, err := r.GetSMClient(ctx, serviceInstance.Namespace, serviceInstance.Spec.BTPAccessCredentialsSecret) + smClient, err := r.GetSMClient(ctx, serviceInstance) if err != nil { log.Error(err, "failed to get sm client") return utils.MarkAsTransientError(ctx, r.Client, common.Unknown, err, serviceInstance) @@ -163,12 +163,12 @@ func (r *ServiceInstanceReconciler) Reconcile(ctx context.Context, req ctrl.Requ func (r *ServiceInstanceReconciler) SetupWithManager(mgr ctrl.Manager) error { return ctrl.NewControllerManagedBy(mgr). - For(&servicesv1.ServiceInstance{}). + For(&v1.ServiceInstance{}). WithOptions(controller.Options{RateLimiter: workqueue.NewItemExponentialFailureRateLimiter(r.Config.RetryBaseDelay, r.Config.RetryMaxDelay)}). Complete(r) } -func (r *ServiceInstanceReconciler) createInstance(ctx context.Context, smClient sm.Client, serviceInstance *servicesv1.ServiceInstance) (ctrl.Result, error) { +func (r *ServiceInstanceReconciler) createInstance(ctx context.Context, smClient sm.Client, serviceInstance *v1.ServiceInstance) (ctrl.Result, error) { log := utils.GetLogger(ctx) log.Info("Creating instance in SM") updateHashedSpecValue(serviceInstance) @@ -222,7 +222,7 @@ func (r *ServiceInstanceReconciler) createInstance(ctx context.Context, smClient return ctrl.Result{}, utils.UpdateStatus(ctx, r.Client, serviceInstance) } -func (r *ServiceInstanceReconciler) updateInstance(ctx context.Context, smClient sm.Client, serviceInstance *servicesv1.ServiceInstance) (ctrl.Result, error) { +func (r *ServiceInstanceReconciler) updateInstance(ctx context.Context, smClient sm.Client, serviceInstance *v1.ServiceInstance) (ctrl.Result, error) { log := utils.GetLogger(ctx) log.Info(fmt.Sprintf("updating instance %s in SM", serviceInstance.Status.InstanceID)) @@ -262,11 +262,11 @@ func (r *ServiceInstanceReconciler) updateInstance(ctx context.Context, smClient return ctrl.Result{}, utils.UpdateStatus(ctx, r.Client, serviceInstance) } -func (r *ServiceInstanceReconciler) deleteInstance(ctx context.Context, serviceInstance *servicesv1.ServiceInstance) (ctrl.Result, error) { +func (r *ServiceInstanceReconciler) deleteInstance(ctx context.Context, serviceInstance *v1.ServiceInstance) (ctrl.Result, error) { log := utils.GetLogger(ctx) if controllerutil.ContainsFinalizer(serviceInstance, common.FinalizerName) { - smClient, err := r.GetSMClient(ctx, serviceInstance.Namespace, serviceInstance.Spec.BTPAccessCredentialsSecret) + smClient, err := r.GetSMClient(ctx, serviceInstance) if err != nil { log.Error(err, "failed to get sm client") return utils.MarkAsTransientError(ctx, r.Client, common.Unknown, err, serviceInstance) @@ -311,7 +311,7 @@ func (r *ServiceInstanceReconciler) deleteInstance(ctx context.Context, serviceI return ctrl.Result{}, nil } -func (r *ServiceInstanceReconciler) handleInstanceSharing(ctx context.Context, serviceInstance *servicesv1.ServiceInstance, smClient sm.Client) (ctrl.Result, error) { +func (r *ServiceInstanceReconciler) handleInstanceSharing(ctx context.Context, serviceInstance *v1.ServiceInstance, smClient sm.Client) (ctrl.Result, error) { log := utils.GetLogger(ctx) log.Info("Handling change in instance sharing") @@ -345,10 +345,10 @@ func (r *ServiceInstanceReconciler) handleInstanceSharing(ctx context.Context, s return ctrl.Result{}, utils.UpdateStatus(ctx, r.Client, serviceInstance) } -func (r *ServiceInstanceReconciler) poll(ctx context.Context, serviceInstance *servicesv1.ServiceInstance) (ctrl.Result, error) { +func (r *ServiceInstanceReconciler) poll(ctx context.Context, serviceInstance *v1.ServiceInstance) (ctrl.Result, error) { log := utils.GetLogger(ctx) log.Info(fmt.Sprintf("resource is in progress, found operation url %s", serviceInstance.Status.OperationURL)) - smClient, err := r.GetSMClient(ctx, serviceInstance.Namespace, serviceInstance.Spec.BTPAccessCredentialsSecret) + smClient, err := r.GetSMClient(ctx, serviceInstance) if err != nil { log.Error(err, "failed to get sm client") return utils.MarkAsTransientError(ctx, r.Client, common.Unknown, err, serviceInstance) @@ -359,7 +359,7 @@ func (r *ServiceInstanceReconciler) poll(ctx context.Context, serviceInstance *s log.Info(fmt.Sprintf("failed to fetch operation, got error from SM: %s", statusErr.Error()), "operationURL", serviceInstance.Status.OperationURL) utils.SetInProgressConditions(ctx, serviceInstance.Status.OperationType, string(smClientTypes.INPROGRESS), serviceInstance) // if failed to read operation status we cleanup the status to trigger re-sync from SM - freshStatus := servicesv1.ServiceInstanceStatus{Conditions: serviceInstance.GetConditions(), ObservedGeneration: serviceInstance.Generation} + freshStatus := v1.ServiceInstanceStatus{Conditions: serviceInstance.GetConditions(), ObservedGeneration: serviceInstance.Generation} if utils.IsMarkedForDeletion(serviceInstance.ObjectMeta) { freshStatus.InstanceID = serviceInstance.Status.InstanceID } @@ -425,7 +425,7 @@ func (r *ServiceInstanceReconciler) poll(ctx context.Context, serviceInstance *s return ctrl.Result{}, utils.UpdateStatus(ctx, r.Client, serviceInstance) } -func (r *ServiceInstanceReconciler) handleAsyncDelete(ctx context.Context, serviceInstance *servicesv1.ServiceInstance, opURL string) (ctrl.Result, error) { +func (r *ServiceInstanceReconciler) handleAsyncDelete(ctx context.Context, serviceInstance *v1.ServiceInstance, opURL string) (ctrl.Result, error) { serviceInstance.Status.OperationURL = opURL serviceInstance.Status.OperationType = smClientTypes.DELETE utils.SetInProgressConditions(ctx, smClientTypes.DELETE, "", serviceInstance) @@ -437,7 +437,7 @@ func (r *ServiceInstanceReconciler) handleAsyncDelete(ctx context.Context, servi return ctrl.Result{Requeue: true, RequeueAfter: r.Config.PollInterval}, nil } -func (r *ServiceInstanceReconciler) getInstanceForRecovery(ctx context.Context, smClient sm.Client, serviceInstance *servicesv1.ServiceInstance) (*smClientTypes.ServiceInstance, error) { +func (r *ServiceInstanceReconciler) getInstanceForRecovery(ctx context.Context, smClient sm.Client, serviceInstance *v1.ServiceInstance) (*smClientTypes.ServiceInstance, error) { log := utils.GetLogger(ctx) parameters := sm.Parameters{ FieldQuery: []string{ @@ -462,7 +462,7 @@ func (r *ServiceInstanceReconciler) getInstanceForRecovery(ctx context.Context, return nil, nil } -func (r *ServiceInstanceReconciler) recover(ctx context.Context, smClient sm.Client, k8sInstance *servicesv1.ServiceInstance, smInstance *smClientTypes.ServiceInstance) (ctrl.Result, error) { +func (r *ServiceInstanceReconciler) recover(ctx context.Context, smClient sm.Client, k8sInstance *v1.ServiceInstance, smInstance *smClientTypes.ServiceInstance) (ctrl.Result, error) { log := utils.GetLogger(ctx) log.Info(fmt.Sprintf("found existing instance in SM with id %s, updating status", smInstance.ID)) @@ -546,7 +546,7 @@ func (r *ServiceInstanceReconciler) handleInstanceSharingError(ctx context.Conte return ctrl.Result{Requeue: isTransient}, utils.UpdateStatus(ctx, r.Client, object) } -func isFinalState(ctx context.Context, serviceInstance *servicesv1.ServiceInstance) bool { +func isFinalState(ctx context.Context, serviceInstance *v1.ServiceInstance) bool { log := utils.GetLogger(ctx) if utils.IsMarkedForDeletion(serviceInstance.ObjectMeta) { log.Info("instance is not in final state, it is marked for deletion") @@ -579,7 +579,7 @@ func isFinalState(ctx context.Context, serviceInstance *servicesv1.ServiceInstan return true } -func updateRequired(serviceInstance *servicesv1.ServiceInstance) bool { +func updateRequired(serviceInstance *v1.ServiceInstance) bool { //update is not supported for failed instances (this can occur when instance creation was asynchronously) if serviceInstance.Status.Ready != metav1.ConditionTrue { return false @@ -593,7 +593,7 @@ func updateRequired(serviceInstance *servicesv1.ServiceInstance) bool { return getSpecHash(serviceInstance) != serviceInstance.Status.HashedSpec } -func sharingUpdateRequired(serviceInstance *servicesv1.ServiceInstance) bool { +func sharingUpdateRequired(serviceInstance *v1.ServiceInstance) bool { //relevant only for non-shared instances - sharing instance is possible only for usable instances if serviceInstance.Status.Ready != metav1.ConditionTrue { return false @@ -661,7 +661,7 @@ func getTags(tags []byte) ([]string, error) { return tagsArr, nil } -func getSpecHash(serviceInstance *servicesv1.ServiceInstance) string { +func getSpecHash(serviceInstance *v1.ServiceInstance) string { spec := serviceInstance.Spec spec.Shared = ptr.To(false) specBytes, _ := json.Marshal(spec) @@ -699,7 +699,7 @@ func setSharedCondition(object common.SAPBTPResource, status metav1.ConditionSta object.SetConditions(conditions) } -func updateHashedSpecValue(serviceInstance *servicesv1.ServiceInstance) { +func updateHashedSpecValue(serviceInstance *v1.ServiceInstance) { serviceInstance.Status.HashedSpec = getSpecHash(serviceInstance) } diff --git a/controllers/suite_test.go b/controllers/suite_test.go index d15579e5..211eaaad 100644 --- a/controllers/suite_test.go +++ b/controllers/suite_test.go @@ -158,7 +158,7 @@ var _ = BeforeSuite(func(done Done) { Client: k8sManager.GetClient(), Scheme: k8sManager.GetScheme(), Log: ctrl.Log.WithName("controllers").WithName("ServiceInstance"), - GetSMClient: func(_ context.Context, _, _ string) (sm.Client, error) { + GetSMClient: func(_ context.Context, _ *v1.ServiceInstance) (sm.Client, error) { return fakeClient, nil }, Config: testConfig, @@ -170,7 +170,7 @@ var _ = BeforeSuite(func(done Done) { Client: k8sManager.GetClient(), Scheme: k8sManager.GetScheme(), Log: ctrl.Log.WithName("controllers").WithName("ServiceBinding"), - GetSMClient: func(_ context.Context, _, _ string) (sm.Client, error) { + GetSMClient: func(_ context.Context, _ *v1.ServiceInstance) (sm.Client, error) { return fakeClient, nil }, Config: testConfig, diff --git a/internal/utils/secret_resolver.go b/internal/utils/secret_resolver.go index 361dd1c2..5e8f582c 100644 --- a/internal/utils/secret_resolver.go +++ b/internal/utils/secret_resolver.go @@ -88,8 +88,8 @@ func (sr *secretClient) getSecretForResource(ctx context.Context, namespace, nam } // secret not found in resource namespace, search for namespace-specific secret in management namespace - sr.Log.Info(fmt.Sprintf("Searching a secret for namespace %s in the management namespace %s", namespace, sr.ManagementNamespace)) - err := sr.getWithClientFallback(ctx, types.NamespacedName{Namespace: sr.ManagementNamespace, Name: fmt.Sprintf("%s-%s", namespace, name)}, secretForResource) + var err error + secretForResource, err = secretsClient.getSecretFromManagementNamespace(ctx, fmt.Sprintf("%s-%s", namespace, name)) if err == nil { return secretForResource, nil } @@ -100,10 +100,10 @@ func (sr *secretClient) getSecretForResource(ctx context.Context, namespace, nam } // namespace-specific secret not found in management namespace, fallback to central cluster secret - return sr.getDefaultSecret(ctx, name) + return sr.getClusterDefaultSecret(ctx, name) } -func (sr *secretClient) getDefaultSecret(ctx context.Context, name string) (*v1.Secret, error) { +func (sr *secretClient) getClusterDefaultSecret(ctx context.Context, name string) (*v1.Secret, error) { secretForResource := &v1.Secret{} sr.Log.Info(fmt.Sprintf("Searching for cluster secret %s in releaseNamespace %s", name, sr.ReleaseNamespace)) err := sr.getWithClientFallback(ctx, types.NamespacedName{Namespace: sr.ReleaseNamespace, Name: name}, secretForResource) diff --git a/internal/utils/sm_utils.go b/internal/utils/sm_utils.go index cb0855d2..9d30597d 100644 --- a/internal/utils/sm_utils.go +++ b/internal/utils/sm_utils.go @@ -4,21 +4,35 @@ import ( "context" "fmt" + v1 "github.com/SAP/sap-btp-service-operator/api/v1" "github.com/SAP/sap-btp-service-operator/client/sm" - v1 "k8s.io/api/core/v1" + corev1 "k8s.io/api/core/v1" "sigs.k8s.io/controller-runtime/pkg/client" ) -func GetSMClient(ctx context.Context, resourceNamespace, btpAccessSecretName string) (sm.Client, error) { - log := GetLogger(ctx) +type InvalidCredentialsError struct{} - if len(btpAccessSecretName) > 0 { - return getBTPAccessClient(ctx, btpAccessSecretName) - } +func (ic *InvalidCredentialsError) Error() string { + return "invalid Service-Manager credentials, contact your cluster administrator" +} + +func GetSMClient(ctx context.Context, serviceInstance *v1.ServiceInstance) (sm.Client, error) { + log := GetLogger(ctx) + var err error - secret, err := GetSecretForResource(ctx, resourceNamespace, SAPBTPOperatorSecretName) - if err != nil { - return nil, err + var secret *corev1.Secret + if len(serviceInstance.Spec.BTPAccessCredentialsSecret) > 0 { + secret, err = GetSecretFromManagementNamespace(ctx, serviceInstance.Spec.BTPAccessCredentialsSecret) + if err != nil { + log.Error(err, "failed to get secret BTPAccessCredentialsSecret") + return nil, err + } + } else { + secret, err = GetSecretForResource(ctx, serviceInstance.Namespace, SAPBTPOperatorSecretName) + if err != nil { + log.Error(err, "failed to get secret for instance") + return nil, err + } } clientConfig := &sm.ClientConfig{ @@ -27,8 +41,8 @@ func GetSMClient(ctx context.Context, resourceNamespace, btpAccessSecretName str URL: string(secret.Data["sm_url"]), TokenURL: string(secret.Data["tokenurl"]), TokenURLSuffix: string(secret.Data["tokenurlsuffix"]), - TLSPrivateKey: string(secret.Data[v1.TLSPrivateKeyKey]), - TLSCertKey: string(secret.Data[v1.TLSCertKey]), + TLSPrivateKey: string(secret.Data[corev1.TLSPrivateKeyKey]), + TLSCertKey: string(secret.Data[corev1.TLSCertKey]), SSLDisabled: false, } @@ -39,45 +53,24 @@ func GetSMClient(ctx context.Context, resourceNamespace, btpAccessSecretName str //backward compatibility (tls data in a dedicated secret) if len(clientConfig.ClientSecret) == 0 && (len(clientConfig.TLSPrivateKey) == 0 || len(clientConfig.TLSCertKey) == 0) { - tlsSecret, err := GetSecretForResource(ctx, resourceNamespace, SAPBTPOperatorTLSSecretName) + if len(serviceInstance.Spec.BTPAccessCredentialsSecret) > 0 && !clientConfig.IsValid() { + log.Info("btpAccess secret found but did not contain all the required data") + return nil, fmt.Errorf("invalid Service-Manager credentials, contact your cluster administrator") + } + + tlsSecret, err := GetSecretForResource(ctx, serviceInstance.Namespace, SAPBTPOperatorTLSSecretName) if client.IgnoreNotFound(err) != nil { return nil, err } - if tlsSecret == nil || len(tlsSecret.Data) == 0 || len(tlsSecret.Data[v1.TLSCertKey]) == 0 || len(tlsSecret.Data[v1.TLSPrivateKeyKey]) == 0 { + if tlsSecret == nil || len(tlsSecret.Data) == 0 || len(tlsSecret.Data[corev1.TLSCertKey]) == 0 || len(tlsSecret.Data[corev1.TLSPrivateKeyKey]) == 0 { log.Info("clientsecret not found in SM credentials, and tls secret is invalid") - return nil, fmt.Errorf("invalid Service-Manager credentials, contact your cluster administrator") + return nil, &InvalidCredentialsError{} } log.Info("found tls configuration") - clientConfig.TLSCertKey = string(tlsSecret.Data[v1.TLSCertKey]) - clientConfig.TLSPrivateKey = string(tlsSecret.Data[v1.TLSPrivateKeyKey]) - } - - return sm.NewClient(ctx, clientConfig, nil) -} - -func getBTPAccessClient(ctx context.Context, secretName string) (sm.Client, error) { - log := GetLogger(ctx) - secret, err := GetSecretFromManagementNamespace(ctx, secretName) - if err != nil { - return nil, err - } - - clientConfig := &sm.ClientConfig{ - ClientID: string(secret.Data["clientid"]), - ClientSecret: string(secret.Data["clientsecret"]), - URL: string(secret.Data["sm_url"]), - TokenURL: string(secret.Data["tokenurl"]), - TokenURLSuffix: string(secret.Data["tokenurlsuffix"]), - TLSPrivateKey: string(secret.Data[v1.TLSPrivateKeyKey]), - TLSCertKey: string(secret.Data[v1.TLSCertKey]), - SSLDisabled: false, - } - - if !clientConfig.IsValid() { - log.Info("btpAccess secret found but did not contain all the required data") - return nil, fmt.Errorf("invalid Service-Manager credentials, contact your cluster administrator") + clientConfig.TLSCertKey = string(tlsSecret.Data[corev1.TLSCertKey]) + clientConfig.TLSPrivateKey = string(tlsSecret.Data[corev1.TLSPrivateKeyKey]) } return sm.NewClient(ctx, clientConfig, nil) diff --git a/internal/utils/sm_utils_test.go b/internal/utils/sm_utils_test.go index 754dcb3d..1444c488 100644 --- a/internal/utils/sm_utils_test.go +++ b/internal/utils/sm_utils_test.go @@ -1,6 +1,7 @@ package utils import ( + v1 "github.com/SAP/sap-btp-service-operator/api/v1" "github.com/SAP/sap-btp-service-operator/internal/config" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" @@ -11,8 +12,9 @@ import ( var _ = Describe("SM Utils", func() { var ( - secret *corev1.Secret - tlsSecret *corev1.Secret + secret *corev1.Secret + tlsSecret *corev1.Secret + serviceInstance *v1.ServiceInstance ) BeforeEach(func() { @@ -20,6 +22,21 @@ var _ = Describe("SM Utils", func() { ManagementNamespace: managementNamespace, ReleaseNamespace: managementNamespace, }) + serviceInstance = &v1.ServiceInstance{Spec: v1.ServiceInstanceSpec{}, Status: v1.ServiceInstanceStatus{}} + serviceInstance.Name = "test-instance" + serviceInstance.Namespace = testNamespace + serviceInstance.Spec = v1.ServiceInstanceSpec{ + ServiceOfferingName: "test", + ServicePlanName: "test", + } + Expect(k8sClient.Create(ctx, serviceInstance)).To(Succeed()) + Expect(InitConditions(ctx, k8sClient, serviceInstance)).To(Succeed()) + }) + + AfterEach(func() { + if serviceInstance != nil { + Expect(client.IgnoreNotFound(k8sClient.Delete(ctx, serviceInstance))).To(Succeed()) + } }) Context("GetSMClient", func() { @@ -55,7 +72,7 @@ var _ = Describe("SM Utils", func() { Expect(k8sClient.Create(ctx, secret)).To(Succeed()) }) It("should succeed", func() { - client, err := GetSMClient(ctx, testNamespace, "") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).ToNot(HaveOccurred()) Expect(client).ToNot(BeNil()) }) @@ -79,7 +96,7 @@ var _ = Describe("SM Utils", func() { Expect(k8sClient.Create(ctx, secret)).To(Succeed()) }) It("should succeed", func() { - client, err := GetSMClient(ctx, testNamespace, "") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).ToNot(HaveOccurred()) Expect(client).ToNot(BeNil()) }) @@ -102,7 +119,7 @@ var _ = Describe("SM Utils", func() { Expect(k8sClient.Create(ctx, secret)).To(Succeed()) }) It("should return error", func() { - client, err := GetSMClient(ctx, testNamespace, "") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("invalid Service-Manager credentials, contact your cluster administrator")) Expect(client).To(BeNil()) @@ -125,7 +142,7 @@ var _ = Describe("SM Utils", func() { Expect(k8sClient.Create(ctx, secret)).To(Succeed()) }) It("should return error", func() { - client, err := GetSMClient(ctx, testNamespace, "") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("invalid Service-Manager credentials, contact your cluster administrator")) Expect(client).To(BeNil()) @@ -147,7 +164,7 @@ var _ = Describe("SM Utils", func() { Expect(k8sClient.Create(ctx, secret)).To(Succeed()) }) It("should return error", func() { - client, err := GetSMClient(ctx, testNamespace, "") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("invalid Service-Manager credentials, contact your cluster administrator")) Expect(client).To(BeNil()) @@ -185,14 +202,14 @@ var _ = Describe("SM Utils", func() { Expect(k8sClient.Create(ctx, tlsSecret)).To(Succeed()) }) It("should succeed", func() { - client, err := GetSMClient(ctx, testNamespace, "") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).ToNot(HaveOccurred()) //tls: failed to find any PEM data in key input Expect(client).ToNot(BeNil()) }) }) When("tls secret not found", func() { It("should return error", func() { - client, err := GetSMClient(ctx, testNamespace, "") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("invalid Service-Manager credentials, contact your cluster administrator")) Expect(client).To(BeNil()) @@ -212,7 +229,7 @@ var _ = Describe("SM Utils", func() { Expect(k8sClient.Create(ctx, tlsSecret)).To(Succeed()) }) It("should return error", func() { - client, err := GetSMClient(ctx, testNamespace, "") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("invalid Service-Manager credentials, contact your cluster administrator")) Expect(client).To(BeNil()) @@ -221,6 +238,12 @@ var _ = Describe("SM Utils", func() { }) Context("btpAccessSecret", func() { + BeforeEach(func() { + serviceInstance.Spec.BTPAccessCredentialsSecret = "my-btp-access-secret" + }) + AfterEach(func() { + serviceInstance.Spec.BTPAccessCredentialsSecret = "" + }) Context("client credentials", func() { When("secret is valid", func() { BeforeEach(func() { @@ -237,9 +260,14 @@ var _ = Describe("SM Utils", func() { }, } Expect(k8sClient.Create(ctx, secret)).To(Succeed()) + serviceInstance.Spec.BTPAccessCredentialsSecret = "my-btp-access-secret" + }) + AfterEach(func() { + serviceInstance.Spec.BTPAccessCredentialsSecret = "" }) + It("should succeed", func() { - client, err := GetSMClient(ctx, testNamespace, "my-btp-access-secret") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).ToNot(HaveOccurred()) Expect(client).ToNot(BeNil()) }) @@ -262,7 +290,7 @@ var _ = Describe("SM Utils", func() { Expect(k8sClient.Create(ctx, secret)).To(Succeed()) }) It("should return error", func() { - client, err := GetSMClient(ctx, testNamespace, "my-btp-access-secret") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("invalid Service-Manager credentials, contact your cluster administrator")) Expect(client).To(BeNil()) @@ -285,7 +313,7 @@ var _ = Describe("SM Utils", func() { Expect(k8sClient.Create(ctx, secret)).To(Succeed()) }) It("should return error", func() { - client, err := GetSMClient(ctx, testNamespace, "my-btp-access-secret") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("invalid Service-Manager credentials, contact your cluster administrator")) Expect(client).To(BeNil()) @@ -307,7 +335,7 @@ var _ = Describe("SM Utils", func() { Expect(k8sClient.Create(ctx, secret)).To(Succeed()) }) It("should return error", func() { - client, err := GetSMClient(ctx, testNamespace, "my-btp-access-secret") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("invalid Service-Manager credentials, contact your cluster administrator")) Expect(client).To(BeNil()) @@ -334,7 +362,7 @@ var _ = Describe("SM Utils", func() { Expect(k8sClient.Create(ctx, secret)).To(Succeed()) }) It("should succeed", func() { - client, err := GetSMClient(ctx, testNamespace, "my-btp-access-secret") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).ToNot(HaveOccurred()) Expect(client).ToNot(BeNil()) }) @@ -354,7 +382,7 @@ var _ = Describe("SM Utils", func() { Expect(k8sClient.Create(ctx, tlsSecret)).To(Succeed()) }) It("should return error", func() { - client, err := GetSMClient(ctx, testNamespace, "my-btp-access-secret") + client, err := GetSMClient(ctx, serviceInstance) Expect(err).To(HaveOccurred()) Expect(err.Error()).To(ContainSubstring("invalid Service-Manager credentials, contact your cluster administrator")) Expect(client).To(BeNil()) diff --git a/internal/utils/suite_test.go b/internal/utils/suite_test.go index 0311c3d8..76ecd8ae 100644 --- a/internal/utils/suite_test.go +++ b/internal/utils/suite_test.go @@ -50,6 +50,7 @@ const ( timeout = time.Second * 10 interval = time.Millisecond * 250 managementNamespace = "test-management-namespace" + releaseNamespace = "test-release-namespace" testNamespace = "test-namespace" ) diff --git a/sapbtp-operator-charts/templates/crd.yml b/sapbtp-operator-charts/templates/crd.yml index ed16902e..551cbd69 100644 --- a/sapbtp-operator-charts/templates/crd.yml +++ b/sapbtp-operator-charts/templates/crd.yml @@ -2,8 +2,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.9.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.15.0 name: servicebindings.services.cloud.sap.com spec: group: services.cloud.sap.com @@ -41,14 +40,19 @@ spec: description: ServiceBinding is the Schema for the servicebindings API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -74,25 +78,30 @@ spec: description: The name of the binding in Service Manager type: string parameters: - description: "Parameters for the binding. \n The Parameters field - is NOT secret or secured in any way and should NEVER be used to - hold sensitive information. To set parameters that contain secret - information, you should ALWAYS store that information in a Secret - and use the ParametersFrom field." + description: |- + Parameters for the binding. + + + The Parameters field is NOT secret or secured in any way and should + NEVER be used to hold sensitive information. To set parameters that + contain secret information, you should ALWAYS store that information + in a Secret and use the ParametersFrom field. type: object x-kubernetes-preserve-unknown-fields: true parametersFrom: - description: List of sources to populate parameters. If a top-level - parameter name exists in multiples sources among `Parameters` and - `ParametersFrom` fields, it is considered to be a user error in - the specification + description: |- + List of sources to populate parameters. + If a top-level parameter name exists in multiples sources among + `Parameters` and `ParametersFrom` fields, it is + considered to be a user error in the specification items: description: ParametersFromSource represents the source of a set of Parameters properties: secretKeyRef: - description: The Secret key to select from. The value must be - a JSON object. + description: |- + The Secret key to select from. + The value must be a JSON object. properties: key: description: The key of the secret to select from. Must @@ -109,29 +118,31 @@ spec: type: object type: array secretKey: - description: SecretKey is used as the key inside the secret to store - the credentials returned by the broker encoded as json to support - complex data structures. If not specified, the credentials returned - by the broker will be used directly as the secrets data. + description: |- + SecretKey is used as the key inside the secret to store the credentials + returned by the broker encoded as json to support complex data structures. + If not specified, the credentials returned by the broker will be used + directly as the secrets data. type: string secretName: description: SecretName is the name of the secret where credentials will be stored type: string secretRootKey: - description: SecretRootKey is used as the key inside the secret to - store all binding data including credentials returned by the broker - and additional info under single key. Convenient way to store whole - binding data in single file when using `volumeMounts`. + description: |- + SecretRootKey is used as the key inside the secret to store all binding + data including credentials returned by the broker and additional info under single key. + Convenient way to store whole binding data in single file when using `volumeMounts`. type: string secretTemplate: - description: 'SecretTemplate is a Go template that generates a custom - Kubernetes v1/Secret based on data from the service binding returned - by Service Manager and the instance information. The generated secret - is used instead of the default secret. This is useful if the consumer - of service binding data expects them in a specific format. For Go - templates see https://pkg.go.dev/text/template. For supported funcs - see: https://pkg.go.dev/text/template#hdr-Functions, https://masterminds.github.io/sprig/' + description: |- + SecretTemplate is a Go template that generates a custom Kubernetes + v1/Secret based on data from the service binding returned by Service Manager and the instance information. + The generated secret is used instead of the default secret. + This is useful if the consumer of service binding data expects them in + a specific format. + For Go templates see https://pkg.go.dev/text/template. + For supported funcs see: https://pkg.go.dev/text/template#hdr-Functions, https://masterminds.github.io/sprig/ type: string x-kubernetes-preserve-unknown-fields: true serviceInstanceName: @@ -144,10 +155,10 @@ spec: namespace will be used type: string userInfo: - description: UserInfo contains information about the user that last - modified this instance. This field is set by the API server and - not settable by the end-user. User-provided values for this field - are not saved. + description: |- + UserInfo contains information about the user that last modified this + instance. This field is set by the API server and not settable by the + end-user. User-provided values for this field are not saved. properties: extra: additionalProperties: @@ -164,9 +175,10 @@ spec: type: array x-kubernetes-list-type: atomic uid: - description: A unique value that identifies this user across time. - If this user is deleted and another user by the same name is - added, they will have different UIDs. + description: |- + A unique value that identifies this user across time. If this user is + deleted and another user by the same name is added, they will have + different UIDs. type: string username: description: The name that uniquely identifies this user among @@ -187,42 +199,42 @@ spec: description: Service binding conditions items: description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -236,11 +248,12 @@ spec: - Unknown type: string type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string @@ -311,14 +324,19 @@ spec: description: ServiceBinding is the Schema for the servicebindings API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -344,25 +362,30 @@ spec: description: The name of the binding in Service Manager type: string parameters: - description: "Parameters for the binding. \n The Parameters field - is NOT secret or secured in any way and should NEVER be used to - hold sensitive information. To set parameters that contain secret - information, you should ALWAYS store that information in a Secret - and use the ParametersFrom field." + description: |- + Parameters for the binding. + + + The Parameters field is NOT secret or secured in any way and should + NEVER be used to hold sensitive information. To set parameters that + contain secret information, you should ALWAYS store that information + in a Secret and use the ParametersFrom field. type: object x-kubernetes-preserve-unknown-fields: true parametersFrom: - description: List of sources to populate parameters. If a top-level - parameter name exists in multiples sources among `Parameters` and - `ParametersFrom` fields, it is considered to be a user error in - the specification + description: |- + List of sources to populate parameters. + If a top-level parameter name exists in multiples sources among + `Parameters` and `ParametersFrom` fields, it is + considered to be a user error in the specification items: description: ParametersFromSource represents the source of a set of Parameters properties: secretKeyRef: - description: The Secret key to select from. The value must be - a JSON object. + description: |- + The Secret key to select from. + The value must be a JSON object. properties: key: description: The key of the secret to select from. Must @@ -379,20 +402,21 @@ spec: type: object type: array secretKey: - description: SecretKey is used as the key inside the secret to store - the credentials returned by the broker encoded as json to support - complex data structures. If not specified, the credentials returned - by the broker will be used directly as the secrets data. + description: |- + SecretKey is used as the key inside the secret to store the credentials + returned by the broker encoded as json to support complex data structures. + If not specified, the credentials returned by the broker will be used + directly as the secrets data. type: string secretName: description: SecretName is the name of the secret where credentials will be stored type: string secretRootKey: - description: SecretRootKey is used as the key inside the secret to - store all binding data including credentials returned by the broker - and additional info under single key. Convenient way to store whole - binding data in single file when using `volumeMounts`. + description: |- + SecretRootKey is used as the key inside the secret to store all binding + data including credentials returned by the broker and additional info under single key. + Convenient way to store whole binding data in single file when using `volumeMounts`. type: string serviceInstanceName: description: The k8s name of the service instance to bind, should @@ -400,10 +424,10 @@ spec: minLength: 1 type: string userInfo: - description: UserInfo contains information about the user that last - modified this instance. This field is set by the API server and - not settable by the end-user. User-provided values for this field - are not saved. + description: |- + UserInfo contains information about the user that last modified this + instance. This field is set by the API server and not settable by the + end-user. User-provided values for this field are not saved. properties: extra: additionalProperties: @@ -420,9 +444,10 @@ spec: type: array x-kubernetes-list-type: atomic uid: - description: A unique value that identifies this user across time. - If this user is deleted and another user by the same name is - added, they will have different UIDs. + description: |- + A unique value that identifies this user across time. If this user is + deleted and another user by the same name is added, they will have + different UIDs. type: string username: description: The name that uniquely identifies this user among @@ -443,42 +468,42 @@ spec: description: Service binding conditions items: description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -492,11 +517,12 @@ spec: - Unknown type: string type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string @@ -542,8 +568,7 @@ apiVersion: apiextensions.k8s.io/v1 kind: CustomResourceDefinition metadata: annotations: - controller-gen.kubebuilder.io/version: v0.9.0 - creationTimestamp: null + controller-gen.kubebuilder.io/version: v0.15.0 name: serviceinstances.services.cloud.sap.com spec: group: services.cloud.sap.com @@ -590,14 +615,19 @@ spec: description: ServiceInstance is the Schema for the serviceinstances API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -621,25 +651,30 @@ spec: description: The name of the instance in Service Manager type: string parameters: - description: "Provisioning parameters for the instance. \n The Parameters - field is NOT secret or secured in any way and should NEVER be used - to hold sensitive information. To set parameters that contain secret - information, you should ALWAYS store that information in a Secret - and use the ParametersFrom field." + description: |- + Provisioning parameters for the instance. + + + The Parameters field is NOT secret or secured in any way and should + NEVER be used to hold sensitive information. To set parameters that + contain secret information, you should ALWAYS store that information + in a Secret and use the ParametersFrom field. type: object x-kubernetes-preserve-unknown-fields: true parametersFrom: - description: List of sources to populate parameters. If a top-level - parameter name exists in multiples sources among `Parameters` and - `ParametersFrom` fields, it is considered to be a user error in - the specification + description: |- + List of sources to populate parameters. + If a top-level parameter name exists in multiples sources among + `Parameters` and `ParametersFrom` fields, it is + considered to be a user error in the specification items: description: ParametersFromSource represents the source of a set of Parameters properties: secretKeyRef: - description: The Secret key to select from. The value must be - a JSON object. + description: |- + The Secret key to select from. + The value must be a JSON object. properties: key: description: The key of the secret to select from. Must @@ -671,10 +706,10 @@ spec: description: Indicates the desired shared state type: boolean userInfo: - description: UserInfo contains information about the user that last - modified this instance. This field is set by the API server and - not settable by the end-user. User-provided values for this field - are not saved. + description: |- + UserInfo contains information about the user that last modified this + instance. This field is set by the API server and not settable by the + end-user. User-provided values for this field are not saved. properties: extra: additionalProperties: @@ -691,9 +726,10 @@ spec: type: array x-kubernetes-list-type: atomic uid: - description: A unique value that identifies this user across time. - If this user is deleted and another user by the same name is - added, they will have different UIDs. + description: |- + A unique value that identifies this user across time. If this user is + deleted and another user by the same name is added, they will have + different UIDs. type: string username: description: The name that uniquely identifies this user among @@ -711,42 +747,42 @@ spec: description: Service instance conditions items: description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -760,11 +796,12 @@ spec: - Unknown type: string type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string @@ -845,14 +882,19 @@ spec: description: ServiceInstance is the Schema for the serviceinstances API properties: apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + description: |- + APIVersion defines the versioned schema of this representation of an object. + Servers should convert recognized schemas to the latest internal value, and + may reject unrecognized values. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources type: string kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + description: |- + Kind is a string value representing the REST resource this object represents. + Servers may infer this from the endpoint the client submits requests to. + Cannot be updated. + In CamelCase. + More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds type: string metadata: type: object @@ -869,25 +911,30 @@ spec: description: The name of the instance in Service Manager type: string parameters: - description: "Provisioning parameters for the instance. \n The Parameters - field is NOT secret or secured in any way and should NEVER be used - to hold sensitive information. To set parameters that contain secret - information, you should ALWAYS store that information in a Secret - and use the ParametersFrom field." + description: |- + Provisioning parameters for the instance. + + + The Parameters field is NOT secret or secured in any way and should + NEVER be used to hold sensitive information. To set parameters that + contain secret information, you should ALWAYS store that information + in a Secret and use the ParametersFrom field. type: object x-kubernetes-preserve-unknown-fields: true parametersFrom: - description: List of sources to populate parameters. If a top-level - parameter name exists in multiples sources among `Parameters` and - `ParametersFrom` fields, it is considered to be a user error in - the specification + description: |- + List of sources to populate parameters. + If a top-level parameter name exists in multiples sources among + `Parameters` and `ParametersFrom` fields, it is + considered to be a user error in the specification items: description: ParametersFromSource represents the source of a set of Parameters properties: secretKeyRef: - description: The Secret key to select from. The value must be - a JSON object. + description: |- + The Secret key to select from. + The value must be a JSON object. properties: key: description: The key of the secret to select from. Must @@ -919,10 +966,10 @@ spec: description: Indicates the desired shared state type: boolean userInfo: - description: UserInfo contains information about the user that last - modified this instance. This field is set by the API server and - not settable by the end-user. User-provided values for this field - are not saved. + description: |- + UserInfo contains information about the user that last modified this + instance. This field is set by the API server and not settable by the + end-user. User-provided values for this field are not saved. properties: extra: additionalProperties: @@ -939,9 +986,10 @@ spec: type: array x-kubernetes-list-type: atomic uid: - description: A unique value that identifies this user across time. - If this user is deleted and another user by the same name is - added, they will have different UIDs. + description: |- + A unique value that identifies this user across time. If this user is + deleted and another user by the same name is added, they will have + different UIDs. type: string username: description: The name that uniquely identifies this user among @@ -959,42 +1007,42 @@ spec: description: Service instance conditions items: description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + state of this API Resource.\n---\nThis struct is intended for + direct use as an array at the field path .status.conditions. For + example,\n\n\n\ttype FooStatus struct{\n\t // Represents the + observations of a foo's current state.\n\t // Known .status.conditions.type + are: \"Available\", \"Progressing\", and \"Degraded\"\n\t // + +patchMergeKey=type\n\t // +patchStrategy=merge\n\t // +listType=map\n\t + \ // +listMapKey=type\n\t Conditions []metav1.Condition `json:\"conditions,omitempty\" + patchStrategy:\"merge\" patchMergeKey:\"type\" protobuf:\"bytes,1,rep,name=conditions\"`\n\n\n\t + \ // other fields\n\t}" properties: lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. + description: |- + lastTransitionTime is the last time the condition transitioned from one status to another. + This should be when the underlying condition changed. If that is not known, then using the time when the API field changed is acceptable. format: date-time type: string message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. + description: |- + message is a human readable message indicating details about the transition. + This may be an empty string. maxLength: 32768 type: string observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. + description: |- + observedGeneration represents the .metadata.generation that the condition was set based upon. + For instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date + with respect to the current state of the instance. format: int64 minimum: 0 type: integer reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. + description: |- + reason contains a programmatic identifier indicating the reason for the condition's last transition. + Producers of specific condition types may define expected values and meanings for this field, + and whether the values are considered a guaranteed API. + The value should be a CamelCase string. This field may not be empty. maxLength: 1024 minLength: 1 @@ -1008,11 +1056,12 @@ spec: - Unknown type: string type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + description: |- + type of condition in CamelCase or in foo.example.com/CamelCase. + --- + Many .condition.type values are consistent across resources like Available, but because arbitrary conditions can be + useful (see .node.status.conditions), the ability to deconflict is important. + The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) maxLength: 316 pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ type: string