diff --git a/pkg/daprrp/processors/pubsubbrokers/processor.go b/pkg/daprrp/processors/pubsubbrokers/processor.go index a095416ca9..597246d2c8 100644 --- a/pkg/daprrp/processors/pubsubbrokers/processor.go +++ b/pkg/daprrp/processors/pubsubbrokers/processor.go @@ -63,7 +63,7 @@ func (p *Processor) Process(ctx context.Context, resource *datamodel.DaprPubSubB // Let's do this now. applicationID, err := resources.ParseResource(resource.Properties.Application) - if err != nil { + if err != nil && resource.Properties.Application != "" { return err // This should already be validated by this point. } @@ -114,7 +114,7 @@ func (p *Processor) Delete(ctx context.Context, resource *datamodel.DaprPubSubBr } applicationID, err := resources.ParseResource(resource.Properties.Application) - if err != nil { + if err != nil && resource.Properties.Application != "" { return err // This should already be validated by this point. } diff --git a/pkg/daprrp/processors/pubsubbrokers/processor_test.go b/pkg/daprrp/processors/pubsubbrokers/processor_test.go index c4397b46c4..ab9d6780cb 100644 --- a/pkg/daprrp/processors/pubsubbrokers/processor_test.go +++ b/pkg/daprrp/processors/pubsubbrokers/processor_test.go @@ -205,6 +205,95 @@ func Test_Process(t *testing.T) { require.Equal(t, []unstructured.Unstructured{*generated}, components.Items) }) + t.Run("success - manual (no application)", func(t *testing.T) { + processor := Processor{ + Client: k8sutil.NewFakeKubeClient(scheme.Scheme, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace"}}), + } + + resource := &datamodel.DaprPubSubBroker{ + BaseResource: v1.BaseResource{ + TrackedResource: v1.TrackedResource{ + Name: "some-other-name", + }, + }, + Properties: datamodel.DaprPubSubBrokerProperties{ + BasicResourceProperties: rpv1.BasicResourceProperties{ + Environment: envID, + }, + BasicDaprResourceProperties: rpv1.BasicDaprResourceProperties{ + ComponentName: componentName, + }, + ResourceProvisioning: portableresources.ResourceProvisioningManual, + Metadata: map[string]any{ + "config": "extrasecure", + }, + Resources: []*portableresources.ResourceReference{{ID: externalResourceID1}}, + Type: "pubsub.redis", + Version: "v1", + }, + } + + options := processors.Options{ + RuntimeConfiguration: recipes.RuntimeConfiguration{ + Kubernetes: &recipes.KubernetesRuntime{ + Namespace: "test-namespace", + }, + }, + } + + err := processor.Process(context.Background(), resource, options) + require.NoError(t, err) + + require.Equal(t, componentName, resource.Properties.ComponentName) + + expectedValues := map[string]any{ + "componentName": componentName, + } + expectedSecrets := map[string]rpv1.SecretValueReference{} + + expectedOutputResources, err := processors.GetOutputResourcesFromResourcesField(resource.Properties.Resources) + + generated := &unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": dapr.DaprAPIVersion, + "kind": dapr.DaprKind, + "metadata": map[string]any{ + "namespace": "test-namespace", + "name": "test-dapr-pubsub-broker", + "labels": kubernetes.MakeDescriptiveDaprLabels("", "some-other-name", portableresources.DaprPubSubBrokersResourceType), + "resourceVersion": "1", + }, + "spec": map[string]any{ + "type": "pubsub.redis", + "version": "v1", + "metadata": []any{ + map[string]any{ + "name": "config", + "value": "extrasecure", + }, + }, + }, + }, + } + + component := rpv1.NewKubernetesOutputResource("Component", generated, metav1.ObjectMeta{Name: generated.GetName(), Namespace: generated.GetNamespace()}) + component.RadiusManaged = to.Ptr(true) + expectedOutputResources = append(expectedOutputResources, component) + require.NoError(t, err) + + require.Equal(t, expectedValues, resource.ComputedValues) + require.Equal(t, expectedSecrets, resource.SecretValues) + require.Equal(t, expectedOutputResources, resource.Properties.Status.OutputResources) + + components := unstructured.UnstructuredList{} + components.SetAPIVersion("dapr.io/v1alpha1") + components.SetKind("Component") + err = processor.Client.List(context.Background(), &components, &client.ListOptions{Namespace: options.RuntimeConfiguration.Kubernetes.Namespace}) + require.NoError(t, err) + require.NotEmpty(t, components.Items) + require.Equal(t, []unstructured.Unstructured{*generated}, components.Items) + }) + t.Run("success - recipe with overrides", func(t *testing.T) { processor := Processor{ Client: k8sutil.NewFakeKubeClient(scheme.Scheme), diff --git a/pkg/daprrp/processors/secretstores/processor.go b/pkg/daprrp/processors/secretstores/processor.go index 7153006db2..a8ab999816 100644 --- a/pkg/daprrp/processors/secretstores/processor.go +++ b/pkg/daprrp/processors/secretstores/processor.go @@ -60,7 +60,7 @@ func (p *Processor) Process(ctx context.Context, resource *datamodel.DaprSecretS // Let's do this now. applicationID, err := resources.ParseResource(resource.Properties.Application) - if err != nil { + if err != nil && resource.Properties.Application != "" { return err // This should already be validated by this point. } @@ -111,7 +111,7 @@ func (p *Processor) Delete(ctx context.Context, resource *datamodel.DaprSecretSt } applicationID, err := resources.ParseResource(resource.Properties.Application) - if err != nil { + if err != nil && resource.Properties.Application != "" { return err // This should already be validated by this point. } diff --git a/pkg/daprrp/processors/secretstores/processor_test.go b/pkg/daprrp/processors/secretstores/processor_test.go index e5eedf30c5..a1b15ba870 100644 --- a/pkg/daprrp/processors/secretstores/processor_test.go +++ b/pkg/daprrp/processors/secretstores/processor_test.go @@ -42,6 +42,7 @@ import ( func Test_Process(t *testing.T) { const kubernetesResource = "/planes/kubernetes/local/namespaces/test-namespace/providers/dapr.io/Component/test-component" const applicationID = "/planes/radius/local/resourceGroups/test-rg/providers/Applications.Core/applications/test-app" + const envID = "/planes/radius/local/resourceGroups/test-rg/providers/Applications.Core/environments/test-env" const componentName = "test-component" t.Run("success - recipe", func(t *testing.T) { @@ -189,6 +190,89 @@ func Test_Process(t *testing.T) { require.Equal(t, []unstructured.Unstructured{*generated}, components.Items) }) + t.Run("success - values (no application)", func(t *testing.T) { + processor := Processor{ + Client: k8sutil.NewFakeKubeClient(scheme.Scheme, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace"}}), + } + + resource := &datamodel.DaprSecretStore{ + BaseResource: v1.BaseResource{ + TrackedResource: v1.TrackedResource{ + Name: "some-other-name", + }, + }, + Properties: datamodel.DaprSecretStoreProperties{ + BasicResourceProperties: rpv1.BasicResourceProperties{ + Environment: envID, + }, + BasicDaprResourceProperties: rpv1.BasicDaprResourceProperties{ + ComponentName: componentName, + }, + ResourceProvisioning: portableresources.ResourceProvisioningManual, + Metadata: map[string]any{"config": "extrasecure"}, + Type: "secretstores.kubernetes", + Version: "v1", + }, + } + + options := processors.Options{ + RuntimeConfiguration: recipes.RuntimeConfiguration{ + Kubernetes: &recipes.KubernetesRuntime{ + Namespace: "test-namespace", + }, + }, + } + + err := processor.Process(context.Background(), resource, options) + require.NoError(t, err) + + require.Equal(t, componentName, resource.Properties.ComponentName) + + expectedValues := map[string]any{ + "componentName": componentName, + } + expectedSecrets := map[string]rpv1.SecretValueReference{} + generated := &unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": dapr.DaprAPIVersion, + "kind": dapr.DaprKind, + "metadata": map[string]any{ + "namespace": "test-namespace", + "name": "test-component", + "labels": kubernetes.MakeDescriptiveDaprLabels("", "some-other-name", portableresources.DaprSecretStoresResourceType), + "resourceVersion": "1", + }, + "spec": map[string]any{ + "type": "secretstores.kubernetes", + "version": "v1", + "metadata": []any{ + map[string]any{ + "name": "config", + "value": "extrasecure", + }, + }, + }, + }, + } + + component := rpv1.NewKubernetesOutputResource("Component", generated, metav1.ObjectMeta{Name: generated.GetName(), Namespace: generated.GetNamespace()}) + component.RadiusManaged = to.Ptr(true) + expectedOutputResources := []rpv1.OutputResource{component} + require.NoError(t, err) + + require.Equal(t, expectedValues, resource.ComputedValues) + require.Equal(t, expectedSecrets, resource.SecretValues) + require.Equal(t, expectedOutputResources, resource.Properties.Status.OutputResources) + + components := unstructured.UnstructuredList{} + components.SetAPIVersion("dapr.io/v1alpha1") + components.SetKind("Component") + err = processor.Client.List(context.Background(), &components, &client.ListOptions{Namespace: options.RuntimeConfiguration.Kubernetes.Namespace}) + require.NoError(t, err) + require.NotEmpty(t, components.Items) + require.Equal(t, []unstructured.Unstructured{*generated}, components.Items) + }) + t.Run("success - recipe with value overrides", func(t *testing.T) { processor := Processor{ Client: k8sutil.NewFakeKubeClient(scheme.Scheme), diff --git a/pkg/daprrp/processors/statestores/processor.go b/pkg/daprrp/processors/statestores/processor.go index 5275e92864..03fdaf391f 100644 --- a/pkg/daprrp/processors/statestores/processor.go +++ b/pkg/daprrp/processors/statestores/processor.go @@ -63,7 +63,7 @@ func (p *Processor) Process(ctx context.Context, resource *datamodel.DaprStateSt // Let's do this now. applicationID, err := resources.ParseResource(resource.Properties.Application) - if err != nil { + if err != nil && resource.Properties.Application != "" { return err // This should already be validated by this point. } @@ -114,7 +114,7 @@ func (p *Processor) Delete(ctx context.Context, resource *datamodel.DaprStateSto } applicationID, err := resources.ParseResource(resource.Properties.Application) - if err != nil { + if err != nil && resource.Properties.Application != "" { return err // This should already be validated by this point. } diff --git a/pkg/daprrp/processors/statestores/processor_test.go b/pkg/daprrp/processors/statestores/processor_test.go index ddb228d04f..3c930b3939 100644 --- a/pkg/daprrp/processors/statestores/processor_test.go +++ b/pkg/daprrp/processors/statestores/processor_test.go @@ -45,6 +45,7 @@ func Test_Process(t *testing.T) { const externalResourceID2 = "/subscriptions/0000/resourceGroups/test-group/providers/Microsoft.Cache/redis/myredis2" const kubernetesResource = "/planes/kubernetes/local/namespaces/test-namespace/providers/dapr.io/Component/test-component" const applicationID = "/planes/radius/local/resourceGroups/test-rg/providers/Applications.Core/applications/test-app" + const envID = "/planes/radius/local/resourceGroups/test-rg/providers/Applications.Core/environments/test-env" const componentName = "test-component" t.Run("success - recipe", func(t *testing.T) { @@ -197,6 +198,93 @@ func Test_Process(t *testing.T) { require.Equal(t, []unstructured.Unstructured{*generated}, components.Items) }) + t.Run("success - manual (no application)", func(t *testing.T) { + processor := Processor{ + Client: k8sutil.NewFakeKubeClient(scheme.Scheme, &corev1.Namespace{ObjectMeta: metav1.ObjectMeta{Name: "test-namespace"}}), + } + + resource := &datamodel.DaprStateStore{ + BaseResource: v1.BaseResource{ + TrackedResource: v1.TrackedResource{ + Name: "some-other-name", + }, + }, + Properties: datamodel.DaprStateStoreProperties{ + BasicResourceProperties: rpv1.BasicResourceProperties{ + Environment: envID, + }, + BasicDaprResourceProperties: rpv1.BasicDaprResourceProperties{ + ComponentName: componentName, + }, + ResourceProvisioning: portableresources.ResourceProvisioningManual, + Metadata: map[string]any{"config": "extrasecure"}, + Resources: []*portableresources.ResourceReference{{ID: externalResourceID1}}, + Type: "state.redis", + Version: "v1", + }, + } + + options := processors.Options{ + RuntimeConfiguration: recipes.RuntimeConfiguration{ + Kubernetes: &recipes.KubernetesRuntime{ + Namespace: "test-namespace", + }, + }, + } + + err := processor.Process(context.Background(), resource, options) + require.NoError(t, err) + + require.Equal(t, componentName, resource.Properties.ComponentName) + + expectedValues := map[string]any{ + "componentName": componentName, + } + expectedSecrets := map[string]rpv1.SecretValueReference{} + + expectedOutputResources, err := processors.GetOutputResourcesFromResourcesField(resource.Properties.Resources) + + generated := &unstructured.Unstructured{ + Object: map[string]any{ + "apiVersion": dapr.DaprAPIVersion, + "kind": dapr.DaprKind, + "metadata": map[string]any{ + "namespace": "test-namespace", + "name": "test-component", + "labels": kubernetes.MakeDescriptiveDaprLabels("", "some-other-name", portableresources.DaprStateStoresResourceType), + "resourceVersion": "1", + }, + "spec": map[string]any{ + "type": "state.redis", + "version": "v1", + "metadata": []any{ + map[string]any{ + "name": "config", + "value": "extrasecure", + }, + }, + }, + }, + } + + component := rpv1.NewKubernetesOutputResource("Component", generated, metav1.ObjectMeta{Name: generated.GetName(), Namespace: generated.GetNamespace()}) + component.RadiusManaged = to.Ptr(true) + expectedOutputResources = append(expectedOutputResources, component) + require.NoError(t, err) + + require.Equal(t, expectedValues, resource.ComputedValues) + require.Equal(t, expectedSecrets, resource.SecretValues) + require.Equal(t, expectedOutputResources, resource.Properties.Status.OutputResources) + + components := unstructured.UnstructuredList{} + components.SetAPIVersion("dapr.io/v1alpha1") + components.SetKind("Component") + err = processor.Client.List(context.Background(), &components, &client.ListOptions{Namespace: options.RuntimeConfiguration.Kubernetes.Namespace}) + require.NoError(t, err) + require.NotEmpty(t, components.Items) + require.Equal(t, []unstructured.Unstructured{*generated}, components.Items) + }) + t.Run("success - recipe with value overrides", func(t *testing.T) { processor := Processor{ Client: k8sutil.NewFakeKubeClient(scheme.Scheme),