-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add service account and cluster role/binding reconciliation
- Loading branch information
Showing
6 changed files
with
319 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package fullnode | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
cosmosv1 "github.com/strangelove-ventures/cosmos-operator/api/v1" | ||
"github.com/strangelove-ventures/cosmos-operator/internal/diff" | ||
"github.com/strangelove-ventures/cosmos-operator/internal/kube" | ||
rbacv1 "k8s.io/api/rbac/v1" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
) | ||
|
||
// ClusterRoleBindingControl creates or updates ClusterRoleBindings. | ||
type ClusterRoleBindingControl struct { | ||
client Client | ||
} | ||
|
||
func NewClusterRoleBindingControl(client Client) ClusterRoleBindingControl { | ||
return ClusterRoleBindingControl{ | ||
client: client, | ||
} | ||
} | ||
|
||
// Reconcile creates or updates cluster role bindings. | ||
func (sc ClusterRoleBindingControl) Reconcile(ctx context.Context, log kube.Logger, crd *cosmosv1.CosmosFullNode) kube.ReconcileError { | ||
var crs rbacv1.ClusterRoleBindingList | ||
if err := sc.client.List(ctx, &crs, | ||
client.InNamespace(crd.Namespace), | ||
client.MatchingFields{kube.ControllerOwnerField: crd.Name}, | ||
); err != nil { | ||
return kube.TransientError(fmt.Errorf("list existing cluster role bindings: %w", err)) | ||
} | ||
|
||
current := ptrSlice(crs.Items) | ||
want := BuildClusterRoleBindings(crd) | ||
diffed := diff.New(current, want) | ||
|
||
for _, cr := range diffed.Creates() { | ||
log.Info("Creating cluster role binding", "clusterRoleBindingName", cr.Name) | ||
if err := ctrl.SetControllerReference(crd, cr, sc.client.Scheme()); err != nil { | ||
return kube.TransientError(fmt.Errorf("set controller reference on cluster role binding %q: %w", cr.Name, err)) | ||
} | ||
// CreateOrUpdate (vs. only create) fixes a bug with current deployments where updating would remove the owner reference. | ||
// This ensures we update the service with the owner reference. | ||
if err := kube.CreateOrUpdate(ctx, sc.client, cr); err != nil { | ||
return kube.TransientError(fmt.Errorf("create cluster role binding %q: %w", cr.Name, err)) | ||
} | ||
} | ||
|
||
for _, cr := range diffed.Updates() { | ||
log.Info("Updating cluster role binding", "clusterRoleBindingName", cr.Name) | ||
if err := sc.client.Update(ctx, cr); err != nil { | ||
return kube.TransientError(fmt.Errorf("update cluster role binding %q: %w", cr.Name, err)) | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package fullnode | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
cosmosv1 "github.com/strangelove-ventures/cosmos-operator/api/v1" | ||
"github.com/strangelove-ventures/cosmos-operator/internal/diff" | ||
"github.com/strangelove-ventures/cosmos-operator/internal/kube" | ||
rbacv1 "k8s.io/api/rbac/v1" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
) | ||
|
||
// ClusterRoleControl creates or updates ClusterRoles. | ||
type ClusterRoleControl struct { | ||
client Client | ||
} | ||
|
||
func NewClusterRoleControl(client Client) ClusterRoleControl { | ||
return ClusterRoleControl{ | ||
client: client, | ||
} | ||
} | ||
|
||
// Reconcile creates or updates cluster roles. | ||
func (sc ClusterRoleControl) Reconcile(ctx context.Context, log kube.Logger, crd *cosmosv1.CosmosFullNode) kube.ReconcileError { | ||
var crs rbacv1.ClusterRoleList | ||
if err := sc.client.List(ctx, &crs, | ||
client.InNamespace(crd.Namespace), | ||
client.MatchingFields{kube.ControllerOwnerField: crd.Name}, | ||
); err != nil { | ||
return kube.TransientError(fmt.Errorf("list existing cluster roles: %w", err)) | ||
} | ||
|
||
current := ptrSlice(crs.Items) | ||
want := BuildClusterRoles(crd) | ||
diffed := diff.New(current, want) | ||
|
||
for _, cr := range diffed.Creates() { | ||
log.Info("Creating cluster role", "clusterRoleName", cr.Name) | ||
if err := ctrl.SetControllerReference(crd, cr, sc.client.Scheme()); err != nil { | ||
return kube.TransientError(fmt.Errorf("set controller reference on cluster role %q: %w", cr.Name, err)) | ||
} | ||
// CreateOrUpdate (vs. only create) fixes a bug with current deployments where updating would remove the owner reference. | ||
// This ensures we update the service with the owner reference. | ||
if err := kube.CreateOrUpdate(ctx, sc.client, cr); err != nil { | ||
return kube.TransientError(fmt.Errorf("create cluster role %q: %w", cr.Name, err)) | ||
} | ||
} | ||
|
||
for _, cr := range diffed.Updates() { | ||
log.Info("Updating cluster role", "clusterRoleName", cr.Name) | ||
if err := sc.client.Update(ctx, cr); err != nil { | ||
return kube.TransientError(fmt.Errorf("update cluster role %q: %w", cr.Name, err)) | ||
} | ||
} | ||
|
||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
package fullnode | ||
|
||
import ( | ||
cosmosv1 "github.com/strangelove-ventures/cosmos-operator/api/v1" | ||
"github.com/strangelove-ventures/cosmos-operator/internal/diff" | ||
corev1 "k8s.io/api/core/v1" | ||
rbacv1 "k8s.io/api/rbac/v1" | ||
v1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||
) | ||
|
||
func serviceAccountName(crd *cosmosv1.CosmosFullNode) string { | ||
return crd.Name + "-vc" | ||
} | ||
|
||
func clusterRoleName(crd *cosmosv1.CosmosFullNode) string { | ||
return crd.Name + "-cr" | ||
} | ||
|
||
// BuildServiceAccounts returns a list of service accounts given the crd. | ||
// | ||
// Creates a single service account for the version check. | ||
func BuildServiceAccounts(crd *cosmosv1.CosmosFullNode) []diff.Resource[*corev1.ServiceAccount] { | ||
diffSa := make([]diff.Resource[*corev1.ServiceAccount], 1) | ||
svc := corev1.ServiceAccount{ | ||
TypeMeta: v1.TypeMeta{ | ||
Kind: "ServiceAccount", | ||
}, | ||
ObjectMeta: v1.ObjectMeta{ | ||
Name: serviceAccountName(crd), | ||
Namespace: crd.Namespace, | ||
}, | ||
} | ||
|
||
diffSa[0] = diff.Adapt(&svc, 0) | ||
|
||
return diffSa | ||
} | ||
|
||
// BuildClusterRoles returns a list of cluster roles given the crd. | ||
// | ||
// Creates a single cluster role for the version check. | ||
func BuildClusterRoles(crd *cosmosv1.CosmosFullNode) []diff.Resource[*rbacv1.ClusterRole] { | ||
diffCr := make([]diff.Resource[*rbacv1.ClusterRole], 1) | ||
cr := rbacv1.ClusterRole{ | ||
ObjectMeta: v1.ObjectMeta{ | ||
Name: clusterRoleName(crd), | ||
Namespace: crd.Namespace, | ||
}, | ||
Rules: []rbacv1.PolicyRule{ | ||
{ | ||
APIGroups: []string{""}, // core API group | ||
Resources: []string{"namespaces", "pods"}, | ||
Verbs: []string{"get", "list"}, | ||
}, | ||
{ | ||
APIGroups: []string{"cosmos.strange.love"}, | ||
Resources: []string{"cosmosfullnodes"}, | ||
Verbs: []string{"get", "list", "patch"}, | ||
}, | ||
}, | ||
} | ||
|
||
diffCr[0] = diff.Adapt(&cr, 0) | ||
|
||
return diffCr | ||
} | ||
|
||
// BuildClusterRoles returns a list of cluster role bindings given the crd. | ||
// | ||
// Creates a single cluster role binding for the version check. | ||
func BuildClusterRoleBindings(crd *cosmosv1.CosmosFullNode) []diff.Resource[*rbacv1.ClusterRoleBinding] { | ||
diffCrb := make([]diff.Resource[*rbacv1.ClusterRoleBinding], 1) | ||
crb := rbacv1.ClusterRoleBinding{ | ||
ObjectMeta: v1.ObjectMeta{ | ||
Name: crd.Name + "-crb", | ||
Namespace: crd.Namespace, | ||
}, | ||
Subjects: []rbacv1.Subject{ | ||
{ | ||
Kind: "ServiceAccount", | ||
Name: serviceAccountName(crd), | ||
Namespace: crd.Namespace, | ||
}, | ||
}, | ||
RoleRef: rbacv1.RoleRef{ | ||
Kind: "ClusterRole", | ||
Name: clusterRoleName(crd), | ||
APIGroup: "rbac.authorization.k8s.io", | ||
}, | ||
} | ||
|
||
diffCrb[0] = diff.Adapt(&crb, 0) | ||
|
||
return diffCrb | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
package fullnode | ||
|
||
import ( | ||
"context" | ||
"fmt" | ||
|
||
cosmosv1 "github.com/strangelove-ventures/cosmos-operator/api/v1" | ||
"github.com/strangelove-ventures/cosmos-operator/internal/diff" | ||
"github.com/strangelove-ventures/cosmos-operator/internal/kube" | ||
corev1 "k8s.io/api/core/v1" | ||
ctrl "sigs.k8s.io/controller-runtime" | ||
"sigs.k8s.io/controller-runtime/pkg/client" | ||
) | ||
|
||
// ServiceControl creates or updates Services. | ||
type ServiceAccountControl struct { | ||
client Client | ||
} | ||
|
||
func NewServiceAccountControl(client Client) ServiceAccountControl { | ||
return ServiceAccountControl{ | ||
client: client, | ||
} | ||
} | ||
|
||
// Reconcile creates or updates service accounts. | ||
func (sc ServiceAccountControl) Reconcile(ctx context.Context, log kube.Logger, crd *cosmosv1.CosmosFullNode) kube.ReconcileError { | ||
var svcs corev1.ServiceAccountList | ||
if err := sc.client.List(ctx, &svcs, | ||
client.InNamespace(crd.Namespace), | ||
client.MatchingFields{kube.ControllerOwnerField: crd.Name}, | ||
); err != nil { | ||
return kube.TransientError(fmt.Errorf("list existing service accounts: %w", err)) | ||
} | ||
|
||
current := ptrSlice(svcs.Items) | ||
want := BuildServiceAccounts(crd) | ||
diffed := diff.New(current, want) | ||
|
||
for _, svc := range diffed.Creates() { | ||
log.Info("Creating service account", "svcAccountName", svc.Name) | ||
if err := ctrl.SetControllerReference(crd, svc, sc.client.Scheme()); err != nil { | ||
return kube.TransientError(fmt.Errorf("set controller reference on service account %q: %w", svc.Name, err)) | ||
} | ||
// CreateOrUpdate (vs. only create) fixes a bug with current deployments where updating would remove the owner reference. | ||
// This ensures we update the service with the owner reference. | ||
if err := kube.CreateOrUpdate(ctx, sc.client, svc); err != nil { | ||
return kube.TransientError(fmt.Errorf("create service account %q: %w", svc.Name, err)) | ||
} | ||
} | ||
|
||
for _, svc := range diffed.Updates() { | ||
log.Info("Updating service account", "svcAccountName", svc.Name) | ||
if err := sc.client.Update(ctx, svc); err != nil { | ||
return kube.TransientError(fmt.Errorf("update service account %q: %w", svc.Name, err)) | ||
} | ||
} | ||
|
||
return nil | ||
} |