Skip to content

Commit

Permalink
Merge pull request #29 from appuio/feat/owner-ref
Browse files Browse the repository at this point in the history
Link OrganizationMembers to Organization with an owner reference
  • Loading branch information
glrf authored Feb 3, 2022
2 parents 9b44b52 + 3ba833b commit 60643fa
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 18 deletions.
18 changes: 14 additions & 4 deletions apiserver/organization/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ func (s *organizationStorage) Create(ctx context.Context, obj runtime.Object, cr
}

func (s *organizationStorage) create(ctx context.Context, org *orgv1.Organization, options *metav1.CreateOptions) (*orgv1.Organization, error) {
if err := s.namepaces.CreateNamespace(ctx, org.ToNamespace(), options); err != nil {
ns, err := s.namepaces.CreateNamespace(ctx, org.ToNamespace(), options)
if err != nil {
return nil, convertNamespaceError(err)
}
org = orgv1.NewOrganizationFromNS(ns)

if err := s.rbac.CreateRoleBindings(ctx, org.Name); err != nil {
// rollback
Expand All @@ -48,7 +50,7 @@ func (s *organizationStorage) create(ctx context.Context, org *orgv1.Organizatio
return nil, fmt.Errorf("failed to create organization: %w", err)
}

orgMembers := newOrganizationMembers(ctx, org.Name, s.usernamePrefix)
orgMembers := newOrganizationMembers(ctx, org, s.usernamePrefix)

if err := s.members.CreateMembers(ctx, orgMembers); err != nil {
// rollback
Expand All @@ -63,7 +65,7 @@ func (s *organizationStorage) create(ctx context.Context, org *orgv1.Organizatio
return org, nil
}

func newOrganizationMembers(ctx context.Context, organization, usernamePrefix string) *controlv1.OrganizationMembers {
func newOrganizationMembers(ctx context.Context, organization *orgv1.Organization, usernamePrefix string) *controlv1.OrganizationMembers {
userRefs := []controlv1.UserRef{}
user, ok := request.UserFrom(ctx)
if ok {
Expand All @@ -72,10 +74,18 @@ func newOrganizationMembers(ctx context.Context, organization, usernamePrefix st
})
}

isController := true
return &controlv1.OrganizationMembers{
ObjectMeta: metav1.ObjectMeta{
Name: "members",
Namespace: organization,
Namespace: organization.Name,
OwnerReferences: []metav1.OwnerReference{{
APIVersion: orgv1.GroupVersion.String(),
Kind: "Organization",
UID: organization.UID,
Name: organization.Name,
Controller: &isController,
}},
},
Spec: controlv1.OrganizationMembersSpec{
UserRefs: userRefs,
Expand Down
23 changes: 15 additions & 8 deletions apiserver/organization/create_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
controlv1 "github.com/appuio/control-api/apis/v1"
mock "github.com/appuio/control-api/apiserver/organization/mock"

corev1 "k8s.io/api/core/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/runtime/schema"
Expand Down Expand Up @@ -88,20 +89,24 @@ func TestOrganizationStorage_Create(t *testing.T) {
mmemb := mock.NewMockmemberProvider(ctrl)
os.members = mmemb
os.usernamePrefix = "appuio#"
nsOut := &corev1.Namespace{}
if tc.organizationOut != nil {
nsOut = tc.organizationOut.ToNamespace()
}
mauth.EXPECT().
Authorize(gomock.Any(), isAuthRequest("create")).
Return(tc.authDecision.decision, tc.authDecision.reason, tc.authDecision.err).
Times(1)
mnp.EXPECT().
CreateNamespace(gomock.Any(), gomock.Any(), gomock.Any()).
Return(tc.namespaceErr).
Return(nsOut, tc.namespaceErr).
AnyTimes()
mrb.EXPECT().
CreateRoleBindings(gomock.Any(), gomock.Any()).
Return(nil).
AnyTimes()
mmemb.EXPECT().
CreateMembers(gomock.Any(), containsMember(tc.memberName)).
CreateMembers(gomock.Any(), containsMemberAndOwner(tc.organizationIn.Name, tc.memberName)).
Return(nil).
AnyTimes()

Expand Down Expand Up @@ -158,7 +163,7 @@ func TestOrganizationStorage_Create_Abort(t *testing.T) {
Times(1)
mnp.EXPECT().
CreateNamespace(gomock.Any(), gomock.Any(), gomock.Any()).
Return(nil).
Return(fooNs, nil).
Times(1)

if tc.failRoleBinding {
Expand Down Expand Up @@ -202,21 +207,23 @@ func TestOrganizationStorage_Create_Abort(t *testing.T) {
}

type memberMatcher struct {
user string
owner string
user string
}

func (m memberMatcher) Matches(x interface{}) bool {
mem, ok := x.(*controlv1.OrganizationMembers)
if !ok {
return ok
}
return len(mem.Spec.UserRefs) > 0 && mem.Spec.UserRefs[0].ID == m.user
return len(mem.Spec.UserRefs) > 0 && mem.Spec.UserRefs[0].ID == m.user &&
len(mem.OwnerReferences) > 0 && mem.OwnerReferences[0].Name == m.owner
}

func (m memberMatcher) String() string {
return fmt.Sprintf("contains %s", m.user)
return fmt.Sprintf("contains %s and owned by %s", m.user, m.owner)
}

func containsMember(user string) memberMatcher {
return memberMatcher{user: user}
func containsMemberAndOwner(owner, user string) memberMatcher {
return memberMatcher{user: user, owner: owner}
}
7 changes: 4 additions & 3 deletions apiserver/organization/mock/namespace.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 4 additions & 3 deletions apiserver/organization/namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
type namespaceProvider interface {
GetNamespace(ctx context.Context, name string, options *metav1.GetOptions) (*corev1.Namespace, error)
DeleteNamespace(ctx context.Context, name string, options *metav1.DeleteOptions) (*corev1.Namespace, error)
CreateNamespace(ctx context.Context, ns *corev1.Namespace, options *metav1.CreateOptions) error
CreateNamespace(ctx context.Context, ns *corev1.Namespace, options *metav1.CreateOptions) (*corev1.Namespace, error)
UpdateNamespace(ctx context.Context, ns *corev1.Namespace, options *metav1.UpdateOptions) error
ListNamespaces(ctx context.Context, options *metainternalversion.ListOptions) (*corev1.NamespaceList, error)
WatchNamespaces(ctx context.Context, options *metainternalversion.ListOptions) (watch.Interface, error)
Expand All @@ -41,10 +41,11 @@ func (p *kubeNamespaceProvider) DeleteNamespace(ctx context.Context, name string
return &ns, err
}

func (p *kubeNamespaceProvider) CreateNamespace(ctx context.Context, ns *corev1.Namespace, options *metav1.CreateOptions) error {
return p.Client.Create(ctx, ns, &client.CreateOptions{
func (p *kubeNamespaceProvider) CreateNamespace(ctx context.Context, ns *corev1.Namespace, options *metav1.CreateOptions) (*corev1.Namespace, error) {
err := p.Client.Create(ctx, ns, &client.CreateOptions{
Raw: options,
})
return ns, err
}

func (p *kubeNamespaceProvider) UpdateNamespace(ctx context.Context, ns *corev1.Namespace, options *metav1.UpdateOptions) error {
Expand Down

0 comments on commit 60643fa

Please sign in to comment.