Skip to content

Commit

Permalink
api: Add ResourceID wrapper type
Browse files Browse the repository at this point in the history
This is a thinly wrappered azcorearm.ResourceID that implements
the encoding.TextMarshaler and encoding.TextUnmarshaler interfaces,
so that ResourceID can be used directly in structs that get built
from JSON data.

I proposed this for azcorearm.ResourceID in:
Azure/azure-sdk-for-go#23381
  • Loading branch information
Matthew Barnes authored and mjlshen committed Aug 30, 2024
1 parent 3eb9cc0 commit a322e3b
Show file tree
Hide file tree
Showing 10 changed files with 60 additions and 40 deletions.
8 changes: 3 additions & 5 deletions frontend/pkg/frontend/context.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import (
"fmt"
"log/slog"

azcorearm "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"

"github.com/Azure/ARO-HCP/internal/api"
"github.com/Azure/ARO-HCP/internal/api/arm"
)
Expand Down Expand Up @@ -96,12 +94,12 @@ func VersionFromContext(ctx context.Context) (api.Version, error) {
return version, nil
}

func ContextWithResourceID(ctx context.Context, resourceID *azcorearm.ResourceID) context.Context {
func ContextWithResourceID(ctx context.Context, resourceID *arm.ResourceID) context.Context {
return context.WithValue(ctx, contextKeyResourceID, resourceID)
}

func ResourceIDFromContext(ctx context.Context) (*azcorearm.ResourceID, error) {
resourceID, ok := ctx.Value(contextKeyResourceID).(*azcorearm.ResourceID)
func ResourceIDFromContext(ctx context.Context) (*arm.ResourceID, error) {
resourceID, ok := ctx.Value(contextKeyResourceID).(*arm.ResourceID)
if !ok {
err := &ContextError{
got: resourceID,
Expand Down
23 changes: 7 additions & 16 deletions frontend/pkg/frontend/frontend.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ func (f *Frontend) ArmResourceList(writer http.ResponseWriter, request *http.Req
clusters := clustersListResponse.Items().Slice()
for _, cluster := range clusters {
// FIXME Temporary, until we have a real ResourceID to pass.
resourceID, err := azcorearm.ParseResourceID(fmt.Sprintf(
azcoreResourceID, err := azcorearm.ParseResourceID(fmt.Sprintf(
"/subscriptions/%s/resourceGroups/%s/providers/%s/%s",
subscriptionId, resourceGroupName, api.ResourceType,
cluster.Azure().ResourceName()))
Expand All @@ -180,6 +180,7 @@ func (f *Frontend) ArmResourceList(writer http.ResponseWriter, request *http.Req
arm.WriteInternalServerError(writer)
return
}
resourceID := &arm.ResourceID{ResourceID: *azcoreResourceID}
hcpCluster = ConvertCStoHCPOpenShiftCluster(resourceID, cluster)
versionedResource := versionedInterface.NewHCPOpenShiftCluster(hcpCluster)
versionedHcpClusters = append(versionedHcpClusters, &versionedResource)
Expand Down Expand Up @@ -365,7 +366,7 @@ func (f *Frontend) ArmResourceCreateOrUpdate(writer http.ResponseWriter, request

doc = &database.ResourceDocument{
ID: uuid.New().String(),
Key: resourceID.String(),
Key: resourceID,
PartitionKey: resourceID.SubscriptionID,
}
docUpdated = true
Expand Down Expand Up @@ -862,7 +863,7 @@ func (f *Frontend) CreateOrUpdateNodePool(writer http.ResponseWriter, request *h

f.logger.Info(fmt.Sprintf("%s: CreateNodePool", versionedInterface))

clusterResourceID := nodePoolResourceID.Parent
clusterResourceID := nodePoolResourceID.GetParent()
if clusterResourceID == nil {
f.logger.Error(fmt.Sprintf("failed to obtain Azure parent resourceID for node pool %s", nodePoolResourceID))
arm.WriteInternalServerError(writer)
Expand Down Expand Up @@ -954,7 +955,7 @@ func (f *Frontend) CreateOrUpdateNodePool(writer http.ResponseWriter, request *h

nodePoolDoc = &database.ResourceDocument{
ID: uuid.New().String(),
Key: nodePoolResourceID.String(),
Key: nodePoolResourceID,
PartitionKey: nodePoolResourceID.SubscriptionID,
}
docUpdated = true
Expand Down Expand Up @@ -1115,12 +1116,7 @@ func (f *Frontend) DeleteNodePool(writer http.ResponseWriter, request *http.Requ
// marshalCSCluster renders a CS Cluster object in JSON format, applying
// the necessary conversions for the API version of the request.
func marshalCSCluster(csCluster *cmv2alpha1.Cluster, doc *database.ResourceDocument, versionedInterface api.Version) ([]byte, error) {
resourceID, err := azcorearm.ParseResourceID(doc.Key)
if err != nil {
return nil, err
}

hcpCluster := ConvertCStoHCPOpenShiftCluster(resourceID, csCluster)
hcpCluster := ConvertCStoHCPOpenShiftCluster(doc.Key, csCluster)
hcpCluster.TrackedResource.Resource.SystemData = doc.SystemData
hcpCluster.TrackedResource.Tags = maps.Clone(doc.Tags)

Expand All @@ -1130,12 +1126,7 @@ func marshalCSCluster(csCluster *cmv2alpha1.Cluster, doc *database.ResourceDocum
// marshalCSNodePool renders a CS NodePool object in JSON format, applying
// the necessary conversions for the API version of the request.
func marshalCSNodePool(csNodePool *cmv2alpha1.NodePool, doc *database.ResourceDocument, versionedInterface api.Version) ([]byte, error) {
resourceID, err := azcorearm.ParseResourceID(doc.Key)
if err != nil {
return nil, err
}

hcpNodePool := ConvertCStoNodePool(resourceID, csNodePool)
hcpNodePool := ConvertCStoNodePool(doc.Key, csNodePool)
hcpNodePool.TrackedResource.Resource.SystemData = doc.SystemData
hcpNodePool.TrackedResource.Tags = maps.Clone(doc.Tags)

Expand Down
2 changes: 1 addition & 1 deletion frontend/pkg/frontend/middleware_resourceid.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func MiddlewareResourceID(w http.ResponseWriter, r *http.Request, next http.Hand

resourceID, err := azcorearm.ParseResourceID(originalPath)
if err == nil {
ctx := ContextWithResourceID(r.Context(), resourceID)
ctx := ContextWithResourceID(r.Context(), &arm.ResourceID{ResourceID: *resourceID})
r = r.WithContext(ctx)
} else {
logger.Warn(fmt.Sprintf("Failed to parse '%s' as resource ID: %v", originalPath, err))
Expand Down
2 changes: 1 addition & 1 deletion frontend/pkg/frontend/middleware_resourceid_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func TestMiddlewareResourceID(t *testing.T) {
resourceTypes := []string{}
for resourceID != nil {
resourceTypes = append(resourceTypes, resourceID.ResourceType.String())
resourceID = resourceID.Parent
resourceID = resourceID.GetParent()
}

if !reflect.DeepEqual(resourceTypes, tt.resourceTypes) {
Expand Down
5 changes: 2 additions & 3 deletions frontend/pkg/frontend/ocm.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"context"
"fmt"

azcorearm "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
cmv2alpha1 "github.com/openshift-online/ocm-sdk-go/clustersmgmt/v2alpha1"
configv1 "github.com/openshift/api/config/v1"

Expand Down Expand Up @@ -42,7 +41,7 @@ func convertVisibilityToListening(visibility api.Visibility) (listening cmv2alph
}

// ConvertCStoHCPOpenShiftCluster converts a CS Cluster object into HCPOpenShiftCluster object
func ConvertCStoHCPOpenShiftCluster(resourceID *azcorearm.ResourceID, cluster *cmv2alpha1.Cluster) *api.HCPOpenShiftCluster {
func ConvertCStoHCPOpenShiftCluster(resourceID *arm.ResourceID, cluster *cmv2alpha1.Cluster) *api.HCPOpenShiftCluster {
hcpcluster := &api.HCPOpenShiftCluster{
TrackedResource: arm.TrackedResource{
Location: cluster.Region().ID(),
Expand Down Expand Up @@ -226,7 +225,7 @@ func (f *Frontend) BuildCSCluster(ctx context.Context, hcpCluster *api.HCPOpenSh
}

// ConvertCStoNodePool converts a CS Node Pool object into HCPOpenShiftClusterNodePool object
func ConvertCStoNodePool(resourceID *azcorearm.ResourceID, np *cmv2alpha1.NodePool) *api.HCPOpenShiftClusterNodePool {
func ConvertCStoNodePool(resourceID *arm.ResourceID, np *cmv2alpha1.NodePool) *api.HCPOpenShiftClusterNodePool {
nodePool := &api.HCPOpenShiftClusterNodePool{
TrackedResource: arm.TrackedResource{
Resource: arm.Resource{
Expand Down
2 changes: 1 addition & 1 deletion internal/api/arm/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,7 @@ func WriteCloudError(w http.ResponseWriter, err *CloudError) {
_ = encoder.Encode(err)
}

func WriteResourceNotFoundError(w http.ResponseWriter, resourceID *azcorearm.ResourceID) {
func WriteResourceNotFoundError(w http.ResponseWriter, resourceID *ResourceID) {
var code string
var message string

Expand Down
32 changes: 32 additions & 0 deletions internal/api/arm/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,40 @@ package arm
import (
"maps"
"time"

azcorearm "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
)

// ResourceID is a wrappered ResourceID from azcore with text marshaling and unmarshaling methods.
type ResourceID struct {
azcorearm.ResourceID
}

// GetParent returns the parent resource ID, if any. Handles the
// type-casting necessary to access the parent as a wrapper type.
func (id *ResourceID) GetParent() *ResourceID {
var parent *ResourceID
if id.Parent != nil {
parent = &ResourceID{ResourceID: *id.Parent}
}
return parent
}

// MarshalText returns a textual representation of the ResourceID.
func (id *ResourceID) MarshalText() ([]byte, error) {
return []byte(id.String()), nil
}

// UnmarshalText decodes the textual representation of a ResourceID.
func (id *ResourceID) UnmarshalText(text []byte) error {
newId, err := azcorearm.ParseResourceID(string(text))
if err != nil {
return err
}
id.ResourceID = *newId
return nil
}

// Resource represents a basic ARM resource
type Resource struct {
ID string `json:"id,omitempty"`
Expand Down
8 changes: 4 additions & 4 deletions internal/database/cache.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import (
"context"
"strings"

azcorearm "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
"github.com/Azure/ARO-HCP/internal/api/arm"
)

var _ DBClient = &Cache{}
Expand All @@ -30,7 +30,7 @@ func (c *Cache) DBConnectionTest(ctx context.Context) error {
return nil
}

func (c *Cache) GetResourceDoc(ctx context.Context, resourceID *azcorearm.ResourceID) (*ResourceDocument, error) {
func (c *Cache) GetResourceDoc(ctx context.Context, resourceID *arm.ResourceID) (*ResourceDocument, error) {
// Make sure lookup keys are lowercase.
key := strings.ToLower(resourceID.String())

Expand All @@ -43,13 +43,13 @@ func (c *Cache) GetResourceDoc(ctx context.Context, resourceID *azcorearm.Resour

func (c *Cache) SetResourceDoc(ctx context.Context, doc *ResourceDocument) error {
// Make sure lookup keys are lowercase.
key := strings.ToLower(doc.Key)
key := strings.ToLower(doc.Key.String())

c.resource[key] = doc
return nil
}

func (c *Cache) DeleteResourceDoc(ctx context.Context, resourceID *azcorearm.ResourceID) error {
func (c *Cache) DeleteResourceDoc(ctx context.Context, resourceID *arm.ResourceID) error {
// Make sure lookup keys are lowercase.
key := strings.ToLower(resourceID.String())

Expand Down
14 changes: 7 additions & 7 deletions internal/database/database.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import (
"net/http"
"strings"

azcorearm "github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"

"github.com/Azure/azure-sdk-for-go/sdk/azcore"
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
"github.com/Azure/azure-sdk-for-go/sdk/data/azcosmos"

"github.com/Azure/ARO-HCP/internal/api/arm"
)

const (
Expand All @@ -32,11 +32,11 @@ type DBClient interface {

// GetResourceDoc retrieves a ResourceDocument from the database given its resourceID.
// ErrNotFound is returned if an associated ResourceDocument cannot be found.
GetResourceDoc(ctx context.Context, resourceID *azcorearm.ResourceID) (*ResourceDocument, error)
GetResourceDoc(ctx context.Context, resourceID *arm.ResourceID) (*ResourceDocument, error)
SetResourceDoc(ctx context.Context, doc *ResourceDocument) error
// DeleteResourceDoc deletes a ResourceDocument from the database given the resourceID
// of a Microsoft.RedHatOpenShift/HcpOpenShiftClusters resource or NodePools child resource.
DeleteResourceDoc(ctx context.Context, resourceID *azcorearm.ResourceID) error
DeleteResourceDoc(ctx context.Context, resourceID *arm.ResourceID) error

GetOperationDoc(ctx context.Context, operationID string) (*OperationDocument, error)
SetOperationDoc(ctx context.Context, doc *OperationDocument) error
Expand Down Expand Up @@ -109,7 +109,7 @@ func (d *CosmosDBClient) DBConnectionTest(ctx context.Context) error {
}

// GetResourceDoc retrieves a resource document from the "resources" DB using resource ID
func (d *CosmosDBClient) GetResourceDoc(ctx context.Context, resourceID *azcorearm.ResourceID) (*ResourceDocument, error) {
func (d *CosmosDBClient) GetResourceDoc(ctx context.Context, resourceID *arm.ResourceID) (*ResourceDocument, error) {
// Make sure partition key is lowercase.
pk := azcosmos.NewPartitionKeyString(strings.ToLower(resourceID.SubscriptionID))

Expand Down Expand Up @@ -155,7 +155,7 @@ func (d *CosmosDBClient) GetResourceDoc(ctx context.Context, resourceID *azcorea
// normalize or return a toupper or tolower form of the resource
// group or resource name. The resource group name and resource
// name must come from the URL and not the request body.
doc.Key = resourceID.String()
doc.Key = resourceID
return doc, nil
}
return nil, ErrNotFound
Expand Down Expand Up @@ -185,7 +185,7 @@ func (d *CosmosDBClient) SetResourceDoc(ctx context.Context, doc *ResourceDocume
}

// DeleteResourceDoc removes a resource document from the "resources" DB using resource ID
func (d *CosmosDBClient) DeleteResourceDoc(ctx context.Context, resourceID *azcorearm.ResourceID) error {
func (d *CosmosDBClient) DeleteResourceDoc(ctx context.Context, resourceID *arm.ResourceID) error {
// Make sure partition key is lowercase.
pk := azcosmos.NewPartitionKeyString(strings.ToLower(resourceID.SubscriptionID))

Expand Down
4 changes: 2 additions & 2 deletions internal/database/document.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import (
// ARM-specific metadata for the resource.
type ResourceDocument struct {
ID string `json:"id,omitempty"`
Key string `json:"key,omitempty"`
Key *arm.ResourceID `json:"key,omitempty"`
PartitionKey string `json:"partitionKey,omitempty"`
InternalID ocm.InternalID `json:"internalId,omitempty"`
SystemData *arm.SystemData `json:"systemData,omitempty"`
Expand All @@ -31,7 +31,7 @@ type OperationDocument struct {
// Request is the type of operation requested; one of Create, Update or Delete
Request string `json:"request,omitempty"`
// ExternalID is the Azure resource ID of the cluster or node pool
ExternalID string `json:"externalId,omitempty"`
ExternalID *arm.ResourceID `json:"externalId,omitempty"`
// InternalID is the Cluster Service resource identifier in the form of a URL path
// "/cluster/{cluster_id}" or "/cluster/{cluster_id}/node_pools/{node_pool_id}"
InternalID string `json:"internalId,omitempty"`
Expand Down

0 comments on commit a322e3b

Please sign in to comment.