in pkg/install/operator.go [390:464]
func installClusterRoleBinding(ctx context.Context, c client.Client, collection *kubernetes.Collection, namespace string, name string, path string) error {
var target *rbacv1.ClusterRoleBinding
existing, err := c.RbacV1().ClusterRoleBindings().Get(ctx, name, metav1.GetOptions{})
switch {
case k8serrors.IsNotFound(err):
content, err := resources.ResourceAsString(path)
if err != nil {
return err
}
existing = nil
if content == "" {
return fmt.Errorf("resource file %v not found", path)
}
obj, err := kubernetes.LoadResourceFromYaml(c.GetScheme(), content)
if err != nil {
return err
}
var ok bool
if target, ok = obj.(*rbacv1.ClusterRoleBinding); !ok {
return fmt.Errorf("file %v does not contain a ClusterRoleBinding resource", path)
}
case err != nil:
return err
default:
target = existing.DeepCopy()
}
bound := false
for i, subject := range target.Subjects {
if subject.Name == serviceAccountName {
if subject.Namespace == namespace {
bound = true
break
} else if subject.Namespace == "" || subject.Namespace == "placeholder" {
target.Subjects[i].Namespace = namespace
bound = true
break
}
}
}
if !bound {
target.Subjects = append(target.Subjects, rbacv1.Subject{
Kind: "ServiceAccount",
Namespace: namespace,
Name: serviceAccountName,
})
}
if collection != nil {
collection.Add(target)
return nil
}
if existing == nil {
return c.Create(ctx, target)
}
// The ClusterRoleBinding.Subjects field does not have a patchStrategy key in its field tag,
// so a strategic merge patch would use the default patch strategy, which is replace.
// Let's compute a simple JSON merge patch from the existing resource, and patch it.
p, err := patch.MergePatch(existing, target)
if err != nil {
return err
} else if len(p) == 0 {
// Avoid triggering a patch request for nothing
return nil
}
return c.Patch(ctx, existing, ctrl.RawPatch(types.MergePatchType, p))
}