diff --git a/api/v1alpha1/frontend_types.go b/api/v1alpha1/frontend_types.go index cae75af7..f8d59c4f 100644 --- a/api/v1alpha1/frontend_types.go +++ b/api/v1alpha1/frontend_types.go @@ -21,6 +21,7 @@ import ( "fmt" errors "github.com/RedHatInsights/clowder/controllers/cloud.redhat.com/errors" + apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" @@ -37,16 +38,17 @@ type FrontendInfo struct { // FrontendSpec defines the desired state of Frontend type FrontendSpec struct { - EnvName string `json:"envName" yaml:"envName"` - Title string `json:"title" yaml:"title"` - DeploymentRepo string `json:"deploymentRepo" yaml:"deploymentRepo"` - API ApiInfo `json:"API" yaml:"API"` - Frontend FrontendInfo `json:"frontend" yaml:"frontend"` - Image string `json:"image,omitempty" yaml:"image,omitempty"` - Service string `json:"service,omitempty" yaml:"service,omitempty"` - Module *FedModule `json:"module,omitempty" yaml:"module,omitempty"` - NavItems []*BundleNavItem `json:"navItems,omitempty" yaml:"navItems,omitempty"` - AssetsPrefix string `json:"assetsPrefix,omitempty" yaml:"assetsPrefix,omitempty"` + EnvName string `json:"envName" yaml:"envName"` + Title string `json:"title" yaml:"title"` + DeploymentRepo string `json:"deploymentRepo" yaml:"deploymentRepo"` + API ApiInfo `json:"API" yaml:"API"` + Frontend FrontendInfo `json:"frontend" yaml:"frontend"` + Image string `json:"image,omitempty" yaml:"image,omitempty"` + Service string `json:"service,omitempty" yaml:"service,omitempty"` + Module *FedModule `json:"module,omitempty" yaml:"module,omitempty"` + NavItems []*BundleNavItem `json:"navItems,omitempty" yaml:"navItems,omitempty"` + AssetsPrefix string `json:"assetsPrefix,omitempty" yaml:"assetsPrefix,omitempty"` + CustomConfig *apiextensions.JSON `json:"customConfig,omitempty" yaml:"customConfig,omitempty"` } var ReconciliationSuccessful clusterv1.ConditionType = "ReconciliationSuccessful" @@ -66,9 +68,10 @@ type FrontendDeployments struct { } type FedModule struct { - ManifestLocation string `json:"manifestLocation" yaml:"manifestLocation"` - Modules []Module `json:"modules,omitempty" yaml:"modules,omitempty"` - ModuleID string `json:"moduleID,omitempty" yaml:"moduleID,omitempty"` + ManifestLocation string `json:"manifestLocation" yaml:"manifestLocation"` + Modules []Module `json:"modules,omitempty" yaml:"modules,omitempty"` + ModuleID string `json:"moduleID,omitempty" yaml:"moduleID,omitempty"` + Config *apiextensions.JSON `json:"config,omitempty" yaml:"config,omitempty"` } type Module struct { diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index cce4894f..dc84de35 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -22,6 +22,7 @@ limitations under the License. package v1alpha1 import ( + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" runtime "k8s.io/apimachinery/pkg/runtime" "sigs.k8s.io/cluster-api/api/v1beta1" ) @@ -296,6 +297,11 @@ func (in *FedModule) DeepCopyInto(out *FedModule) { (*in)[i].DeepCopyInto(&(*out)[i]) } } + if in.Config != nil { + in, out := &in.Config, &out.Config + *out = new(v1.JSON) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FedModule. @@ -517,6 +523,11 @@ func (in *FrontendSpec) DeepCopyInto(out *FrontendSpec) { } } } + if in.CustomConfig != nil { + in, out := &in.CustomConfig, &out.CustomConfig + *out = new(v1.JSON) + (*in).DeepCopyInto(*out) + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FrontendSpec. diff --git a/config/crd/bases/cloud.redhat.com_frontends.yaml b/config/crd/bases/cloud.redhat.com_frontends.yaml index 5fd2942f..8e499837 100644 --- a/config/crd/bases/cloud.redhat.com_frontends.yaml +++ b/config/crd/bases/cloud.redhat.com_frontends.yaml @@ -61,6 +61,8 @@ spec: type: object assetsPrefix: type: string + customConfig: + x-kubernetes-preserve-unknown-fields: true deploymentRepo: type: string envName: @@ -78,6 +80,8 @@ spec: type: string module: properties: + config: + x-kubernetes-preserve-unknown-fields: true manifestLocation: type: string moduleID: diff --git a/controllers/frontend_controller_suite_test.go b/controllers/frontend_controller_suite_test.go index dc1af1d4..f9a465be 100644 --- a/controllers/frontend_controller_suite_test.go +++ b/controllers/frontend_controller_suite_test.go @@ -11,16 +11,20 @@ import ( apps "k8s.io/api/apps/v1" v1 "k8s.io/api/core/v1" networking "k8s.io/api/networking/v1" + apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ) var _ = Describe("Frontend controller with image", func() { const ( - FrontendName = "test-frontend" - FrontendNamespace = "default" - FrontendEnvName = "test-env" - BundleName = "test-bundle" + FrontendName = "test-frontend" + FrontendNamespace = "default" + FrontendEnvName = "test-env" + FrontendName2 = "test-frontend2" + FrontendNamespace2 = "default" + FrontendEnvName2 = "test-env" + BundleName = "test-bundle" timeout = time.Second * 10 duration = time.Second * 10 @@ -32,6 +36,9 @@ var _ = Describe("Frontend controller with image", func() { By("By creating a new Frontend") ctx := context.Background() + var customConfig apiextensions.JSON + customConfig.UnmarshalJSON([]byte(`{"apple": "pie"}`)) + frontend := &crd.Frontend{ TypeMeta: metav1.TypeMeta{ APIVersion: "cloud.redhat.com/v1", @@ -67,10 +74,51 @@ var _ = Describe("Frontend controller with image", func() { }}, }}, }, + CustomConfig: &customConfig, }, } Expect(k8sClient.Create(ctx, frontend)).Should(Succeed()) + frontend2 := &crd.Frontend{ + TypeMeta: metav1.TypeMeta{ + APIVersion: "cloud.redhat.com/v1", + Kind: "Frontend", + }, + ObjectMeta: metav1.ObjectMeta{ + Name: FrontendName2, + Namespace: FrontendNamespace, + }, + Spec: crd.FrontendSpec{ + EnvName: FrontendEnvName, + Title: "", + DeploymentRepo: "", + API: crd.ApiInfo{ + Versions: []string{"v1"}, + }, + Frontend: crd.FrontendInfo{ + Paths: []string{"/things/test"}, + }, + Image: "my-image:version", + NavItems: []*crd.BundleNavItem{{ + Title: "Test", + GroupID: "", + Href: "/test/href", + }}, + Module: &crd.FedModule{ + ManifestLocation: "/apps/inventory/fed-mods.json", + Modules: []crd.Module{{ + Id: "test", + Module: "./RootApp", + Routes: []crd.Route{{ + Pathname: "/test/href", + }}, + }}, + }, + CustomConfig: &customConfig, + }, + } + Expect(k8sClient.Create(ctx, frontend2)).Should(Succeed()) + frontendEnvironment := &crd.FrontendEnvironment{ TypeMeta: metav1.TypeMeta{ APIVersion: "cloud.redhat.com/v1", @@ -99,7 +147,7 @@ var _ = Describe("Frontend controller with image", func() { Spec: crd.BundleSpec{ ID: BundleName, Title: "", - AppList: []string{FrontendName}, + AppList: []string{FrontendName, FrontendName2}, EnvName: FrontendEnvName, }, } @@ -149,8 +197,8 @@ var _ = Describe("Frontend controller with image", func() { }, timeout, interval).Should(BeTrue()) Expect(createdConfigMap.Name).Should(Equal(FrontendEnvName)) Expect(createdConfigMap.Data).Should(Equal(map[string]string{ - "fed-modules.json": "{\"testFrontend\":{\"manifestLocation\":\"/apps/inventory/fed-mods.json\",\"modules\":[{\"id\":\"test\",\"module\":\"./RootApp\",\"routes\":[{\"pathname\":\"/test/href\"}]}]}}", - "test-env.json": "{\"id\":\"test-bundle\",\"title\":\"\",\"navItems\":[{\"title\":\"Test\",\"href\":\"/test/href\"}]}", + "fed-modules.json": "{\"testFrontend\":{\"manifestLocation\":\"/apps/inventory/fed-mods.json\",\"modules\":[{\"id\":\"test\",\"module\":\"./RootApp\",\"routes\":[{\"pathname\":\"/test/href\"}]}],\"config\":{\"apple\":\"pie\"}},\"testFrontend2\":{\"manifestLocation\":\"/apps/inventory/fed-mods.json\",\"modules\":[{\"id\":\"test\",\"module\":\"./RootApp\",\"routes\":[{\"pathname\":\"/test/href\"}]}],\"config\":{\"apple\":\"pie\"}}}", + "test-env.json": "{\"id\":\"test-bundle\",\"title\":\"\",\"navItems\":[{\"title\":\"Test\",\"href\":\"/test/href\"},{\"title\":\"Test\",\"href\":\"/test/href\"}]}", })) Expect(createdConfigMap.ObjectMeta.OwnerReferences[0].Name).Should(Equal(FrontendEnvName)) createdSSOConfigMap := &v1.ConfigMap{} diff --git a/controllers/reconcile.go b/controllers/reconcile.go index c4ebbb45..fd16eeaa 100644 --- a/controllers/reconcile.go +++ b/controllers/reconcile.go @@ -50,28 +50,7 @@ func runReconciliation(context context.Context, pClient client.Client, frontend return nil } -func createFrontendDeployment(context context.Context, pClient client.Client, frontend *crd.Frontend, frontendEnvironment *crd.FrontendEnvironment, hash string, ssoHash string, cache *resCache.ObjectCache) error { - sso := frontendEnvironment.Spec.SSO - - // Create new empty struct - d := &apps.Deployment{} - - // Define name of resource - nn := types.NamespacedName{ - Name: frontend.Name, - Namespace: frontend.Namespace, - } - - // Create object in cache (will populate cache if exists) - if err := cache.Create(CoreDeployment, nn, d); err != nil { - return err - } - - // Label with the right labels - labels := frontend.GetLabels() - - labeler := utils.GetCustomLabeler(labels, nn, frontend) - labeler(d) +func populateContainer(d *apps.Deployment, frontend *crd.Frontend, frontendEnvironment *crd.FrontendEnvironment) { d.SetOwnerReferences([]metav1.OwnerReference{frontend.MakeOwnerReference()}) // Modify the obejct to set the things we care about @@ -103,10 +82,13 @@ func createFrontendDeployment(context context.Context, pClient client.Client, fr }, Env: []v1.EnvVar{{ Name: "SSO_URL", - Value: sso, + Value: frontendEnvironment.Spec.SSO, }}, }} +} + +func populateVolumes(d *apps.Deployment, frontend *crd.Frontend) { d.Spec.Template.Spec.Volumes = []v1.Volume{ { Name: "config", @@ -129,6 +111,32 @@ func createFrontendDeployment(context context.Context, pClient client.Client, fr }, }, } +} + +func createFrontendDeployment(context context.Context, pClient client.Client, frontend *crd.Frontend, frontendEnvironment *crd.FrontendEnvironment, hash string, ssoHash string, cache *resCache.ObjectCache) error { + + // Create new empty struct + d := &apps.Deployment{} + + // Define name of resource + nn := types.NamespacedName{ + Name: frontend.Name, + Namespace: frontend.Namespace, + } + + // Create object in cache (will populate cache if exists) + if err := cache.Create(CoreDeployment, nn, d); err != nil { + return err + } + + // Label with the right labels + labels := frontend.GetLabels() + + labeler := utils.GetCustomLabeler(labels, nn, frontend) + labeler(d) + + populateContainer(d, frontend, frontendEnvironment) + populateVolumes(d, frontend) d.Spec.Template.ObjectMeta.Labels = labels @@ -477,6 +485,14 @@ func createConfigConfigMap(ctx context.Context, pClient client.Client, frontend modName = frontend.Spec.Module.ModuleID } fedModules[modName] = *frontend.Spec.Module + if frontend.Spec.CustomConfig != nil { + module := fedModules[modName] + fmt.Printf("--%v\n", frontend.Spec.CustomConfig) + fmt.Printf("--%v\n", fedModules[modName].Config) + fmt.Printf("--%v\n", fedModules[modName]) + module.Config = frontend.Spec.CustomConfig + fedModules[modName] = module + } } } diff --git a/deploy.yml b/deploy.yml index 8805b5f2..d182b6c1 100644 --- a/deploy.yml +++ b/deploy.yml @@ -450,6 +450,8 @@ objects: type: object assetsPrefix: type: string + customConfig: + x-kubernetes-preserve-unknown-fields: true deploymentRepo: type: string envName: @@ -467,6 +469,8 @@ objects: type: string module: properties: + config: + x-kubernetes-preserve-unknown-fields: true manifestLocation: type: string moduleID: diff --git a/docs/antora/modules/ROOT/pages/api_reference.adoc b/docs/antora/modules/ROOT/pages/api_reference.adoc index 92d75ca4..91e6188f 100644 --- a/docs/antora/modules/ROOT/pages/api_reference.adoc +++ b/docs/antora/modules/ROOT/pages/api_reference.adoc @@ -75,7 +75,7 @@ BundleList contains a list of Bundle | *`kind`* __string__ | `BundleList` | *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#listmeta-v1-meta[$$ListMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`. -| *`items`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-bundle[$$Bundle$$]__ | +| *`items`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-bundle[$$Bundle$$] array__ | |=== @@ -104,8 +104,8 @@ BundleList contains a list of Bundle | *`product`* __string__ | | *`isExternal`* __boolean__ | | *`filterable`* __boolean__ | -| *`permissions`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-bundlepermission[$$BundlePermission$$]__ | -| *`routes`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-embeddedroute[$$EmbeddedRoute$$]__ | +| *`permissions`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-bundlepermission[$$BundlePermission$$] array__ | +| *`routes`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-embeddedroute[$$EmbeddedRoute$$] array__ | | *`expandable`* __boolean__ | | *`dynamicNav`* __string__ | |=== @@ -126,10 +126,20 @@ BundleList contains a list of Bundle |=== | Field | Description | *`method`* __string__ | -| *`args`* __string array__ | +| *`args`* __string array array__ | |=== +[id="{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-bundlepermissionargs"] +==== BundlePermissionArgs + + + +.Appears In: +**** +- xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-bundlepermission[$$BundlePermission$$] +**** + [id="{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-bundlespec"] @@ -149,8 +159,8 @@ BundleSpec defines the desired state of Bundle | *`title`* __string__ | | *`appList`* __string array__ | | *`envName`* __string__ | -| *`extraNavItems`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-extranavitem[$$ExtraNavItem$$]__ | -| *`customNav`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-bundlenavitem[$$BundleNavItem$$]__ | +| *`extraNavItems`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-extranavitem[$$ExtraNavItem$$] array__ | +| *`customNav`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-bundlenavitem[$$BundleNavItem$$] array__ | |=== @@ -213,6 +223,7 @@ EmbeddedRoutes allow deeply nested navs to have support for routes | *`manifestLocation`* __string__ | | *`modules`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-module[$$Module$$] array__ | | *`moduleID`* __string__ | +| *`config`* __JSON__ | |=== @@ -290,7 +301,7 @@ FrontendEnvironmentList contains a list of FrontendEnvironment | *`kind`* __string__ | `FrontendEnvironmentList` | *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#listmeta-v1-meta[$$ListMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`. -| *`items`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-frontendenvironment[$$FrontendEnvironment$$]__ | +| *`items`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-frontendenvironment[$$FrontendEnvironment$$] array__ | |=== @@ -347,7 +358,7 @@ FrontendList contains a list of Frontend | *`kind`* __string__ | `FrontendList` | *`metadata`* __link:https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.22/#listmeta-v1-meta[$$ListMeta$$]__ | Refer to Kubernetes API documentation for fields of `metadata`. -| *`items`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-frontend[$$Frontend$$]__ | +| *`items`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-frontend[$$Frontend$$] array__ | |=== @@ -372,8 +383,9 @@ FrontendSpec defines the desired state of Frontend | *`image`* __string__ | | *`service`* __string__ | | *`module`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-fedmodule[$$FedModule$$]__ | -| *`navItems`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-bundlenavitem[$$BundleNavItem$$]__ | +| *`navItems`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-bundlenavitem[$$BundleNavItem$$] array__ | | *`assetsPrefix`* __string__ | +| *`customConfig`* __xref:{anchor_prefix}-k8s-io-apiextensions-apiserver-pkg-apis-apiextensions-v1-json[$$JSON$$]__ | |=== @@ -401,8 +413,8 @@ FrontendSpec defines the desired state of Frontend | *`filterable`* __boolean__ | | *`expandable`* __boolean__ | | *`notifier`* __string__ | -| *`routes`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-embeddedroute[$$EmbeddedRoute$$]__ | -| *`permissions`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-bundlepermission[$$BundlePermission$$]__ | +| *`routes`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-embeddedroute[$$EmbeddedRoute$$] array__ | +| *`permissions`* __xref:{anchor_prefix}-github-com-redhatinsights-frontend-operator-api-v1alpha1-bundlepermission[$$BundlePermission$$] array__ | |===