Skip to content

Commit

Permalink
Add basic commands for UDT support
Browse files Browse the repository at this point in the history
This change adds the most basic commands for interacting with resource providers and resource types. Also added some flexibility to
existing commands for resources so they can work with UDTs.

- `rad resourceprovider`
  - `list`
  - `show`
  - `delete`

- `rad resourcetype`
  - `list`
  - `show`

Also added `rad resource create`. We never implemented anything like this, it was just missing.

Also enhanced the `rad resource` family of commands to support any fully-qualified resource type. These commands now how to validate and work with the set of built-in types in Radius today using short names like `containers`.

This set of commands are the easy decisions, and already work well using the existing functionality in the implementation. We'll add some of the more complex commands after a design dicussion.

Signed-off-by: Ryan Nowak <nowakra@gmail.com>
  • Loading branch information
rynowak committed Nov 6, 2024
1 parent e6c8911 commit 5888cd8
Show file tree
Hide file tree
Showing 27 changed files with 2,990 additions and 16 deletions.
34 changes: 34 additions & 0 deletions cmd/rad/cmd/resourceprovider.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
Copyright 2023 The Radius Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cmd

import (
"github.com/spf13/cobra"
)

func init() {
RootCmd.AddCommand(resourceProviderCmd)
resourceProviderCmd.PersistentFlags().StringP("workspace", "w", "", "The workspace name")
}

func NewResourceProviderCommand() *cobra.Command {
return &cobra.Command{
Use: "resourceprovider",
Short: "Manage resource providers",
Long: `Manage resource providers`,
}
}
34 changes: 34 additions & 0 deletions cmd/rad/cmd/resourcetype.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
Copyright 2023 The Radius Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package cmd

import (
"github.com/spf13/cobra"
)

func init() {
RootCmd.AddCommand(resourceTypeCmd)
resourceTypeCmd.PersistentFlags().StringP("workspace", "w", "", "The workspace name")
}

