-
Notifications
You must be signed in to change notification settings - Fork 5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Adopting Orphan Instances via Kubernetes Annotation #50
Conversation
internal/cf/binding.go
Outdated
@@ -29,10 +44,19 @@ func (c *spaceClient) GetBinding(ctx context.Context, owner string) (*facade.Bin | |||
if len(serviceBindings) == 0 { | |||
return nil, nil | |||
} else if len(serviceBindings) > 1 { | |||
return nil, fmt.Errorf("found multiple service bindings with owner: %s", owner) | |||
return nil, fmt.Errorf("found multiple service bindings with owner: %s", value) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
message "found multiple service bindings with owner" is only correct in case of empty bindingName
Either use a more generic message or distinguish both cases in this message.
internal/cf/binding.go
Outdated
if bindingName != "" { | ||
listOpts.Names.EqualTo(bindingName) | ||
} else { | ||
listOpts.LabelSelector.EqualTo(fmt.Sprintf("%s/%s=%s", labelPrefix, labelKeyOwner, owner)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The runtime check is a little ugly. How about taking the listOpts as an argument?
internal/cf/binding.go
Outdated
// add parameter values to the cf instance | ||
if bindingName != "" { | ||
generationvalue := "0" | ||
serviceBinding.Metadata.Annotations[annotationGeneration] = &generationvalue | ||
parameterHashValue := "0" | ||
serviceBinding.Metadata.Annotations[annotationParameterHash] = ¶meterHashValue | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding a parameter to the binding in a method called GetBinding
is a bit unexpected for me. Consider moving this to the reconcile function.
internal/cf/instance.go
Outdated
if instanceName != "" { | ||
listOpts.Names.EqualTo(instanceName) | ||
} else { | ||
listOpts.LabelSelector.EqualTo(fmt.Sprintf("%s/%s=%s", labelPrefix, labelKeyOwner, owner)) | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment above
internal/cf/instance.go
Outdated
// add parameter values to the orphan cf instance | ||
if instanceName != "" { | ||
generationvalue := "0" | ||
serviceInstance.Metadata.Annotations[annotationGeneration] = &generationvalue | ||
parameterHashValue := "0" | ||
serviceInstance.Metadata.Annotations[annotationParameterHash] = ¶meterHashValue | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment above
if err != nil { | ||
return ctrl.Result{}, err | ||
} | ||
if exists && bindingName != "" && cfbinding != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We are already in an if exists && cfbinding != nil
block, and we just set bindingName to serviceBinding.Name (which is guaranteed to exist in the type). This if statement can be simplified to if true
, therefore removed.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was mistaken here, the cfbinding variable is shadowed, so we still need to check for cfbinding != nil
if err != nil { | ||
return ctrl.Result{}, err | ||
} | ||
if exists && instanceName != "" && cfinstance != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above for bindings
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See above, cfinstance
is shadowed, so we need the check for cfinstance != nil
internal/cf/binding.go
Outdated
func (c *spaceClient) GetBinding(ctx context.Context, mapBindingOpts map[string]string) (*facade.Binding, error) { | ||
listOpts := cfclient.NewServiceCredentialBindingListOptions() | ||
listOpts.LabelSelector.EqualTo(labelPrefix + "/" + labelKeyOwner + "=" + owner) | ||
if mapBindingOpts["name"] != "" { | ||
listOpts.Names.EqualTo(mapBindingOpts["name"]) | ||
} else { | ||
listOpts.LabelSelector.EqualTo(fmt.Sprintf("%s/%s=%s", labelPrefix, labelKeyOwner, mapBindingOpts["owner"])) | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How about replacing this with
func (c *spaceClient) GetBinding(ctx context.Context, listOpts cfclient.ServiceCredentialBindingListOptions) (*facade.Binding, error) {
And then just creating the listOpts at the servicebinding_controller level?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The suggested change is not viable. ServiceCredentialBindingListOptions is part of the go-cfclient library's client package.
The package controller does not have direct access to the go-cfclient library's client package. Instead, it has an interface called SpaceClient, which wraps any interaction with the go-client library.
That is a problem because changing the function GetBinding to receive listOpts will break the designed separation between the controller and the go-cfclient library.
Also, we will have to create the LabelSelector in the controller:
listOpts.LabelSelector.EqualTo(fmt.Sprintf("%s/%s=%s", labelPrefix, labelKeyOwner, mapBindingOpts["owner"]))
labelPrefix: is only visible within the cf package, not the controller package.
labelKeyOwner: is only visible within the cf package, not the controller package.
Again, this breaks the current design where those variables are only visible within the cf package.
Change this:
const (
labelPrefix = "service-operator.cf.cs.sap.com"
labelKeyOwner = "owner"
labelOwner = labelPrefix + "/" + labelKeyOwner
annotationPrefix = "service-operator.cf.cs.sap.com"
annotationKeyGeneration = "generation"
annotationGeneration = annotationPrefix + "/" + annotationKeyGeneration
annotationKeyParameterHash = "parameter-hash"
annotationParameterHash = annotationPrefix + "/" + annotationKeyParameterHash
)
to
const (
LabelPrefix = "service-operator.cf.cs.sap.com"
LabelKeyOwner = "owner"
LabelOwner = labelPrefix + "/" + labelKeyOwner
AnnotationPrefix = "service-operator.cf.cs.sap.com"
AnnotationKeyGeneration = "generation"
AnnotationGeneration = annotationPrefix + "/" + annotationKeyGeneration
AnnotationKeyParameterHash = "parameter-hash"
AnnotationParameterHash = annotationPrefix + "/" + annotationKeyParameterHash
)
This change is not going to be accepted because we will have to break the separation of concerns between the controller and the cf client.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right!
I thought about including the gocfclient in the controller might not be very nice, I guess it is worse than I thought since you have to also expose the constants.
Maybe add a new type instead, to pass the owner or name? Like this:
type BindingFilter interface {
GetListOptions() *cfclient.ServiceCredentialBindingListOptions
}
type BindingFilterName struct {
name string
}
type BindingFilterOwner struct {
owner string
}
func (bn *BindingFilterName) GetListOptions() *cfclient.ServiceCredentialBindingListOptions {
listOpts := cfclient.NewServiceCredentialBindingListOptions()
listOpts.Names.EqualTo(bn.name)
return listOpts
}
func (bo *BindingFilterOwner) GetListOptions() *cfclient.ServiceCredentialBindingListOptions {
listOpts := cfclient.NewServiceCredentialBindingListOptions()
listOpts.LabelSelector.EqualTo(fmt.Sprintf("%s/%s=%s", labelPrefix, labelKeyOwner, bo.owner))
return listOpts
}
func (c *spaceClient) GetBinding(ctx context.Context, filter BindindingFilter) (*facade.Binding, error) {
listOpts := filter.GetListOptions()
//...
This way above in the Reconcile, you could just call the function like so GetBinding(ctx, BindingFilterOwner{name: "foo"})
or GetBinding(BindingFilterOwner{owner: "bar"}
. This is nice, since the type is checked at compile time, so we don't need the runtime check for the string. It also makes the function signature nicer and removes the need to initialize a complex string map.
Motivation
We introduce the new annotation
service-operator.cf.cs.sap.com/adopt-instances
to facilitate the adoption of orphan instances.Currently, the only way is via a call to the Cloud Foundry API, as explained in the documentation "Adopt existing resources".
This allows updating the Orphaned Cloud Foundry instances with the label
owner
and the annotationsgeneration
andparameter-hash.