Skip to content

Commit

Permalink
Make Regions Organization Scoped
Browse files Browse the repository at this point in the history
After playing with the UI, it semms quite apparent that mapping a region
ID to a name, when the region is itself project scoped is quite heavy
weight and unwieldy.  To remedy this we move regions back to the
organization scope so we need only a single lookup, relying on RBAC
information to do any filtering.  This also splits up regions and
instrastructure so readers can map to regions, but not create identities
etc.
  • Loading branch information
spjmurray committed Jul 15, 2024
1 parent e228e66 commit 7941755
Show file tree
Hide file tree
Showing 10 changed files with 440 additions and 547 deletions.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require (
github.com/oapi-codegen/runtime v1.1.1
github.com/spf13/pflag v1.0.5
github.com/stretchr/testify v1.9.0
github.com/unikorn-cloud/core v0.1.59
github.com/unikorn-cloud/core v0.1.60
github.com/unikorn-cloud/identity v0.2.25
go.opentelemetry.io/otel v1.28.0
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.28.0
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,8 @@ github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsT
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE=
github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/unikorn-cloud/core v0.1.59 h1:Fow+RmWADvIHcDGnKxeE+m7uJzq2ARJb1/nPA2tY6+o=
github.com/unikorn-cloud/core v0.1.59/go.mod h1:Cd0zU1LrKo+OwnnCwuTQ+QL3yibnkjDHtkujfDM4AdE=
github.com/unikorn-cloud/core v0.1.60 h1:N/4xkv3dNv8/ZM3VqyxsECm2Ji/gE3QBoLjGsEUQTg4=
github.com/unikorn-cloud/core v0.1.60/go.mod h1:Cd0zU1LrKo+OwnnCwuTQ+QL3yibnkjDHtkujfDM4AdE=
github.com/unikorn-cloud/identity v0.2.25 h1:nb45gnI8o/12idVodWtAVO5WRFW8cTg6PFQHYjLd3DM=
github.com/unikorn-cloud/identity v0.2.25/go.mod h1:8WxgWetyrCvLjRGAeEWy5hWXDJ8prVz+FNt9sG17lV8=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
Expand Down
71 changes: 33 additions & 38 deletions pkg/handler/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ import (
"github.com/unikorn-cloud/region/pkg/providers"
"github.com/unikorn-cloud/region/pkg/server/util"

metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
kerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"

"sigs.k8s.io/controller-runtime/pkg/client"
Expand Down Expand Up @@ -80,8 +80,8 @@ func (h *Handler) setUncacheable(w http.ResponseWriter) {
w.Header().Add("Cache-Control", "no-cache")
}

func (h *Handler) GetApiV1OrganizationsOrganizationIDProjectsProjectIDRegions(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter) {
if err := rbac.AllowProjectScope(r.Context(), "infrastructure", identityapi.Read, organizationID, projectID); err != nil {
func (h *Handler) GetApiV1OrganizationsOrganizationIDRegions(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter) {
if err := rbac.AllowOrganizationScope(r.Context(), "regions", identityapi.Read, organizationID); err != nil {
errors.HandleError(w, r, err)
return
}
Expand Down Expand Up @@ -133,8 +133,8 @@ func convertFlavor(in providers.Flavor) openapi.Flavor {
return out
}

func (h *Handler) GetApiV1OrganizationsOrganizationIDProjectsProjectIDRegionsRegionIDFlavors(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter, regionID openapi.RegionIDParameter) {
if err := rbac.AllowProjectScope(r.Context(), "infrastructure", identityapi.Read, organizationID, projectID); err != nil {
func (h *Handler) GetApiV1OrganizationsOrganizationIDRegionsRegionIDFlavors(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, regionID openapi.RegionIDParameter) {
if err := rbac.AllowOrganizationScope(r.Context(), "regions", identityapi.Read, organizationID); err != nil {
errors.HandleError(w, r, err)
return
}
Expand Down Expand Up @@ -194,8 +194,8 @@ func convertImage(in providers.Image) openapi.Image {
return out
}

func (h *Handler) GetApiV1OrganizationsOrganizationIDProjectsProjectIDRegionsRegionIDImages(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter, regionID openapi.RegionIDParameter) {
if err := rbac.AllowProjectScope(r.Context(), "infrastructure", identityapi.Read, organizationID, projectID); err != nil {
func (h *Handler) GetApiV1OrganizationsOrganizationIDRegionsRegionIDImages(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, regionID openapi.RegionIDParameter) {
if err := rbac.AllowOrganizationScope(r.Context(), "regions", identityapi.Read, organizationID); err != nil {
errors.HandleError(w, r, err)
return
}
Expand Down Expand Up @@ -250,29 +250,12 @@ func convertTags(in unikornv1.TagList) openapi.TagList {
return out
}

func regionScopedResourceReadMetadata(in metav1.Object, status coreapi.ResourceProvisioningStatus) coreapi.RegionScopedResourceMetadata {
labels := in.GetLabels()

temp := conversion.ProjectScopedResourceReadMetadata(in, status)

out := coreapi.RegionScopedResourceMetadata{
Id: temp.Id,
Name: temp.Name,
Description: temp.Description,
CreatedBy: temp.CreatedBy,
CreationTime: temp.CreationTime,
ProvisioningStatus: temp.ProvisioningStatus,
OrganizationId: temp.OrganizationId,
ProjectId: temp.ProjectId,
RegionId: labels[constants.RegionLabel],
}

return out
}

func convertIdentity(identity *unikornv1.Identity, in *providers.CloudConfig) *openapi.IdentityRead {
out := &openapi.IdentityRead{
Metadata: regionScopedResourceReadMetadata(identity, coreapi.ResourceProvisioningStatusProvisioned),
Metadata: conversion.ProjectScopedResourceReadMetadata(identity, coreapi.ResourceProvisioningStatusProvisioned),
Spec: openapi.IdentitySpec{
RegionId: identity.Labels[constants.RegionLabel],
},
}

if tags := convertTags(identity.Spec.Tags); tags != nil {
Expand Down Expand Up @@ -310,7 +293,7 @@ func convertIdentityList(in unikornv1.IdentityList) openapi.IdentitiesRead {
}

func (h *Handler) GetApiV1OrganizationsOrganizationIDIdentities(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter) {
if err := rbac.AllowOrganizationScope(r.Context(), "infrastructure", identityapi.Read, organizationID); err != nil {
if err := rbac.AllowOrganizationScope(r.Context(), "identities", identityapi.Read, organizationID); err != nil {
errors.HandleError(w, r, err)
return
}
Expand All @@ -331,8 +314,8 @@ func (h *Handler) GetApiV1OrganizationsOrganizationIDIdentities(w http.ResponseW
util.WriteJSONResponse(w, r, http.StatusOK, convertIdentityList(resources))
}

func (h *Handler) PostApiV1OrganizationsOrganizationIDProjectsProjectIDRegionsRegionIDIdentities(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter, regionID openapi.RegionIDParameter) {
if err := rbac.AllowProjectScope(r.Context(), "infrastructure", identityapi.Create, organizationID, projectID); err != nil {
func (h *Handler) PostApiV1OrganizationsOrganizationIDProjectsProjectIDIdentities(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter) {
if err := rbac.AllowProjectScope(r.Context(), "identities", identityapi.Create, organizationID, projectID); err != nil {
errors.HandleError(w, r, err)
return
}
Expand All @@ -344,7 +327,7 @@ func (h *Handler) PostApiV1OrganizationsOrganizationIDProjectsProjectIDRegionsRe
return
}

provider, err := region.NewClient(h.client, h.namespace).Provider(r.Context(), regionID)
provider, err := region.NewClient(h.client, h.namespace).Provider(r.Context(), request.Spec.RegionId)
if err != nil {
errors.HandleError(w, r, err)
return
Expand Down Expand Up @@ -372,8 +355,8 @@ func convertPhysicalNetwork(in *unikornv1.PhysicalNetwork) *openapi.PhysicalNetw
return out
}

func (h *Handler) PostApiV1OrganizationsOrganizationIDProjectsProjectIDRegionsRegionIDIdentitiesIdentityIDPhysicalNetworks(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter, regionID openapi.RegionIDParameter, identityID openapi.IdentityIDParameter) {
if err := rbac.AllowProjectScope(r.Context(), "infrastructure", identityapi.Create, organizationID, projectID); err != nil {
func (h *Handler) PostApiV1OrganizationsOrganizationIDProjectsProjectIDIdentitiesIdentityIDPhysicalNetworks(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter, identityID openapi.IdentityIDParameter) {
if err := rbac.AllowProjectScope(r.Context(), "identities", identityapi.Create, organizationID, projectID); err != nil {
errors.HandleError(w, r, err)
return
}
Expand All @@ -385,13 +368,25 @@ func (h *Handler) PostApiV1OrganizationsOrganizationIDProjectsProjectIDRegionsRe
return
}

provider, err := region.NewClient(h.client, h.namespace).Provider(r.Context(), regionID)
identity := &unikornv1.Identity{}

if err := h.client.Get(r.Context(), client.ObjectKey{Namespace: h.namespace, Name: identityID}, identity); err != nil {
if kerrors.IsNotFound(err) {
errors.HandleError(w, r, errors.HTTPNotFound().WithError(err))
return
}

errors.HandleError(w, r, err)
return
}

provider, err := region.NewClient(h.client, h.namespace).Provider(r.Context(), identity.Labels[constants.RegionLabel])
if err != nil {
errors.HandleError(w, r, err)
return
}

network, err := provider.CreatePhysicalNetwork(r.Context(), organizationID, projectID, identityID, request)
network, err := provider.CreatePhysicalNetwork(r.Context(), identity, request)
if err != nil {
errors.HandleError(w, r, err)
return
Expand Down Expand Up @@ -419,8 +414,8 @@ func convertExternalNetworks(in providers.ExternalNetworks) openapi.ExternalNetw
return out
}

func (h *Handler) GetApiV1OrganizationsOrganizationIDProjectsProjectIDRegionsRegionIDExternalnetworks(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, projectID openapi.ProjectIDParameter, regionID openapi.RegionIDParameter) {
if err := rbac.AllowProjectScope(r.Context(), "infrastructure", identityapi.Read, organizationID, projectID); err != nil {
func (h *Handler) GetApiV1OrganizationsOrganizationIDRegionsRegionIDExternalnetworks(w http.ResponseWriter, r *http.Request, organizationID openapi.OrganizationIDParameter, regionID openapi.RegionIDParameter) {
if err := rbac.AllowOrganizationScope(r.Context(), "regions", identityapi.Read, organizationID); err != nil {
errors.HandleError(w, r, err)
return
}
Expand Down
Loading

0 comments on commit 7941755

Please sign in to comment.