func NewResourceTypeCommand() *cobra.Command {
return &cobra.Command{
Use: "resourcetype",
Short: "Manage resource types",
Long: `Manage resource types`,
}
}
38 changes: 32 additions & 6 deletions cmd/rad/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,9 +53,15 @@ import (
recipe_register "github.com/radius-project/radius/pkg/cli/cmd/recipe/register"
recipe_show "github.com/radius-project/radius/pkg/cli/cmd/recipe/show"
recipe_unregister "github.com/radius-project/radius/pkg/cli/cmd/recipe/unregister"
resource_create "github.com/radius-project/radius/pkg/cli/cmd/resource/create"
resource_delete "github.com/radius-project/radius/pkg/cli/cmd/resource/delete"
resource_list "github.com/radius-project/radius/pkg/cli/cmd/resource/list"
resource_show "github.com/radius-project/radius/pkg/cli/cmd/resource/show"
resourceprovider_delete "github.com/radius-project/radius/pkg/cli/cmd/resourceprovider/delete"
resourceprovider_list "github.com/radius-project/radius/pkg/cli/cmd/resourceprovider/list"
resourceprovider_show "github.com/radius-project/radius/pkg/cli/cmd/resourceprovider/show"
resourcetype_list "github.com/radius-project/radius/pkg/cli/cmd/resourcetype/list"
resourcetype_show "github.com/radius-project/radius/pkg/cli/cmd/resourcetype/show"
"github.com/radius-project/radius/pkg/cli/cmd/run"
"github.com/radius-project/radius/pkg/cli/cmd/uninstall"
uninstall_kubernetes "github.com/radius-project/radius/pkg/cli/cmd/uninstall/kubernetes"
Expand Down Expand Up @@ -100,6 +106,8 @@ const (

var applicationCmd = NewAppCommand()
var resourceCmd = NewResourceCommand()
var resourceProviderCmd = NewResourceProviderCommand()
var resourceTypeCmd = NewResourceTypeCommand()
var recipeCmd = NewRecipeCommand()
var envCmd = NewEnvironmentCommand()
var workspaceCmd = NewWorkspaceCommand()
Expand Down Expand Up @@ -211,14 +219,32 @@ func initSubCommands() {
runCmd, _ := run.NewCommand(framework)
RootCmd.AddCommand(runCmd)

showCmd, _ := resource_show.NewCommand(framework)
resourceCmd.AddCommand(showCmd)
resourceShowCmd, _ := resource_show.NewCommand(framework)
resourceCmd.AddCommand(resourceShowCmd)

listCmd, _ := resource_list.NewCommand(framework)
resourceCmd.AddCommand(listCmd)
resourceListCmd, _ := resource_list.NewCommand(framework)
resourceCmd.AddCommand(resourceListCmd)

deleteCmd, _ := resource_delete.NewCommand(framework)
resourceCmd.AddCommand(deleteCmd)
resourceCreateCmd, _ := resource_create.NewCommand(framework)
resourceCmd.AddCommand(resourceCreateCmd)

resourceDeleteCmd, _ := resource_delete.NewCommand(framework)
resourceCmd.AddCommand(resourceDeleteCmd)

resourceProviderShowCmd, _ := resourceprovider_show.NewCommand(framework)
resourceProviderCmd.AddCommand(resourceProviderShowCmd)

resourceProviderListCmd, _ := resourceprovider_list.NewCommand(framework)
resourceProviderCmd.AddCommand(resourceProviderListCmd)

resourceProviderDeleteCmd, _ := resourceprovider_delete.NewCommand(framework)
resourceProviderCmd.AddCommand(resourceProviderDeleteCmd)

resourceTypeShowCmd, _ := resourcetype_show.NewCommand(framework)
resourceTypeCmd.AddCommand(resourceTypeShowCmd)

resourceTypeListCmd, _ := resourcetype_list.NewCommand(framework)
resourceTypeCmd.AddCommand(resourceTypeListCmd)

listRecipeCmd, _ := recipe_list.NewCommand(framework)
recipeCmd.AddCommand(listRecipeCmd)
Expand Down
21 changes: 21 additions & 0 deletions pkg/cli/clients/clients.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,9 @@ type ApplicationsManagementClient interface {
// GetResource retrieves a resource by its type and name (or id).
GetResource(ctx context.Context, resourceType string, resourceNameOrID string) (generated.GenericResource, error)

// CreateOrUpdateResource creates or updates a resource using its type name (or id).
CreateOrUpdateResource(ctx context.Context, resourceType string, resourceNameOrID string, resource *generated.GenericResource) (generated.GenericResource, error)

// DeleteResource deletes a resource by its type and name (or id).
DeleteResource(ctx context.Context, resourceType string, resourceNameOrID string) (bool, error)

Expand Down Expand Up @@ -205,6 +208,24 @@ type ApplicationsManagementClient interface {

// DeleteResourceGroup deletes a resource group by its name.
DeleteResourceGroup(ctx context.Context, planeName string, resourceGroupName string) (bool, error)

// ListResourceProviders lists all resource providers in the configured scope.
ListResourceProviders(ctx context.Context, planeName string) ([]ucp_v20231001preview.ResourceProviderResource, error)

// GetResourceProvider gets the resource provider with the specified name in the configured scope.
GetResourceProvider(ctx context.Context, planeName string, providerNamespace string) (ucp_v20231001preview.ResourceProviderResource, error)

// CreateOrUpdateResourceProvider creates or updates a resource provider in the configured scope.
CreateOrUpdateResourceProvider(ctx context.Context, planeName string, providerNamespace string, resource *ucp_v20231001preview.ResourceProviderResource) (ucp_v20231001preview.ResourceProviderResource, error)

// DeleteResourceProvider deletes a resource provider in the configured scope.
DeleteResourceProvider(ctx context.Context, planeName string, providerNamespace string) (bool, error)

// ListResourceProviderSummaries list the summary data of all resource providers in the configured scope.
ListResourceProviderSummaries(ctx context.Context, planeName string) ([]ucp_v20231001preview.ResourceProviderSummary, error)

// GetResourceProviderSummary gets the resource provider summary with the specified name in the configured scope.
GetResourceProviderSummary(ctx context.Context, planeName string, providerNamespace string) (ucp_v20231001preview.ResourceProviderSummary, error)
}

// ShallowCopy creates a shallow copy of the DeploymentParameters object by iterating through the original object and
Expand Down
153 changes: 153 additions & 0 deletions pkg/cli/clients/management.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ type UCPApplicationsManagementClient struct {
applicationResourceClientFactory func(scope string) (applicationResourceClient, error)
environmentResourceClientFactory func(scope string) (environmentResourceClient, error)
resourceGroupClientFactory func() (resourceGroupClient, error)
resourceProviderClientFactory func() (resourceProviderClient, error)
capture func(ctx context.Context, capture **http.Response) context.Context
}

Expand Down Expand Up @@ -196,6 +197,31 @@ func (amc *UCPApplicationsManagementClient) GetResource(ctx context.Context, res
return getResponse.GenericResource, nil
}

// CreateOrUpdateResource creates or updates a resource using its type name (or id).
func (amc *UCPApplicationsManagementClient) CreateOrUpdateResource(ctx context.Context, resourceType string, resourceNameOrID string, resource *generated.GenericResource) (generated.GenericResource, error) {
scope, name, err := amc.extractScopeAndName(resourceNameOrID)
if err != nil {
return generated.GenericResource{}, err
}

client, err := amc.createGenericClient(scope, resourceType)
if err != nil {
return generated.GenericResource{}, err
}

poller, err := client.BeginCreateOrUpdate(ctx, name, *resource, &generated.GenericResourcesClientBeginCreateOrUpdateOptions{})
if err != nil {
return generated.GenericResource{}, err
}

response, err := poller.PollUntilDone(ctx, nil)
if err != nil {
return generated.GenericResource{}, err
}

return response.GenericResource, nil
}

// DeleteResource deletes a resource by its type and name (or id).
func (amc *UCPApplicationsManagementClient) DeleteResource(ctx context.Context, resourceType string, resourceNameOrID string) (bool, error) {
scope, name, err := amc.extractScopeAndName(resourceNameOrID)
Expand Down Expand Up @@ -656,6 +682,125 @@ func (amc *UCPApplicationsManagementClient) DeleteResourceGroup(ctx context.Cont
return response.StatusCode != 204, nil
}

// ListResourceProviders lists all resource providers in the configured scope.
func (amc *UCPApplicationsManagementClient) ListResourceProviders(ctx context.Context, planeName string) ([]ucpv20231001.ResourceProviderResource, error) {
client, err := amc.createResourceProviderClient()
if err != nil {
return nil, err
}

results := []ucpv20231001.ResourceProviderResource{}
pager := client.NewListPager(planeName, &ucpv20231001.ResourceProvidersClientListOptions{})
for pager.More() {
page, err := pager.NextPage(ctx)
if err != nil {
return nil, err
}

for _, resourceGroup := range page.Value {
results = append(results, *resourceGroup)
}
}

return results, nil
}

// GetResourceProvider gets the resource provider with the specified name in the configured scope.
func (amc *UCPApplicationsManagementClient) GetResourceProvider(ctx context.Context, planeName string, providerNamespace string) (ucpv20231001.ResourceProviderResource, error) {
client, err := amc.createResourceProviderClient()
if err != nil {
return ucpv20231001.ResourceProviderResource{}, err
}

response, err := client.Get(ctx, planeName, providerNamespace, &ucpv20231001.ResourceProvidersClientGetOptions{})
if err != nil {
return ucpv20231001.ResourceProviderResource{}, err
}

return response.ResourceProviderResource, nil
}

// CreateOrUpdateResourceProvider creates or updates a resource provider in the configured scope.
func (amc *UCPApplicationsManagementClient) CreateOrUpdateResourceProvider(ctx context.Context, planeName string, providerNamespace string, resource *ucpv20231001.ResourceProviderResource) (ucpv20231001.ResourceProviderResource, error) {
client, err := amc.createResourceProviderClient()
if err != nil {
return ucpv20231001.ResourceProviderResource{}, err
}

poller, err := client.BeginCreateOrUpdate(ctx, planeName, providerNamespace, *resource, &ucpv20231001.ResourceProvidersClientBeginCreateOrUpdateOptions{})
if err != nil {
return ucpv20231001.ResourceProviderResource{}, err
}

response, err := poller.PollUntilDone(ctx, nil)
if err != nil {
return ucpv20231001.ResourceProviderResource{}, err
}

return response.ResourceProviderResource, nil
}

// DeleteResourceProvider deletes a resource provider in the configured scope.
func (amc *UCPApplicationsManagementClient) DeleteResourceProvider(ctx context.Context, planeName string, providerNamespace string) (bool, error) {
client, err := amc.createResourceProviderClient()
if err != nil {
return false, err
}

var response *http.Response
ctx = amc.captureResponse(ctx, &response)

poller, err := client.BeginDelete(ctx, planeName, providerNamespace, &ucpv20231001.ResourceProvidersClientBeginDeleteOptions{})
if err != nil {
return false, err
}

_, err = poller.PollUntilDone(ctx, nil)
if err != nil {
return false, err
}

return response.StatusCode != 204, nil
}

// ListResourceProviderSummaries lists all resource provider summaries in the configured scope.
func (amc *UCPApplicationsManagementClient) ListResourceProviderSummaries(ctx context.Context, planeName string) ([]ucpv20231001.ResourceProviderSummary, error) {
client, err := amc.createResourceProviderClient()
if err != nil {
return nil, err
}

results := []ucpv20231001.ResourceProviderSummary{}
pager := client.NewListProviderSummariesPager(planeName, &ucpv20231001.ResourceProvidersClientListProviderSummariesOptions{})
for pager.More() {
page, err := pager.NextPage(ctx)
if err != nil {
return nil, err
}

for _, summary := range page.Value {
results = append(results, *summary)
}
}

return results, nil
}

// GetResourceProvider gets the resource provider summary with the specified name in the configured scope.
func (amc *UCPApplicationsManagementClient) GetResourceProviderSummary(ctx context.Context, planeName string, providerNamespace string) (ucpv20231001.ResourceProviderSummary, error) {
client, err := amc.createResourceProviderClient()
if err != nil {
return ucpv20231001.ResourceProviderSummary{}, err
}

response, err := client.GetProviderSummary(ctx, planeName, providerNamespace, &ucpv20231001.ResourceProvidersClientGetProviderSummaryOptions{})
if err != nil {
return ucpv20231001.ResourceProviderSummary{}, err
}

return response.ResourceProviderSummary, nil
}

func (amc *UCPApplicationsManagementClient) createApplicationClient(scope string) (applicationResourceClient, error) {
if amc.applicationResourceClientFactory == nil {
// Generated client doesn't like the leading '/' in the scope.
Expand Down Expand Up @@ -691,6 +836,14 @@ func (amc *UCPApplicationsManagementClient) createResourceGroupClient() (resourc
return amc.resourceGroupClientFactory()
}

func (amc *UCPApplicationsManagementClient) createResourceProviderClient() (resourceProviderClient, error) {
if amc.resourceProviderClientFactory == nil {
return ucpv20231001.NewResourceProvidersClient(&aztoken.AnonymousCredential{}, amc.ClientOptions)
}

return amc.resourceProviderClientFactory()
}

func (amc *UCPApplicationsManagementClient) extractScopeAndName(nameOrID string) (string, string, error) {
if strings.HasPrefix(nameOrID, resources.SegmentSeparator) {
// Treat this as a resource id.
Expand Down
12 changes: 11 additions & 1 deletion pkg/cli/clients/management_mocks.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import (
// Because these interfaces are non-exported, they MUST be defined in their own file
// and we MUST use -source on mockgen to generate mocks for them.

//go:generate mockgen -typed -source=./management_mocks.go -destination=./mock_management_wrapped_clients.go -package=clients -self_package github.com/radius-project/radius/pkg/cli/clients github.com/radius-project/radius/pkg/cli/clients genericResourceClient,applicationResourceClient,environmentResourceClient,resourceGroupClient
//go:generate mockgen -typed -source=./management_mocks.go -destination=./mock_management_wrapped_clients.go -package=clients -self_package github.com/radius-project/radius/pkg/cli/clients github.com/radius-project/radius/pkg/cli/clients genericResourceClient,applicationResourceClient,environmentResourceClient,resourceGroupClient,resourceProviderClient

// genericResourceClient is an interface for mocking the generated SDK client for any resource.
type genericResourceClient interface {
Expand Down Expand Up @@ -71,3 +71,13 @@ type resourceGroupClient interface {
Get(ctx context.Context, planeName string, resourceGroupName string, options *ucpv20231001.ResourceGroupsClientGetOptions) (ucpv20231001.ResourceGroupsClientGetResponse, error)
NewListPager(planeName string, options *ucpv20231001.ResourceGroupsClientListOptions) *runtime.Pager[ucpv20231001.ResourceGroupsClientListResponse]
}

// resourceProviderClient is an interface for mocking the generated SDK client for resource providers.
type resourceProviderClient interface {
BeginCreateOrUpdate(ctx context.Context, planeName string, resourceProviderName string, resource ucpv20231001.ResourceProviderResource, options *ucpv20231001.ResourceProvidersClientBeginCreateOrUpdateOptions) (*runtime.Poller[ucpv20231001.ResourceProvidersClientCreateOrUpdateResponse], error)
BeginDelete(ctx context.Context, planeName string, resourceProviderName string, options *ucpv20231001.ResourceProvidersClientBeginDeleteOptions) (*runtime.Poller[ucpv20231001.ResourceProvidersClientDeleteResponse], error)
Get(ctx context.Context, planeName string, resourceProviderName string, options *ucpv20231001.ResourceProvidersClientGetOptions) (ucpv20231001.ResourceProvidersClientGetResponse, error)
NewListPager(planeName string, options *ucpv20231001.ResourceProvidersClientListOptions) *runtime.Pager[ucpv20231001.ResourceProvidersClientListResponse]
GetProviderSummary(ctx context.Context, planeName string, resourceProviderName string, options *ucpv20231001.ResourceProvidersClientGetProviderSummaryOptions) (ucpv20231001.ResourceProvidersClientGetProviderSummaryResponse, error)
NewListProviderSummariesPager(planeName string, options *ucpv20231001.ResourceProvidersClientListProviderSummariesOptions) *runtime.Pager[ucpv20231001.ResourceProvidersClientListProviderSummariesResponse]
}
Loading

0 comments on commit 5888cd8

Please sign in to comment.