From 43742e5d99ecfd8223d0cd6185207e0aa62d212a Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Fri, 31 May 2024 11:16:27 +0200 Subject: [PATCH 01/23] improvements --- internal/api/api.go | 16 +++++++++++----- ui/pkg/sumdb/sum.golang.org/latest | 5 +++++ ui/src/components/SecretsView.tsx | 20 +++++++++++++++++--- ui/src/components/ServiceInstancesView.tsx | 7 +++++-- ui/src/components/ServiceOfferingsView.tsx | 15 +++++++++------ ui/src/shared/api.tsx | 3 ++- 6 files changed, 49 insertions(+), 17 deletions(-) create mode 100644 ui/pkg/sumdb/sum.golang.org/latest diff --git a/internal/api/api.go b/internal/api/api.go index 037aac4f1..8f857c40e 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -8,20 +8,26 @@ import ( "log/slog" + "fmt" "github.com/kyma-project/btp-manager/internal/api/vm" clusterobject "github.com/kyma-project/btp-manager/internal/cluster-object" servicemanager "github.com/kyma-project/btp-manager/internal/service-manager" ) +var ( + apiPort = 0 +) + type API struct { serviceManager *servicemanager.Client secretProvider *clusterobject.SecretProvider - slogger *slog.Logger + slog *slog.Logger } func NewAPI(serviceManager *servicemanager.Client, secretProvider *clusterobject.SecretProvider) *API { - slogger := slog.Default() - return &API{serviceManager: serviceManager, secretProvider: secretProvider, slogger: slogger} + slog := slog.Default() + apiPort = getFreePort() + return &API{serviceManager: serviceManager, secretProvider: secretProvider, slog: slog} } func (a *API) Start() { @@ -33,9 +39,9 @@ func (a *API) Start() { mux.HandleFunc("GET /api/service-offerings/{namespace}/{name}", a.ListServiceOfferings) mux.HandleFunc("GET /api/service-offering/{id}", a.GetServiceOffering) go func() { - err := http.ListenAndServe(":3006", nil) + err := http.ListenAndServe(fmt.Sprintf(":%d", apiPort), nil) if err != nil { - a.slogger.Error("failed to Start listening", "error", err) + a.slog.Error("failed to Start listening", "error", err) } }() } diff --git a/ui/pkg/sumdb/sum.golang.org/latest b/ui/pkg/sumdb/sum.golang.org/latest new file mode 100644 index 000000000..df5df294e --- /dev/null +++ b/ui/pkg/sumdb/sum.golang.org/latest @@ -0,0 +1,5 @@ +go.sum database tree +25169615 +l3M8lJVDV2EToEmKf5iGj0emA8PRakjZsjaskhCQtXo= + +— sum.golang.org Az3grpkMN5x46aNzLchq5f/LYNiVWO/11Dr+88NB7ZvI2o77RKgB6xKr9i0iqlA26hFkDYYqMsx5q0VrtRbkHHz3HAM= diff --git a/ui/src/components/SecretsView.tsx b/ui/src/components/SecretsView.tsx index 0bf734d80..95a713107 100644 --- a/ui/src/components/SecretsView.tsx +++ b/ui/src/components/SecretsView.tsx @@ -10,6 +10,7 @@ function SecretsView(props: any) { const [error, setError] = useState(null); useEffect(() => { + setLoading(true); axios .get(api("secrets")) .then((response) => { @@ -23,8 +24,10 @@ function SecretsView(props: any) { ); }) .catch((error) => { - setError(error); setLoading(false); + props.handler( + formatDisplay("","") + ); }); }, []); @@ -33,13 +36,21 @@ function SecretsView(props: any) { } if (error) { - return Error: {error}; + props.handler( + formatDisplay("","") + ); + return } const renderData = () => { + if (!secrets) { + console.log(secrets); + return {formatDisplay("", "")} + } + return secrets?.items.map((s, i) => { return ( - {formatDisplay(s.name, s.namespace)} + {formatDisplay(s.name, s.namespace)} ); }); }; @@ -64,6 +75,9 @@ function SecretsView(props: any) { } function formatDisplay(secretName: string, secretNamespace: string) { + if (!secretName || !secretNamespace) { + return "No secret found" + } return `${secretName} in (${secretNamespace})`; } diff --git a/ui/src/components/ServiceInstancesView.tsx b/ui/src/components/ServiceInstancesView.tsx index 1a89c0f82..86f8b3af8 100644 --- a/ui/src/components/ServiceInstancesView.tsx +++ b/ui/src/components/ServiceInstancesView.tsx @@ -34,14 +34,17 @@ function ServiceInstancesView() { }, []); if (loading) { - return + return } if (error) { - return Error: {error}; + return } const renderData = () => { + if (!serviceInstances) { + return + } return serviceInstances?.items.map((brief, index) => { return ( <> diff --git a/ui/src/components/ServiceOfferingsView.tsx b/ui/src/components/ServiceOfferingsView.tsx index 82a8b714a..fed7bc239 100644 --- a/ui/src/components/ServiceOfferingsView.tsx +++ b/ui/src/components/ServiceOfferingsView.tsx @@ -6,7 +6,7 @@ import axios from "axios"; import { ServiceOfferingDetails, ServiceOfferings } from "../shared/models"; import ts from "typescript"; import api from "../shared/api"; - +import "@ui5/webcomponents-fiori/dist/illustrations/AllIllustrations.js" function ServiceOfferingsView(props: any) { const [offerings, setOfferings] = useState(); const [serviceOfferingDetails, setServiceOfferingDetails] = @@ -26,6 +26,9 @@ function ServiceOfferingsView(props: any) { }; useEffect(() => { + if (props.secret == null) { + return; + } const splited = splitSecret(props.secret); if (splited) { setLoading(true); @@ -51,10 +54,6 @@ function ServiceOfferingsView(props: any) { return } - if (error) { - return Error: {error}; - } - function getImg(b64: string) { if (b64 == null) { return ""; @@ -78,7 +77,11 @@ function ServiceOfferingsView(props: any) { } const renderData = () => { - return offerings?.items.map((offering, index) => { + if (!offerings) { + console.log(offerings); + return + } + return offerings?.items.map((offering, index) => { return ( <> Date: Wed, 29 May 2024 12:36:26 +0200 Subject: [PATCH 02/23] gomod(deps): bump sigs.k8s.io/controller-runtime from 0.18.2 to 0.18.3 (#710) Bumps [sigs.k8s.io/controller-runtime](https://github.com/kubernetes-sigs/controller-runtime) from 0.18.2 to 0.18.3. - [Release notes](https://github.com/kubernetes-sigs/controller-runtime/releases) - [Changelog](https://github.com/kubernetes-sigs/controller-runtime/blob/main/RELEASE.md) - [Commits](https://github.com/kubernetes-sigs/controller-runtime/compare/v0.18.2...v0.18.3) --- updated-dependencies: - dependency-name: sigs.k8s.io/controller-runtime dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 593e81a7e..84f2a6def 100644 --- a/go.mod +++ b/go.mod @@ -15,7 +15,7 @@ require ( k8s.io/apiextensions-apiserver v0.30.1 k8s.io/apimachinery v0.30.1 k8s.io/client-go v0.30.1 - sigs.k8s.io/controller-runtime v0.18.2 + sigs.k8s.io/controller-runtime v0.18.3 ) require ( diff --git a/go.sum b/go.sum index 352a35869..1f37f3a83 100644 --- a/go.sum +++ b/go.sum @@ -165,8 +165,8 @@ k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108 h1:Q8Z7VlGhcJgBHJHYugJ/K/ k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 h1:ao5hUqGhsqdm+bYbjH/pRkCs0unBGe9UyDahzs9zQzQ= k8s.io/utils v0.0.0-20240423183400-0849a56e8f22/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.18.2 h1:RqVW6Kpeaji67CY5nPEfRz6ZfFMk0lWQlNrLqlNpx+Q= -sigs.k8s.io/controller-runtime v0.18.2/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw= +sigs.k8s.io/controller-runtime v0.18.3 h1:B5Wmmo8WMWK7izei+2LlXLVDGzMwAHBNLX68lwtlSR4= +sigs.k8s.io/controller-runtime v0.18.3/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= From c182eebc402171f96ca9c64a25c9f0697a85b510 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 29 May 2024 13:04:26 +0200 Subject: [PATCH 03/23] gomod(deps): bump github.com/onsi/ginkgo/v2 from 2.18.0 to 2.19.0 (#709) Bumps [github.com/onsi/ginkgo/v2](https://github.com/onsi/ginkgo) from 2.18.0 to 2.19.0. - [Release notes](https://github.com/onsi/ginkgo/releases) - [Changelog](https://github.com/onsi/ginkgo/blob/master/CHANGELOG.md) - [Commits](https://github.com/onsi/ginkgo/compare/v2.18.0...v2.19.0) --- updated-dependencies: - dependency-name: github.com/onsi/ginkgo/v2 dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 84f2a6def..335988e54 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.22.3 require ( github.com/go-logr/logr v1.4.2 - github.com/onsi/ginkgo/v2 v2.18.0 + github.com/onsi/ginkgo/v2 v2.19.0 github.com/onsi/gomega v1.33.1 github.com/prometheus/client_golang v1.19.1 github.com/stretchr/testify v1.9.0 diff --git a/go.sum b/go.sum index 1f37f3a83..c471c7c68 100644 --- a/go.sum +++ b/go.sum @@ -64,8 +64,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.18.0 h1:W9Y7IWXxPUpAit9ieMOLI7PJZGaW22DTKgiVAuhDTLc= -github.com/onsi/ginkgo/v2 v2.18.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= +github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= From ff7348f2f3bc02d778acafae24ddd58d5d6bb3ca Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Fri, 31 May 2024 12:12:03 +0200 Subject: [PATCH 04/23] wip --- internal/api/api.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/internal/api/api.go b/internal/api/api.go index 8f857c40e..2da8b84b7 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -9,6 +9,10 @@ import ( "log/slog" "fmt" + + "net" + "os" + "github.com/kyma-project/btp-manager/internal/api/vm" clusterobject "github.com/kyma-project/btp-manager/internal/cluster-object" servicemanager "github.com/kyma-project/btp-manager/internal/service-manager" @@ -30,6 +34,22 @@ func NewAPI(serviceManager *servicemanager.Client, secretProvider *clusterobject return &API{serviceManager: serviceManager, secretProvider: secretProvider, slog: slog} } +func getFreePort() int { + addr, err := net.ResolveTCPAddr("tcp", "localhost:0") + if err != nil { + panic(err) + } + + l, err := net.ListenTCP("tcp", addr) + if err != nil { + panic(err) + } + defer l.Close() + + os.Setenv("BTP_MANAGER_API_PORT", fmt.Sprint(l.Addr().(*net.TCPAddr).Port)) + return l.Addr().(*net.TCPAddr).Port +} + func (a *API) Start() { mux := http.ServeMux{} mux.HandleFunc("GET /api/secrets", a.ListSecrets) From 7b82b4dd1ef19fc1715930b7790aec7f01ec2ab1 Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Fri, 31 May 2024 12:59:42 +0200 Subject: [PATCH 05/23] wip --- Makefile | 2 +- config/manager/kustomization.yaml | 4 +- config/rbac/role.yaml | 1 + internal/api/api.go | 10 +- main.go | 98 ++++-- manifests/btp-operator/btp-manager.yaml | 396 ++++++++++++++++++++++++ ui/src/components/SecretsView.tsx | 2 + 7 files changed, 476 insertions(+), 37 deletions(-) create mode 100644 manifests/btp-operator/btp-manager.yaml diff --git a/Makefile b/Makefile index 2a359a8c0..ff782c5b8 100644 --- a/Makefile +++ b/Makefile @@ -123,7 +123,7 @@ create-manifest: manifests kustomize ## Deploy controller to the K8s cluster spe .PHONY: deploy deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. - cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} + cd config/manager && $(KUSTOMIZE) edit set image controller=europe-docker.pkg.dev/kyma-project/dev/btp-manager:PR-711 $(KUSTOMIZE) build config/default | kubectl apply -f - .PHONY: undeploy diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index deed35163..8f3a6999f 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -4,5 +4,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - name: controller - newName: europe-docker.pkg.dev/kyma-project/prod/btp-manager - newTag: 0.0.23-test + newName: europe-docker.pkg.dev/kyma-project/dev/btp-manager + newTag: PR-711 diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 998b61d33..1d3a6f550 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -2,6 +2,7 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: + creationTimestamp: null name: manager-role rules: - apiGroups: diff --git a/internal/api/api.go b/internal/api/api.go index 2da8b84b7..58fc4387d 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -18,20 +18,16 @@ import ( servicemanager "github.com/kyma-project/btp-manager/internal/service-manager" ) -var ( - apiPort = 0 -) - type API struct { serviceManager *servicemanager.Client secretProvider *clusterobject.SecretProvider slog *slog.Logger + Port int } func NewAPI(serviceManager *servicemanager.Client, secretProvider *clusterobject.SecretProvider) *API { slog := slog.Default() - apiPort = getFreePort() - return &API{serviceManager: serviceManager, secretProvider: secretProvider, slog: slog} + return &API{serviceManager: serviceManager, secretProvider: secretProvider, Port: getFreePort(), slog: slog} } func getFreePort() int { @@ -59,7 +55,7 @@ func (a *API) Start() { mux.HandleFunc("GET /api/service-offerings/{namespace}/{name}", a.ListServiceOfferings) mux.HandleFunc("GET /api/service-offering/{id}", a.GetServiceOffering) go func() { - err := http.ListenAndServe(fmt.Sprintf(":%d", apiPort), nil) + err := http.ListenAndServe(fmt.Sprintf(":%d", a.Port), nil) if err != nil { a.slog.Error("failed to Start listening", "error", err) } diff --git a/main.go b/main.go index 17ea2efff..40941332b 100644 --- a/main.go +++ b/main.go @@ -39,7 +39,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/metrics/server" - //+kubebuilder:scaffold:imports + // +kubebuilder:scaffold:imports ) type managerWithContext struct { @@ -78,7 +78,7 @@ func init() { utilruntime.Must(v1alpha1.AddToScheme(scheme)) utilruntime.Must(apiextensionsv1.AddToScheme(scheme)) - //+kubebuilder:scaffold:scheme + // +kubebuilder:scaffold:scheme } func main() { @@ -99,6 +99,7 @@ func main() { go sm.start() go api.Start() + setupLog.Info("api listening on port", "port", api.Port) select { case <-signalContext.Done(): setupLog.Info("shutting down btp-manager") @@ -108,22 +109,58 @@ func main() { func parseCmdFlags(probeAddr *string, metricsAddr *string, enableLeaderElection *bool) { flag.StringVar(probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") flag.StringVar(metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") - flag.BoolVar(enableLeaderElection, "leader-elect", false, + flag.BoolVar( + enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. "+ - "Enabling this will ensure there is only one active controller manager.") - flag.StringVar(&controllers.ChartNamespace, "chart-namespace", controllers.ChartNamespace, "Namespace to install chart resources.") - flag.StringVar(&controllers.SecretName, "secret-name", controllers.SecretName, "Secret name with input values for sap-btp-operator chart templating.") - flag.StringVar(&controllers.ConfigName, "config-name", controllers.ConfigName, "ConfigMap name with configuration knobs for the btp-manager internals.") - flag.StringVar(&controllers.DeploymentName, "deployment-name", controllers.DeploymentName, "Name of the deployment of sap-btp-operator for deprovisioning.") - flag.StringVar(&controllers.ChartPath, "chart-path", controllers.ChartPath, "Path to the root directory inside the chart.") - flag.StringVar(&controllers.ResourcesPath, "resources-path", controllers.ResourcesPath, "Path to the directory with module resources to apply/delete.") - flag.DurationVar(&controllers.ProcessingStateRequeueInterval, "processing-state-requeue-interval", controllers.ProcessingStateRequeueInterval, `Requeue interval for state "processing".`) - flag.DurationVar(&controllers.ReadyStateRequeueInterval, "ready-state-requeue-interval", controllers.ReadyStateRequeueInterval, `Requeue interval for state "ready".`) + "Enabling this will ensure there is only one active controller manager.", + ) + flag.StringVar( + &controllers.ChartNamespace, "chart-namespace", controllers.ChartNamespace, + "Namespace to install chart resources.", + ) + flag.StringVar( + &controllers.SecretName, "secret-name", controllers.SecretName, + "Secret name with input values for sap-btp-operator chart templating.", + ) + flag.StringVar( + &controllers.ConfigName, "config-name", controllers.ConfigName, + "ConfigMap name with configuration knobs for the btp-manager internals.", + ) + flag.StringVar( + &controllers.DeploymentName, "deployment-name", controllers.DeploymentName, + "Name of the deployment of sap-btp-operator for deprovisioning.", + ) + flag.StringVar( + &controllers.ChartPath, "chart-path", controllers.ChartPath, "Path to the root directory inside the chart.", + ) + flag.StringVar( + &controllers.ResourcesPath, "resources-path", controllers.ResourcesPath, + "Path to the directory with module resources to apply/delete.", + ) + flag.DurationVar( + &controllers.ProcessingStateRequeueInterval, "processing-state-requeue-interval", + controllers.ProcessingStateRequeueInterval, `Requeue interval for state "processing".`, + ) + flag.DurationVar( + &controllers.ReadyStateRequeueInterval, "ready-state-requeue-interval", controllers.ReadyStateRequeueInterval, + `Requeue interval for state "ready".`, + ) flag.DurationVar(&controllers.ReadyTimeout, "ready-timeout", controllers.ReadyTimeout, "Helm chart timeout.") - flag.DurationVar(&controllers.ReadyCheckInterval, "ready-check-interval", controllers.ReadyCheckInterval, "Ready check retry interval.") - flag.DurationVar(&controllers.HardDeleteCheckInterval, "hard-delete-check-interval", controllers.HardDeleteCheckInterval, "Hard delete retry interval.") - flag.DurationVar(&controllers.HardDeleteTimeout, "hard-delete-timeout", controllers.HardDeleteTimeout, "Hard delete timeout.") - flag.DurationVar(&controllers.DeleteRequestTimeout, "delete-request-timeout", controllers.DeleteRequestTimeout, "Delete request timeout in hard delete.") + flag.DurationVar( + &controllers.ReadyCheckInterval, "ready-check-interval", controllers.ReadyCheckInterval, + "Ready check retry interval.", + ) + flag.DurationVar( + &controllers.HardDeleteCheckInterval, "hard-delete-check-interval", controllers.HardDeleteCheckInterval, + "Hard delete retry interval.", + ) + flag.DurationVar( + &controllers.HardDeleteTimeout, "hard-delete-timeout", controllers.HardDeleteTimeout, "Hard delete timeout.", + ) + flag.DurationVar( + &controllers.DeleteRequestTimeout, "delete-request-timeout", controllers.DeleteRequestTimeout, + "Delete request timeout in hard delete.", + ) opts := zap.Options{ Development: true, } @@ -133,29 +170,36 @@ func parseCmdFlags(probeAddr *string, metricsAddr *string, enableLeaderElection ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) } -func setupManager(restCfg *rest.Config, probeAddr *string, metricsAddr *string, enableLeaderElection *bool, signalContext context.Context) managerWithContext { - mgr, err := ctrl.NewManager(restCfg, ctrl.Options{ - Scheme: scheme, - LeaderElection: *enableLeaderElection, - LeaderElectionID: "ec023d38.kyma-project.io", - Metrics: server.Options{BindAddress: *metricsAddr}, - HealthProbeBindAddress: *probeAddr, - NewCache: controllers.CacheCreator, - }) +func setupManager( + restCfg *rest.Config, probeAddr *string, metricsAddr *string, enableLeaderElection *bool, + signalContext context.Context, +) managerWithContext { + mgr, err := ctrl.NewManager( + restCfg, ctrl.Options{ + Scheme: scheme, + LeaderElection: *enableLeaderElection, + LeaderElectionID: "ec023d38.kyma-project.io", + Metrics: server.Options{BindAddress: *metricsAddr}, + HealthProbeBindAddress: *probeAddr, + NewCache: controllers.CacheCreator, + }, + ) if err != nil { setupLog.Error(err, "unable to start manager") os.Exit(1) } metrics := btpmanagermetrics.NewMetrics() - cleanupReconciler := controllers.NewInstanceBindingControllerManager(signalContext, mgr.GetClient(), mgr.GetScheme(), restCfg) + cleanupReconciler := controllers.NewInstanceBindingControllerManager( + signalContext, mgr.GetClient(), mgr.GetScheme(), restCfg, + ) reconciler := controllers.NewBtpOperatorReconciler(mgr.GetClient(), scheme, cleanupReconciler, metrics) if err = reconciler.SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "BtpOperator") os.Exit(1) } - //+kubebuilder:scaffold:builder + // +kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { setupLog.Error(err, "unable to set up health check") diff --git a/manifests/btp-operator/btp-manager.yaml b/manifests/btp-operator/btp-manager.yaml new file mode 100644 index 000000000..7becb11f2 --- /dev/null +++ b/manifests/btp-operator/btp-manager.yaml @@ -0,0 +1,396 @@ +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + labels: + app.kubernetes.io/component: btp-manager.kyma-project.io + name: btpoperators.operator.kyma-project.io +spec: + group: operator.kyma-project.io + names: + kind: BtpOperator + listKind: BtpOperatorList + plural: btpoperators + singular: btpoperator + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.state + name: State + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: BtpOperator is the Schema for the btpoperators API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: BtpOperatorSpec defines the desired state of BtpOperator + nullable: true + type: object + status: + description: Status defines the observed state of CustomObject. Status + defines the observed state of CustomObject. + properties: + conditions: + description: Conditions associated with CustomStatus. + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + state: + description: State signifies current state of CustomObject. Value + can be one of ("Ready", "Processing", "Error", "Deleting", "Warning"). + enum: + - Processing + - Deleting + - Ready + - Error + - Warning + type: string + required: + - state + type: object + type: object + served: true + storage: true + subresources: + status: {} +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + labels: + app.kubernetes.io/component: btp-manager.kyma-project.io + name: btp-manager-controller-manager + namespace: kyma-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + labels: + app.kubernetes.io/component: btp-manager.kyma-project.io + name: btp-manager-leader-election-role + namespace: kyma-system +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - coordination.k8s.io + resources: + - leases + verbs: + - get + - list + - watch + - create + - update + - patch + - delete +- apiGroups: + - "" + resources: + - events + verbs: + - create + - patch +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + creationTimestamp: null + labels: + app.kubernetes.io/component: btp-manager.kyma-project.io + name: btp-manager-manager-role +rules: +- apiGroups: + - "" + resources: + - configmaps + verbs: + - '*' +- apiGroups: + - "" + resources: + - namespaces + verbs: + - get + - list + - watch +- apiGroups: + - "" + resources: + - secrets + verbs: + - '*' +- apiGroups: + - "" + resources: + - serviceaccounts + verbs: + - '*' +- apiGroups: + - "" + resources: + - services + verbs: + - '*' +- apiGroups: + - admissionregistration.k8s.io + resources: + - mutatingwebhookconfigurations + verbs: + - '*' +- apiGroups: + - admissionregistration.k8s.io + resources: + - validatingwebhookconfigurations + verbs: + - '*' +- apiGroups: + - apiextensions.k8s.io + resources: + - customresourcedefinitions + verbs: + - '*' +- apiGroups: + - apps + resources: + - deployments + verbs: + - '*' +- apiGroups: + - operator.kyma-project.io + resources: + - btpoperators + verbs: + - '*' +- apiGroups: + - operator.kyma-project.io + resources: + - btpoperators/status + verbs: + - '*' +- apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterrolebindings + verbs: + - '*' +- apiGroups: + - rbac.authorization.k8s.io + resources: + - clusterroles + verbs: + - '*' +- apiGroups: + - rbac.authorization.k8s.io + resources: + - rolebindings + verbs: + - '*' +- apiGroups: + - rbac.authorization.k8s.io + resources: + - roles + verbs: + - '*' +- apiGroups: + - services.cloud.sap.com + resources: + - servicebindings + - serviceinstances + verbs: + - '*' +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + labels: + app.kubernetes.io/component: btp-manager.kyma-project.io + name: btp-manager-leader-election-rolebinding + namespace: kyma-system +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: Role + name: btp-manager-leader-election-role +subjects: +- kind: ServiceAccount + name: btp-manager-controller-manager + namespace: kyma-system +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + labels: + app.kubernetes.io/component: btp-manager.kyma-project.io + name: btp-manager-manager-rolebinding +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: btp-manager-manager-role +subjects: +- kind: ServiceAccount + name: btp-manager-controller-manager + namespace: kyma-system +--- +apiVersion: v1 +kind: Service +metadata: + labels: + app.kubernetes.io/component: btp-manager.kyma-project.io + name: btp-manager-metrics-service + namespace: kyma-system +spec: + ports: + - name: http + port: 8080 + targetPort: http + selector: + app.kubernetes.io/component: btp-manager.kyma-project.io +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + labels: + app.kubernetes.io/component: btp-manager.kyma-project.io + name: btp-manager-controller-manager + namespace: kyma-system +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/component: btp-manager.kyma-project.io + template: + metadata: + annotations: + kubectl.kubernetes.io/default-container: manager + traffic.sidecar.istio.io/excludeInboundPorts: "8080" + traffic.sidecar.istio.io/includeInboundPorts: '*' + labels: + app.kubernetes.io/component: btp-manager.kyma-project.io + spec: + containers: + - args: + - --leader-elect + command: + - /manager + image: k3d-kyma-registry:5001/btp-manager:0.0.1 + livenessProbe: + httpGet: + path: /healthz + port: 8081 + initialDelaySeconds: 15 + periodSeconds: 20 + name: manager + ports: + - containerPort: 8080 + name: http + readinessProbe: + httpGet: + path: /readyz + port: 8081 + initialDelaySeconds: 5 + periodSeconds: 10 + resources: + limits: + cpu: 200m + memory: 128Mi + requests: + cpu: 10m + memory: 32Mi + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + securityContext: + runAsNonRoot: true + serviceAccountName: btp-manager-controller-manager + terminationGracePeriodSeconds: 10 diff --git a/ui/src/components/SecretsView.tsx b/ui/src/components/SecretsView.tsx index 95a713107..35c227a5e 100644 --- a/ui/src/components/SecretsView.tsx +++ b/ui/src/components/SecretsView.tsx @@ -10,6 +10,8 @@ function SecretsView(props: any) { const [error, setError] = useState(null); useEffect(() => { + console.log(process.env.BTP_MANAGER_API_PORT) + console.log("port") setLoading(true); axios .get(api("secrets")) From baad7019c6a4b11153d1f81c71cf6082e419bec5 Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Mon, 3 Jun 2024 13:37:47 +0200 Subject: [PATCH 06/23] wip --- ui/src/components/SecretsView.tsx | 2 +- ui/src/components/ServiceInstancesView.tsx | 2 +- ui/src/components/ServiceOfferingsView.tsx | 4 ++++ 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/ui/src/components/SecretsView.tsx b/ui/src/components/SecretsView.tsx index 35c227a5e..1fb4dc43f 100644 --- a/ui/src/components/SecretsView.tsx +++ b/ui/src/components/SecretsView.tsx @@ -41,7 +41,7 @@ function SecretsView(props: any) { props.handler( formatDisplay("","") ); - return + return } const renderData = () => { diff --git a/ui/src/components/ServiceInstancesView.tsx b/ui/src/components/ServiceInstancesView.tsx index 86f8b3af8..9c8723892 100644 --- a/ui/src/components/ServiceInstancesView.tsx +++ b/ui/src/components/ServiceInstancesView.tsx @@ -38,7 +38,7 @@ function ServiceInstancesView() { } if (error) { - return + return } const renderData = () => { diff --git a/ui/src/components/ServiceOfferingsView.tsx b/ui/src/components/ServiceOfferingsView.tsx index fed7bc239..560b5804d 100644 --- a/ui/src/components/ServiceOfferingsView.tsx +++ b/ui/src/components/ServiceOfferingsView.tsx @@ -54,6 +54,10 @@ function ServiceOfferingsView(props: any) { return } + if (error) { + return + } + function getImg(b64: string) { if (b64 == null) { return ""; From 99fd14028516d76c9795fd3ee4286a8a53033814 Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Mon, 3 Jun 2024 14:24:11 +0200 Subject: [PATCH 07/23] wip --- Makefile | 2 +- config/manager/kustomization.yaml | 4 +- config/rbac/role.yaml | 1 - internal/api/api.go | 137 -------- manifests/btp-operator/btp-manager.yaml | 396 ------------------------ ui/pkg/sumdb/sum.golang.org/latest | 5 - ui/src/shared/api.tsx | 3 +- 7 files changed, 4 insertions(+), 544 deletions(-) delete mode 100644 internal/api/api.go delete mode 100644 manifests/btp-operator/btp-manager.yaml delete mode 100644 ui/pkg/sumdb/sum.golang.org/latest diff --git a/Makefile b/Makefile index ff782c5b8..2a359a8c0 100644 --- a/Makefile +++ b/Makefile @@ -123,7 +123,7 @@ create-manifest: manifests kustomize ## Deploy controller to the K8s cluster spe .PHONY: deploy deploy: manifests kustomize ## Deploy controller to the K8s cluster specified in ~/.kube/config. - cd config/manager && $(KUSTOMIZE) edit set image controller=europe-docker.pkg.dev/kyma-project/dev/btp-manager:PR-711 + cd config/manager && $(KUSTOMIZE) edit set image controller=${IMG} $(KUSTOMIZE) build config/default | kubectl apply -f - .PHONY: undeploy diff --git a/config/manager/kustomization.yaml b/config/manager/kustomization.yaml index 8f3a6999f..deed35163 100644 --- a/config/manager/kustomization.yaml +++ b/config/manager/kustomization.yaml @@ -4,5 +4,5 @@ apiVersion: kustomize.config.k8s.io/v1beta1 kind: Kustomization images: - name: controller - newName: europe-docker.pkg.dev/kyma-project/dev/btp-manager - newTag: PR-711 + newName: europe-docker.pkg.dev/kyma-project/prod/btp-manager + newTag: 0.0.23-test diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 1d3a6f550..998b61d33 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -2,7 +2,6 @@ apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: - creationTimestamp: null name: manager-role rules: - apiGroups: diff --git a/internal/api/api.go b/internal/api/api.go deleted file mode 100644 index 58fc4387d..000000000 --- a/internal/api/api.go +++ /dev/null @@ -1,137 +0,0 @@ -package api - -import ( - "context" - "encoding/json" - "net/http" - "strings" - - "log/slog" - - "fmt" - - "net" - "os" - - "github.com/kyma-project/btp-manager/internal/api/vm" - clusterobject "github.com/kyma-project/btp-manager/internal/cluster-object" - servicemanager "github.com/kyma-project/btp-manager/internal/service-manager" -) - -type API struct { - serviceManager *servicemanager.Client - secretProvider *clusterobject.SecretProvider - slog *slog.Logger - Port int -} - -func NewAPI(serviceManager *servicemanager.Client, secretProvider *clusterobject.SecretProvider) *API { - slog := slog.Default() - return &API{serviceManager: serviceManager, secretProvider: secretProvider, Port: getFreePort(), slog: slog} -} - -func getFreePort() int { - addr, err := net.ResolveTCPAddr("tcp", "localhost:0") - if err != nil { - panic(err) - } - - l, err := net.ListenTCP("tcp", addr) - if err != nil { - panic(err) - } - defer l.Close() - - os.Setenv("BTP_MANAGER_API_PORT", fmt.Sprint(l.Addr().(*net.TCPAddr).Port)) - return l.Addr().(*net.TCPAddr).Port -} - -func (a *API) Start() { - mux := http.ServeMux{} - mux.HandleFunc("GET /api/secrets", a.ListSecrets) - mux.HandleFunc("GET /api/service-instances", a.ListServiceInstances) - mux.HandleFunc("PUT /api/service-instance/{id}", a.CreateServiceInstance) - mux.HandleFunc("GET /api/service-instance/{id}", a.GetServiceInstance) - mux.HandleFunc("GET /api/service-offerings/{namespace}/{name}", a.ListServiceOfferings) - mux.HandleFunc("GET /api/service-offering/{id}", a.GetServiceOffering) - go func() { - err := http.ListenAndServe(fmt.Sprintf(":%d", a.Port), nil) - if err != nil { - a.slog.Error("failed to Start listening", "error", err) - } - }() -} - -func (a *API) CreateServiceInstance(writer http.ResponseWriter, request *http.Request) { - return -} - -func (a *API) ListServiceOfferings(writer http.ResponseWriter, request *http.Request) { - a.setupCors(writer, request) - namespace := request.URL.Query().Get("namespace") - name := request.URL.Query().Get("name") - err := a.serviceManager.SetForGivenSecret(context.Background(), name, namespace) - if returnError(writer, err) { - return - } - offerings, err := a.serviceManager.ServiceOfferings() - if returnError(writer, err) { - return - } - response, err := json.Marshal(vm.ToServiceOfferingsVM(offerings)) - returnResponse(writer, response, err) -} - -func (a *API) ListSecrets(writer http.ResponseWriter, request *http.Request) { - a.setupCors(writer, request) - secrets, err := a.secretProvider.All(context.Background()) - if returnError(writer, err) { - return - } - response, err := json.Marshal(vm.ToSecretVM(*secrets)) - returnResponse(writer, response, err) -} - -func (a *API) GetServiceInstance(writer http.ResponseWriter, request *http.Request) { - a.setupCors(writer, request) - // not implemented in SM -} - -func (a *API) GetServiceOffering(writer http.ResponseWriter, request *http.Request) { - a.setupCors(writer, request) - // not implemented in SM -} - -func (a *API) ListServiceInstances(writer http.ResponseWriter, request *http.Request) { - a.setupCors(writer, request) - // will be taken from SM -} - -func (a *API) setupCors(writer http.ResponseWriter, request *http.Request) { - origin := request.Header.Get("Origin") - origin = strings.ReplaceAll(origin, "\r", "") - origin = strings.ReplaceAll(origin, "\n", "") - writer.Header().Set("Access-Control-Allow-Origin", origin) -} - -func returnResponse(writer http.ResponseWriter, response []byte, err error) { - if returnError(writer, err) { - return - } - _, err = writer.Write(response) - if returnError(writer, err) { - return - } -} - -func returnError(writer http.ResponseWriter, err error) bool { - if err != nil { - writer.WriteHeader(http.StatusInternalServerError) - _, err := writer.Write([]byte(err.Error())) - if err != nil { - return true - } - return true - } - return false -} diff --git a/manifests/btp-operator/btp-manager.yaml b/manifests/btp-operator/btp-manager.yaml deleted file mode 100644 index 7becb11f2..000000000 --- a/manifests/btp-operator/btp-manager.yaml +++ /dev/null @@ -1,396 +0,0 @@ -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.9.2 - creationTimestamp: null - labels: - app.kubernetes.io/component: btp-manager.kyma-project.io - name: btpoperators.operator.kyma-project.io -spec: - group: operator.kyma-project.io - names: - kind: BtpOperator - listKind: BtpOperatorList - plural: btpoperators - singular: btpoperator - scope: Namespaced - versions: - - additionalPrinterColumns: - - jsonPath: .status.state - name: State - type: string - name: v1alpha1 - schema: - openAPIV3Schema: - description: BtpOperator is the Schema for the btpoperators API - properties: - apiVersion: - description: 'APIVersion defines the versioned schema of this representation - of an object. Servers should convert recognized schemas to the latest - internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' - type: string - kind: - description: 'Kind is a string value representing the REST resource this - object represents. Servers may infer this from the endpoint the client - submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' - type: string - metadata: - type: object - spec: - description: BtpOperatorSpec defines the desired state of BtpOperator - nullable: true - type: object - status: - description: Status defines the observed state of CustomObject. Status - defines the observed state of CustomObject. - properties: - conditions: - description: Conditions associated with CustomStatus. - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - \n type FooStatus struct{ // Represents the observations of a - foo's current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - state: - description: State signifies current state of CustomObject. Value - can be one of ("Ready", "Processing", "Error", "Deleting", "Warning"). - enum: - - Processing - - Deleting - - Ready - - Error - - Warning - type: string - required: - - state - type: object - type: object - served: true - storage: true - subresources: - status: {} ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - labels: - app.kubernetes.io/component: btp-manager.kyma-project.io - name: btp-manager-controller-manager - namespace: kyma-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: Role -metadata: - labels: - app.kubernetes.io/component: btp-manager.kyma-project.io - name: btp-manager-leader-election-role - namespace: kyma-system -rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - get - - list - - watch - - create - - update - - patch - - delete -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - creationTimestamp: null - labels: - app.kubernetes.io/component: btp-manager.kyma-project.io - name: btp-manager-manager-role -rules: -- apiGroups: - - "" - resources: - - configmaps - verbs: - - '*' -- apiGroups: - - "" - resources: - - namespaces - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - secrets - verbs: - - '*' -- apiGroups: - - "" - resources: - - serviceaccounts - verbs: - - '*' -- apiGroups: - - "" - resources: - - services - verbs: - - '*' -- apiGroups: - - admissionregistration.k8s.io - resources: - - mutatingwebhookconfigurations - verbs: - - '*' -- apiGroups: - - admissionregistration.k8s.io - resources: - - validatingwebhookconfigurations - verbs: - - '*' -- apiGroups: - - apiextensions.k8s.io - resources: - - customresourcedefinitions - verbs: - - '*' -- apiGroups: - - apps - resources: - - deployments - verbs: - - '*' -- apiGroups: - - operator.kyma-project.io - resources: - - btpoperators - verbs: - - '*' -- apiGroups: - - operator.kyma-project.io - resources: - - btpoperators/status - verbs: - - '*' -- apiGroups: - - rbac.authorization.k8s.io - resources: - - clusterrolebindings - verbs: - - '*' -- apiGroups: - - rbac.authorization.k8s.io - resources: - - clusterroles - verbs: - - '*' -- apiGroups: - - rbac.authorization.k8s.io - resources: - - rolebindings - verbs: - - '*' -- apiGroups: - - rbac.authorization.k8s.io - resources: - - roles - verbs: - - '*' -- apiGroups: - - services.cloud.sap.com - resources: - - servicebindings - - serviceinstances - verbs: - - '*' ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: RoleBinding -metadata: - labels: - app.kubernetes.io/component: btp-manager.kyma-project.io - name: btp-manager-leader-election-rolebinding - namespace: kyma-system -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: Role - name: btp-manager-leader-election-role -subjects: -- kind: ServiceAccount - name: btp-manager-controller-manager - namespace: kyma-system ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - labels: - app.kubernetes.io/component: btp-manager.kyma-project.io - name: btp-manager-manager-rolebinding -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: btp-manager-manager-role -subjects: -- kind: ServiceAccount - name: btp-manager-controller-manager - namespace: kyma-system ---- -apiVersion: v1 -kind: Service -metadata: - labels: - app.kubernetes.io/component: btp-manager.kyma-project.io - name: btp-manager-metrics-service - namespace: kyma-system -spec: - ports: - - name: http - port: 8080 - targetPort: http - selector: - app.kubernetes.io/component: btp-manager.kyma-project.io ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - labels: - app.kubernetes.io/component: btp-manager.kyma-project.io - name: btp-manager-controller-manager - namespace: kyma-system -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/component: btp-manager.kyma-project.io - template: - metadata: - annotations: - kubectl.kubernetes.io/default-container: manager - traffic.sidecar.istio.io/excludeInboundPorts: "8080" - traffic.sidecar.istio.io/includeInboundPorts: '*' - labels: - app.kubernetes.io/component: btp-manager.kyma-project.io - spec: - containers: - - args: - - --leader-elect - command: - - /manager - image: k3d-kyma-registry:5001/btp-manager:0.0.1 - livenessProbe: - httpGet: - path: /healthz - port: 8081 - initialDelaySeconds: 15 - periodSeconds: 20 - name: manager - ports: - - containerPort: 8080 - name: http - readinessProbe: - httpGet: - path: /readyz - port: 8081 - initialDelaySeconds: 5 - periodSeconds: 10 - resources: - limits: - cpu: 200m - memory: 128Mi - requests: - cpu: 10m - memory: 32Mi - securityContext: - allowPrivilegeEscalation: false - capabilities: - drop: - - ALL - securityContext: - runAsNonRoot: true - serviceAccountName: btp-manager-controller-manager - terminationGracePeriodSeconds: 10 diff --git a/ui/pkg/sumdb/sum.golang.org/latest b/ui/pkg/sumdb/sum.golang.org/latest deleted file mode 100644 index df5df294e..000000000 --- a/ui/pkg/sumdb/sum.golang.org/latest +++ /dev/null @@ -1,5 +0,0 @@ -go.sum database tree -25169615 -l3M8lJVDV2EToEmKf5iGj0emA8PRakjZsjaskhCQtXo= - -— sum.golang.org Az3grpkMN5x46aNzLchq5f/LYNiVWO/11Dr+88NB7ZvI2o77RKgB6xKr9i0iqlA26hFkDYYqMsx5q0VrtRbkHHz3HAM= diff --git a/ui/src/shared/api.tsx b/ui/src/shared/api.tsx index 9c2d3180f..fb429e170 100644 --- a/ui/src/shared/api.tsx +++ b/ui/src/shared/api.tsx @@ -1,6 +1,5 @@ function api(url :string) { - const port = process.env.BTP_MANAGER_API_PORT - return `http://localhost:${port}/api/${url}` + return `http://localhost:3006/api/${url}` } export default api ; \ No newline at end of file From e5e10809f8be0297861aed8959d6e171b205d0e9 Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Mon, 3 Jun 2024 14:24:54 +0200 Subject: [PATCH 08/23] wip --- internal/api/api.go | 115 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 internal/api/api.go diff --git a/internal/api/api.go b/internal/api/api.go new file mode 100644 index 000000000..037aac4f1 --- /dev/null +++ b/internal/api/api.go @@ -0,0 +1,115 @@ +package api + +import ( + "context" + "encoding/json" + "net/http" + "strings" + + "log/slog" + + "github.com/kyma-project/btp-manager/internal/api/vm" + clusterobject "github.com/kyma-project/btp-manager/internal/cluster-object" + servicemanager "github.com/kyma-project/btp-manager/internal/service-manager" +) + +type API struct { + serviceManager *servicemanager.Client + secretProvider *clusterobject.SecretProvider + slogger *slog.Logger +} + +func NewAPI(serviceManager *servicemanager.Client, secretProvider *clusterobject.SecretProvider) *API { + slogger := slog.Default() + return &API{serviceManager: serviceManager, secretProvider: secretProvider, slogger: slogger} +} + +func (a *API) Start() { + mux := http.ServeMux{} + mux.HandleFunc("GET /api/secrets", a.ListSecrets) + mux.HandleFunc("GET /api/service-instances", a.ListServiceInstances) + mux.HandleFunc("PUT /api/service-instance/{id}", a.CreateServiceInstance) + mux.HandleFunc("GET /api/service-instance/{id}", a.GetServiceInstance) + mux.HandleFunc("GET /api/service-offerings/{namespace}/{name}", a.ListServiceOfferings) + mux.HandleFunc("GET /api/service-offering/{id}", a.GetServiceOffering) + go func() { + err := http.ListenAndServe(":3006", nil) + if err != nil { + a.slogger.Error("failed to Start listening", "error", err) + } + }() +} + +func (a *API) CreateServiceInstance(writer http.ResponseWriter, request *http.Request) { + return +} + +func (a *API) ListServiceOfferings(writer http.ResponseWriter, request *http.Request) { + a.setupCors(writer, request) + namespace := request.URL.Query().Get("namespace") + name := request.URL.Query().Get("name") + err := a.serviceManager.SetForGivenSecret(context.Background(), name, namespace) + if returnError(writer, err) { + return + } + offerings, err := a.serviceManager.ServiceOfferings() + if returnError(writer, err) { + return + } + response, err := json.Marshal(vm.ToServiceOfferingsVM(offerings)) + returnResponse(writer, response, err) +} + +func (a *API) ListSecrets(writer http.ResponseWriter, request *http.Request) { + a.setupCors(writer, request) + secrets, err := a.secretProvider.All(context.Background()) + if returnError(writer, err) { + return + } + response, err := json.Marshal(vm.ToSecretVM(*secrets)) + returnResponse(writer, response, err) +} + +func (a *API) GetServiceInstance(writer http.ResponseWriter, request *http.Request) { + a.setupCors(writer, request) + // not implemented in SM +} + +func (a *API) GetServiceOffering(writer http.ResponseWriter, request *http.Request) { + a.setupCors(writer, request) + // not implemented in SM +} + +func (a *API) ListServiceInstances(writer http.ResponseWriter, request *http.Request) { + a.setupCors(writer, request) + // will be taken from SM +} + +func (a *API) setupCors(writer http.ResponseWriter, request *http.Request) { + origin := request.Header.Get("Origin") + origin = strings.ReplaceAll(origin, "\r", "") + origin = strings.ReplaceAll(origin, "\n", "") + writer.Header().Set("Access-Control-Allow-Origin", origin) +} + +func returnResponse(writer http.ResponseWriter, response []byte, err error) { + if returnError(writer, err) { + return + } + _, err = writer.Write(response) + if returnError(writer, err) { + return + } +} + +func returnError(writer http.ResponseWriter, err error) bool { + if err != nil { + writer.WriteHeader(http.StatusInternalServerError) + _, err := writer.Write([]byte(err.Error())) + if err != nil { + return true + } + return true + } + return false +} From 612f9a3e523aa30e331e2d25cbd033f78fe7875a Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Mon, 3 Jun 2024 14:25:18 +0200 Subject: [PATCH 09/23] wip --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 335988e54..593e81a7e 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.22.3 require ( github.com/go-logr/logr v1.4.2 - github.com/onsi/ginkgo/v2 v2.19.0 + github.com/onsi/ginkgo/v2 v2.18.0 github.com/onsi/gomega v1.33.1 github.com/prometheus/client_golang v1.19.1 github.com/stretchr/testify v1.9.0 @@ -15,7 +15,7 @@ require ( k8s.io/apiextensions-apiserver v0.30.1 k8s.io/apimachinery v0.30.1 k8s.io/client-go v0.30.1 - sigs.k8s.io/controller-runtime v0.18.3 + sigs.k8s.io/controller-runtime v0.18.2 ) require ( diff --git a/go.sum b/go.sum index c471c7c68..352a35869 100644 --- a/go.sum +++ b/go.sum @@ -64,8 +64,8 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.19.0 h1:9Cnnf7UHo57Hy3k6/m5k3dRfGTMXGvxhHFvkDTCTpvA= -github.com/onsi/ginkgo/v2 v2.19.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= +github.com/onsi/ginkgo/v2 v2.18.0 h1:W9Y7IWXxPUpAit9ieMOLI7PJZGaW22DTKgiVAuhDTLc= +github.com/onsi/ginkgo/v2 v2.18.0/go.mod h1:rlwLi9PilAFJ8jCg9UE1QP6VBpd6/xj3SRC0d6TU0To= github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -165,8 +165,8 @@ k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108 h1:Q8Z7VlGhcJgBHJHYugJ/K/ k8s.io/kube-openapi v0.0.0-20240423202451-8948a665c108/go.mod h1:yD4MZYeKMBwQKVht279WycxKyM84kkAx2DPrTXaeb98= k8s.io/utils v0.0.0-20240423183400-0849a56e8f22 h1:ao5hUqGhsqdm+bYbjH/pRkCs0unBGe9UyDahzs9zQzQ= k8s.io/utils v0.0.0-20240423183400-0849a56e8f22/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -sigs.k8s.io/controller-runtime v0.18.3 h1:B5Wmmo8WMWK7izei+2LlXLVDGzMwAHBNLX68lwtlSR4= -sigs.k8s.io/controller-runtime v0.18.3/go.mod h1:TVoGrfdpbA9VRFaRnKgk9P5/atA0pMwq+f+msb9M8Sg= +sigs.k8s.io/controller-runtime v0.18.2 h1:RqVW6Kpeaji67CY5nPEfRz6ZfFMk0lWQlNrLqlNpx+Q= +sigs.k8s.io/controller-runtime v0.18.2/go.mod h1:tuAt1+wbVsXIT8lPtk5RURxqAnq7xkpv2Mhttslg7Hw= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd h1:EDPBXCAspyGV4jQlpZSudPeMmr1bNJefnuqLsRAsHZo= sigs.k8s.io/json v0.0.0-20221116044647-bc3834ca7abd/go.mod h1:B8JuhiUyNFVKdsE8h686QcCxMaH6HrOAZj4vswFpcB0= sigs.k8s.io/structured-merge-diff/v4 v4.4.1 h1:150L+0vs/8DA78h1u02ooW1/fFq/Lwr+sGiqlzvrtq4= From ffea125f64bbe5be274e0502ede1684a5781d4a5 Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Mon, 3 Jun 2024 14:26:11 +0200 Subject: [PATCH 10/23] wip --- main.go | 98 ++++++++++++++++----------------------------------------- 1 file changed, 27 insertions(+), 71 deletions(-) diff --git a/main.go b/main.go index 40941332b..17ea2efff 100644 --- a/main.go +++ b/main.go @@ -39,7 +39,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/log/zap" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/metrics/server" - // +kubebuilder:scaffold:imports + //+kubebuilder:scaffold:imports ) type managerWithContext struct { @@ -78,7 +78,7 @@ func init() { utilruntime.Must(v1alpha1.AddToScheme(scheme)) utilruntime.Must(apiextensionsv1.AddToScheme(scheme)) - // +kubebuilder:scaffold:scheme + //+kubebuilder:scaffold:scheme } func main() { @@ -99,7 +99,6 @@ func main() { go sm.start() go api.Start() - setupLog.Info("api listening on port", "port", api.Port) select { case <-signalContext.Done(): setupLog.Info("shutting down btp-manager") @@ -109,58 +108,22 @@ func main() { func parseCmdFlags(probeAddr *string, metricsAddr *string, enableLeaderElection *bool) { flag.StringVar(probeAddr, "health-probe-bind-address", ":8081", "The address the probe endpoint binds to.") flag.StringVar(metricsAddr, "metrics-bind-address", ":8080", "The address the metric endpoint binds to.") - flag.BoolVar( - enableLeaderElection, "leader-elect", false, + flag.BoolVar(enableLeaderElection, "leader-elect", false, "Enable leader election for controller manager. "+ - "Enabling this will ensure there is only one active controller manager.", - ) - flag.StringVar( - &controllers.ChartNamespace, "chart-namespace", controllers.ChartNamespace, - "Namespace to install chart resources.", - ) - flag.StringVar( - &controllers.SecretName, "secret-name", controllers.SecretName, - "Secret name with input values for sap-btp-operator chart templating.", - ) - flag.StringVar( - &controllers.ConfigName, "config-name", controllers.ConfigName, - "ConfigMap name with configuration knobs for the btp-manager internals.", - ) - flag.StringVar( - &controllers.DeploymentName, "deployment-name", controllers.DeploymentName, - "Name of the deployment of sap-btp-operator for deprovisioning.", - ) - flag.StringVar( - &controllers.ChartPath, "chart-path", controllers.ChartPath, "Path to the root directory inside the chart.", - ) - flag.StringVar( - &controllers.ResourcesPath, "resources-path", controllers.ResourcesPath, - "Path to the directory with module resources to apply/delete.", - ) - flag.DurationVar( - &controllers.ProcessingStateRequeueInterval, "processing-state-requeue-interval", - controllers.ProcessingStateRequeueInterval, `Requeue interval for state "processing".`, - ) - flag.DurationVar( - &controllers.ReadyStateRequeueInterval, "ready-state-requeue-interval", controllers.ReadyStateRequeueInterval, - `Requeue interval for state "ready".`, - ) + "Enabling this will ensure there is only one active controller manager.") + flag.StringVar(&controllers.ChartNamespace, "chart-namespace", controllers.ChartNamespace, "Namespace to install chart resources.") + flag.StringVar(&controllers.SecretName, "secret-name", controllers.SecretName, "Secret name with input values for sap-btp-operator chart templating.") + flag.StringVar(&controllers.ConfigName, "config-name", controllers.ConfigName, "ConfigMap name with configuration knobs for the btp-manager internals.") + flag.StringVar(&controllers.DeploymentName, "deployment-name", controllers.DeploymentName, "Name of the deployment of sap-btp-operator for deprovisioning.") + flag.StringVar(&controllers.ChartPath, "chart-path", controllers.ChartPath, "Path to the root directory inside the chart.") + flag.StringVar(&controllers.ResourcesPath, "resources-path", controllers.ResourcesPath, "Path to the directory with module resources to apply/delete.") + flag.DurationVar(&controllers.ProcessingStateRequeueInterval, "processing-state-requeue-interval", controllers.ProcessingStateRequeueInterval, `Requeue interval for state "processing".`) + flag.DurationVar(&controllers.ReadyStateRequeueInterval, "ready-state-requeue-interval", controllers.ReadyStateRequeueInterval, `Requeue interval for state "ready".`) flag.DurationVar(&controllers.ReadyTimeout, "ready-timeout", controllers.ReadyTimeout, "Helm chart timeout.") - flag.DurationVar( - &controllers.ReadyCheckInterval, "ready-check-interval", controllers.ReadyCheckInterval, - "Ready check retry interval.", - ) - flag.DurationVar( - &controllers.HardDeleteCheckInterval, "hard-delete-check-interval", controllers.HardDeleteCheckInterval, - "Hard delete retry interval.", - ) - flag.DurationVar( - &controllers.HardDeleteTimeout, "hard-delete-timeout", controllers.HardDeleteTimeout, "Hard delete timeout.", - ) - flag.DurationVar( - &controllers.DeleteRequestTimeout, "delete-request-timeout", controllers.DeleteRequestTimeout, - "Delete request timeout in hard delete.", - ) + flag.DurationVar(&controllers.ReadyCheckInterval, "ready-check-interval", controllers.ReadyCheckInterval, "Ready check retry interval.") + flag.DurationVar(&controllers.HardDeleteCheckInterval, "hard-delete-check-interval", controllers.HardDeleteCheckInterval, "Hard delete retry interval.") + flag.DurationVar(&controllers.HardDeleteTimeout, "hard-delete-timeout", controllers.HardDeleteTimeout, "Hard delete timeout.") + flag.DurationVar(&controllers.DeleteRequestTimeout, "delete-request-timeout", controllers.DeleteRequestTimeout, "Delete request timeout in hard delete.") opts := zap.Options{ Development: true, } @@ -170,36 +133,29 @@ func parseCmdFlags(probeAddr *string, metricsAddr *string, enableLeaderElection ctrl.SetLogger(zap.New(zap.UseFlagOptions(&opts))) } -func setupManager( - restCfg *rest.Config, probeAddr *string, metricsAddr *string, enableLeaderElection *bool, - signalContext context.Context, -) managerWithContext { - mgr, err := ctrl.NewManager( - restCfg, ctrl.Options{ - Scheme: scheme, - LeaderElection: *enableLeaderElection, - LeaderElectionID: "ec023d38.kyma-project.io", - Metrics: server.Options{BindAddress: *metricsAddr}, - HealthProbeBindAddress: *probeAddr, - NewCache: controllers.CacheCreator, - }, - ) +func setupManager(restCfg *rest.Config, probeAddr *string, metricsAddr *string, enableLeaderElection *bool, signalContext context.Context) managerWithContext { + mgr, err := ctrl.NewManager(restCfg, ctrl.Options{ + Scheme: scheme, + LeaderElection: *enableLeaderElection, + LeaderElectionID: "ec023d38.kyma-project.io", + Metrics: server.Options{BindAddress: *metricsAddr}, + HealthProbeBindAddress: *probeAddr, + NewCache: controllers.CacheCreator, + }) if err != nil { setupLog.Error(err, "unable to start manager") os.Exit(1) } metrics := btpmanagermetrics.NewMetrics() - cleanupReconciler := controllers.NewInstanceBindingControllerManager( - signalContext, mgr.GetClient(), mgr.GetScheme(), restCfg, - ) + cleanupReconciler := controllers.NewInstanceBindingControllerManager(signalContext, mgr.GetClient(), mgr.GetScheme(), restCfg) reconciler := controllers.NewBtpOperatorReconciler(mgr.GetClient(), scheme, cleanupReconciler, metrics) if err = reconciler.SetupWithManager(mgr); err != nil { setupLog.Error(err, "unable to create controller", "controller", "BtpOperator") os.Exit(1) } - // +kubebuilder:scaffold:builder + //+kubebuilder:scaffold:builder if err := mgr.AddHealthzCheck("healthz", healthz.Ping); err != nil { setupLog.Error(err, "unable to set up health check") From c821bfc36269ce6df73a0a580fe4144fd64d8cb3 Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Mon, 3 Jun 2024 14:42:33 +0200 Subject: [PATCH 11/23] wip --- ui/src/components/SecretsView.tsx | 125 ++++++++++++++---------------- ui/src/shared/models.tsx | 3 +- 2 files changed, 59 insertions(+), 69 deletions(-) diff --git a/ui/src/components/SecretsView.tsx b/ui/src/components/SecretsView.tsx index 1fb4dc43f..9d66eb136 100644 --- a/ui/src/components/SecretsView.tsx +++ b/ui/src/components/SecretsView.tsx @@ -1,86 +1,75 @@ import * as ui5 from "@ui5/webcomponents-react"; import axios from "axios"; -import { useEffect, useState } from "react"; -import { Secrets } from "../shared/models"; +import {useEffect, useState} from "react"; +import {Secrets} from "../shared/models"; import api from "../shared/api"; function SecretsView(props: any) { - const [secrets, setSecrets] = useState(); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); + const [secrets, setSecrets] = useState(); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); - useEffect(() => { - console.log(process.env.BTP_MANAGER_API_PORT) - console.log("port") - setLoading(true); - axios - .get(api("secrets")) - .then((response) => { - setSecrets(response.data); - setLoading(false); - props.handler( - formatDisplay( - response.data.items[0].name, - response.data.items[0].namespace - ) - ); - }) - .catch((error) => { - setLoading(false); - props.handler( - formatDisplay("","") - ); - }); - }, []); + useEffect(() => { + setLoading(true); + axios + .get(api("secrets")) + .then((response) => { + setLoading(false); + setSecrets(response.data); + props.handler(formatSecretText(response.data.items[0].name, response.data.items[0].namespace)); + }) + .catch((error) => { + setLoading(false); + setSecrets(undefined); + props.handler(formatSecretText("", "")); + }); + }, []); - if (loading) { - return - } - - if (error) { - props.handler( - formatDisplay("","") - ); - return - } + if (loading) { + return + } - const renderData = () => { - if (!secrets) { - console.log(secrets); - return {formatDisplay("", "")} + if (error) { + props.handler(formatSecretText("", "")); + return } - return secrets?.items.map((s, i) => { - return ( - {formatDisplay(s.name, s.namespace)} - ); - }); - }; + const renderData = () => { + if (!secrets || secrets.items.length === 0) { + return {formatSecretText("", "")} + } - return ( -
- <> + return secrets?.items.map((secret, index) => { + return ( + {formatSecretText(secret.name, secret.namespace)} + ); + }); + }; + + return (
- { - // @ts-ignore - props.handler(e.target.value); - }} - > - {renderData()} - + <> +
+ { + // @ts-ignore + props.handler(e.target.value); + }} + > + {renderData()} + +
+
- -
- ); + ); } -function formatDisplay(secretName: string, secretNamespace: string) { - if (!secretName || !secretNamespace) { - return "No secret found" - } - return `${secretName} in (${secretNamespace})`; +function formatSecretText(secretName: string, secretNamespace: string) { + if (secretName === "" || secretNamespace === "") { + return "No secret found" + } + return `${secretName} in (${secretNamespace})`; } export default SecretsView; diff --git a/ui/src/shared/models.tsx b/ui/src/shared/models.tsx index 26a408aff..8ec33bfc8 100644 --- a/ui/src/shared/models.tsx +++ b/ui/src/shared/models.tsx @@ -52,4 +52,5 @@ export interface ServiceInstanceDetails { name: string; context: string; namespace: string; -} \ No newline at end of file +} + From 655aa62f0065a1e0486c702bb0e82960648c810b Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Tue, 4 Jun 2024 09:47:19 +0200 Subject: [PATCH 12/23] how to --- docs/user/04-01-webapp.md | 9 +++++++++ ui/src/shared/validator.tsx | 0 2 files changed, 9 insertions(+) create mode 100644 docs/user/04-01-webapp.md create mode 100644 ui/src/shared/validator.tsx diff --git a/docs/user/04-01-webapp.md b/docs/user/04-01-webapp.md new file mode 100644 index 000000000..caef7b015 --- /dev/null +++ b/docs/user/04-01-webapp.md @@ -0,0 +1,9 @@ +1. Connect to cluster with BTP Operator +2. Change directory to BTP Manager source code +3. Change branch to sm-integration +4. Open 2 terminal windows + In one - Run make app + In second - Run make ui + +If any of pors is taken u can use to clean: +kill -9 $(lsof -i tcp:8081 -t) \ No newline at end of file diff --git a/ui/src/shared/validator.tsx b/ui/src/shared/validator.tsx new file mode 100644 index 000000000..e69de29bb From bee244398fc9f5713893b77301555dd5ffe59380 Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Tue, 4 Jun 2024 12:54:09 +0200 Subject: [PATCH 13/23] wip --- ui/src/components/SecretsView.tsx | 22 +++++-- ui/src/components/ServiceInstancesView.tsx | 12 ++-- ui/src/components/ServiceOfferingsView.tsx | 13 ++-- ui/src/components/View.tsx | 77 +++++++++++----------- ui/src/shared/api.tsx | 2 +- ui/src/shared/validator.tsx | 26 ++++++++ 6 files changed, 98 insertions(+), 54 deletions(-) diff --git a/ui/src/components/SecretsView.tsx b/ui/src/components/SecretsView.tsx index 9d66eb136..bb605bef3 100644 --- a/ui/src/components/SecretsView.tsx +++ b/ui/src/components/SecretsView.tsx @@ -2,6 +2,7 @@ import * as ui5 from "@ui5/webcomponents-react"; import axios from "axios"; import {useEffect, useState} from "react"; import {Secrets} from "../shared/models"; +import Ok from "../shared/validator"; import api from "../shared/api"; function SecretsView(props: any) { @@ -16,10 +17,15 @@ function SecretsView(props: any) { .then((response) => { setLoading(false); setSecrets(response.data); - props.handler(formatSecretText(response.data.items[0].name, response.data.items[0].namespace)); + if (Ok(response.data) && Ok(response.data.items)) { + props.handler(formatSecretText(response.data.items[0].name, response.data.items[0].namespace)); + } else { + props.handler(formatSecretText("", "")); + } }) .catch((error) => { setLoading(false); + setError(error); setSecrets(undefined); props.handler(formatSecretText("", "")); }); @@ -35,10 +41,16 @@ function SecretsView(props: any) { } const renderData = () => { - if (!secrets || secrets.items.length === 0) { - return {formatSecretText("", "")} - } - + // @ts-ignore + console.log("No secrets found"); + // @ts-ignore + if (!Ok(secrets) || !Ok(secrets.items)){ + return
+ <> + {formatSecretText("", "")} + +
+ } return secrets?.items.map((secret, index) => { return ( {formatSecretText(secret.name, secret.namespace)} diff --git a/ui/src/components/ServiceInstancesView.tsx b/ui/src/components/ServiceInstancesView.tsx index 9c8723892..f6bcc57c7 100644 --- a/ui/src/components/ServiceInstancesView.tsx +++ b/ui/src/components/ServiceInstancesView.tsx @@ -4,6 +4,7 @@ import axios from "axios"; import { useEffect, useState, useRef } from "react"; import { createPortal } from "react-dom"; import api from "../shared/api"; +import Ok from "../shared/validator"; function ServiceInstancesView() { const [serviceInstances, setServiceInstances] = useState(); @@ -24,12 +25,12 @@ function ServiceInstancesView() { axios .get(api("service-instances")) .then((response) => { - setServiceInstances(response.data); - setLoading(false); + setLoading(false); + setServiceInstances(response.data); }) .catch((error) => { - setError(error); - setLoading(false); + setLoading(false); + setError(error); }); }, []); @@ -42,7 +43,8 @@ function ServiceInstancesView() { } const renderData = () => { - if (!serviceInstances) { + // @ts-ignore + if (!Ok(serviceInstances) || !Ok(serviceInstances.items)) { return } return serviceInstances?.items.map((brief, index) => { diff --git a/ui/src/components/ServiceOfferingsView.tsx b/ui/src/components/ServiceOfferingsView.tsx index 560b5804d..88de48286 100644 --- a/ui/src/components/ServiceOfferingsView.tsx +++ b/ui/src/components/ServiceOfferingsView.tsx @@ -7,6 +7,7 @@ import { ServiceOfferingDetails, ServiceOfferings } from "../shared/models"; import ts from "typescript"; import api from "../shared/api"; import "@ui5/webcomponents-fiori/dist/illustrations/AllIllustrations.js" +import Ok from "../shared/validator"; function ServiceOfferingsView(props: any) { const [offerings, setOfferings] = useState(); const [serviceOfferingDetails, setServiceOfferingDetails] = @@ -39,12 +40,12 @@ function ServiceOfferingsView(props: any) { ) ) .then((response) => { - setOfferings(response.data); setLoading(false); + setOfferings(response.data); }) .catch((error) => { - setError(error); setLoading(false); + setError(error); }); } }, []); @@ -71,18 +72,18 @@ function ServiceOfferingsView(props: any) { axios .get(api(`service-offering/${id}`)) .then((response) => { - setServiceOfferingDetails(response.data); setLoading(false); + setServiceOfferingDetails(response.data); }) .catch((error) => { - setError(error); setLoading(false); + setError(error); }); } const renderData = () => { - if (!offerings) { - console.log(offerings); + // @ts-ignore + if (!Ok(offerings) || !Ok(offerings.items)){ return } return offerings?.items.map((offering, index) => { diff --git a/ui/src/components/View.tsx b/ui/src/components/View.tsx index cb76c0dc8..c5779d2c7 100644 --- a/ui/src/components/View.tsx +++ b/ui/src/components/View.tsx @@ -26,43 +26,46 @@ function Overview(props: any) { handler(e)} style={{ width: "100vw" }} /> <> - - - { - setPageContent(); - }} - /> - { - setPageContent(); - }} - /> - - - {pageContent} - - +
+ + + { + setPageContent(); + }} + /> + { + setPageContent(); + }} + /> + + + {pageContent} + + +
+ ); diff --git a/ui/src/shared/api.tsx b/ui/src/shared/api.tsx index fb429e170..1ad6ad23c 100644 --- a/ui/src/shared/api.tsx +++ b/ui/src/shared/api.tsx @@ -2,4 +2,4 @@ function api(url :string) { return `http://localhost:3006/api/${url}` } -export default api ; \ No newline at end of file +export default api; \ No newline at end of file diff --git a/ui/src/shared/validator.tsx b/ui/src/shared/validator.tsx index e69de29bb..1e2e37087 100644 --- a/ui/src/shared/validator.tsx +++ b/ui/src/shared/validator.tsx @@ -0,0 +1,26 @@ +function Ok(value: any) { + if (value == null) { + return false + } + + if (value == undefined) { + return false + } + + if (!value) { + return false + } + + if ( typeof value == 'string' && value == "") { + return false + } + + if (Array.isArray(value)) { + if (value.length == 0) { + return false + } + } + return true +} + +export default Ok; \ No newline at end of file From 0edd8011f602422150582b8ca3b896f17edbcbd5 Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:58:59 +0200 Subject: [PATCH 14/23] wip --- ui/src/App.css | 2 +- ui/src/components/SecretsView.tsx | 2 - ui/src/components/ServiceOfferingsView.tsx | 45 +++++++++++++++++----- ui/src/components/View.tsx | 26 +++++++++---- 4 files changed, 56 insertions(+), 19 deletions(-) diff --git a/ui/src/App.css b/ui/src/App.css index 969738504..1780dc194 100644 --- a/ui/src/App.css +++ b/ui/src/App.css @@ -43,5 +43,5 @@ html { body { margin: 0px auto; - width: 50vw; + width: 100vw; } \ No newline at end of file diff --git a/ui/src/components/SecretsView.tsx b/ui/src/components/SecretsView.tsx index bb605bef3..5a377fb5b 100644 --- a/ui/src/components/SecretsView.tsx +++ b/ui/src/components/SecretsView.tsx @@ -41,8 +41,6 @@ function SecretsView(props: any) { } const renderData = () => { - // @ts-ignore - console.log("No secrets found"); // @ts-ignore if (!Ok(secrets) || !Ok(secrets.items)){ return
diff --git a/ui/src/components/ServiceOfferingsView.tsx b/ui/src/components/ServiceOfferingsView.tsx index 88de48286..78e8d2255 100644 --- a/ui/src/components/ServiceOfferingsView.tsx +++ b/ui/src/components/ServiceOfferingsView.tsx @@ -1,15 +1,15 @@ import * as ui5 from "@ui5/webcomponents-react"; import { useEffect, useState, useRef } from "react"; import { createPortal } from "react-dom"; - import axios from "axios"; import { ServiceOfferingDetails, ServiceOfferings } from "../shared/models"; -import ts from "typescript"; import api from "../shared/api"; -import "@ui5/webcomponents-fiori/dist/illustrations/AllIllustrations.js" +import "@ui5/webcomponents-icons/dist/AllIcons.js" import Ok from "../shared/validator"; + function ServiceOfferingsView(props: any) { const [offerings, setOfferings] = useState(); + const [offeringsCachced, setOfferingsCached] = useState(); const [serviceOfferingDetails, setServiceOfferingDetails] = useState(); const [loading, setLoading] = useState(true); @@ -19,13 +19,15 @@ function ServiceOfferingsView(props: any) { const handleOpen = (id: any) => { // @ts-ignore dialogRef.current.show(); + console.log("handleOpen id: ", id) load(id); }; const handleClose = () => { // @ts-ignore dialogRef.current.close(); }; - + + useEffect(() => { if (props.secret == null) { return; @@ -58,6 +60,24 @@ function ServiceOfferingsView(props: any) { if (error) { return } + + function filter(e: string) { + return; + console.log("filtering") + // @ts-ignore + setOfferings(offeringsCachced); + const ServiceOfferings = offeringsCachced; + let ii = 0; + // @ts-ignore + for (let i = 0; i < offerings?.items.length; i++) { + // @ts-ignore + if (offerings?.items[i].metadata.displayName.includes(e)) { + // @ts-ignore + ServiceOfferings.items[ii] = [offerings?.items[i]]; + ii++; + } + } + } function getImg(b64: string) { if (b64 == null) { @@ -68,35 +88,42 @@ function ServiceOfferingsView(props: any) { } function load(id: string) { + console.log("loading id: ", id) setLoading(true); axios .get(api(`service-offering/${id}`)) .then((response) => { + console.log("load response: ", response) setLoading(false); setServiceOfferingDetails(response.data); }) .catch((error) => { setLoading(false); setError(error); + console.log("load error: ", error) }); } const renderData = () => { - // @ts-ignore + // @ts-ignore if (!Ok(offerings) || !Ok(offerings.items)){ return } - return offerings?.items.map((offering, index) => { + //console.log("renderData") + //filter(props.phrase) + + return offerings?.items.map((offering, index) => { return ( <> { + console.log("opening id: ", offering.id) handleOpen(offering.id); }} header={ diff --git a/ui/src/components/View.tsx b/ui/src/components/View.tsx index c5779d2c7..7c07ab633 100644 --- a/ui/src/components/View.tsx +++ b/ui/src/components/View.tsx @@ -6,11 +6,16 @@ import React from "react"; function Overview(props: any) { const [secret, setSecret] = React.useState(null); + const [phrase, setPhrase] = React.useState(null); const [pageContent, setPageContent] = React.useState(); function handler(e: any) { setSecret(e); } - + function handler2(e: any) { + console.log("handler2") + setPhrase(e); + } + return ( <> Select your credentials:} > handler(e)} style={{ width: "100vw" }} /> + ){ + console.log("onInput") + const phrase=event.target.value; + handler2(phrase); + }} + valueState="None" + /> <>
@@ -43,7 +56,7 @@ function Overview(props: any) { text="Marketplace" icon="home" onClick={() => { - setPageContent(); + setPageContent(); }} /> {pageContent} From 3f5ffa2513b76dec19a92e799b5d33a1da67c0e3 Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:59:33 +0200 Subject: [PATCH 15/23] wip --- docs/user/04-01-webapp.md | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 docs/user/04-01-webapp.md diff --git a/docs/user/04-01-webapp.md b/docs/user/04-01-webapp.md deleted file mode 100644 index caef7b015..000000000 --- a/docs/user/04-01-webapp.md +++ /dev/null @@ -1,9 +0,0 @@ -1. Connect to cluster with BTP Operator -2. Change directory to BTP Manager source code -3. Change branch to sm-integration -4. Open 2 terminal windows - In one - Run make app - In second - Run make ui - -If any of pors is taken u can use to clean: -kill -9 $(lsof -i tcp:8081 -t) \ No newline at end of file From 54ed23b09b55c5b5a36bae1683efa33df0dcbd07 Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:17:33 +0200 Subject: [PATCH 16/23] wip --- ui/src/components/ServiceOfferingsView.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/ui/src/components/ServiceOfferingsView.tsx b/ui/src/components/ServiceOfferingsView.tsx index 78e8d2255..950bc6fb4 100644 --- a/ui/src/components/ServiceOfferingsView.tsx +++ b/ui/src/components/ServiceOfferingsView.tsx @@ -102,6 +102,7 @@ function ServiceOfferingsView(props: any) { setError(error); console.log("load error: ", error) }); + setLoading(false); } const renderData = () => { From dc0feb1300a6757dee923785bfd65f932f7dbf73 Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:51:06 +0200 Subject: [PATCH 17/23] wip --- internal/api/api.go | 13 +- internal/api/vm/converters.go | 21 + internal/api/vm/vm.go | 12 + ui/src/components/ServiceOfferingsView.tsx | 486 +++++++++++---------- ui/src/shared/models.tsx | 18 +- 5 files changed, 309 insertions(+), 241 deletions(-) diff --git a/internal/api/api.go b/internal/api/api.go index 2f0c8a963..60e0ec9e4 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -28,10 +28,10 @@ func (a *API) Start() { mux := http.NewServeMux() mux.HandleFunc("GET /api/secrets", a.ListSecrets) mux.HandleFunc("GET /api/service-instances", a.ListServiceInstances) - mux.HandleFunc("PUT /api/service-instance/{id}", a.CreateServiceInstance) + mux.HandleFunc("PUT /api/service-instance", a.CreateServiceInstance) mux.HandleFunc("GET /api/service-instance/{id}", a.GetServiceInstance) mux.HandleFunc("GET /api/service-offerings/{namespace}/{name}", a.ListServiceOfferings) - mux.HandleFunc("GET /api/service-offering/{id}", a.GetServiceOffering) + mux.HandleFunc("GET /api/service-offering-details/{id}", a.GetServiceOfferingDetails) go func() { err := http.ListenAndServe(":3006", mux) if err != nil { @@ -75,9 +75,16 @@ func (a *API) GetServiceInstance(writer http.ResponseWriter, request *http.Reque // not implemented in SM } -func (a *API) GetServiceOffering(writer http.ResponseWriter, request *http.Request) { +func (a *API) GetServiceOfferingDetails(writer http.ResponseWriter, request *http.Request) { a.setupCors(writer, request) // not implemented in SM + serviceOfferingId := request.PathValue("id") + details, err := a.serviceManager.ServiceOfferingDetails(serviceOfferingId) + if returnError(writer, err) { + return + } + response, err := json.Marshal(vm.ToServiceOfferingDetailsVM(details)) + returnResponse(writer, response, err) } func (a *API) ListServiceInstances(writer http.ResponseWriter, request *http.Request) { diff --git a/internal/api/vm/converters.go b/internal/api/vm/converters.go index ae1747117..90b535b59 100644 --- a/internal/api/vm/converters.go +++ b/internal/api/vm/converters.go @@ -43,3 +43,24 @@ func ToServiceOfferingsVM(offerings *types.ServiceOfferings) ServiceOfferings { } return serviceOfferings } + +func ToServiceOfferingDetailsVM(serviceOfferings *types.ServiceOfferingDetails) ServiceOfferingDetails { + details := ServiceOfferingDetails{ + Plans: []ServiceOfferingPlan{}, + } + + for _, plan := range serviceOfferings.ServicePlans.ServicePlans { + details.LongDescription, _ = serviceOfferings.MetadataValueByFieldName(types.ServiceOfferingLongDescription) + supportUrl, _ := serviceOfferings.MetadataValueByFieldName(types.ServiceOfferingSupportURL) + documentationUrl, _ := serviceOfferings.MetadataValueByFieldName(types.ServiceOfferingDocumentationUrl) + planReturn := ServiceOfferingPlan{ + Name: plan.Name, + Description: plan.Description, + DocumentationUrl: documentationUrl, + SupportUrl: supportUrl, + } + details.Plans = append(details.Plans, planReturn) + } + + return details +} diff --git a/internal/api/vm/vm.go b/internal/api/vm/vm.go index 031a86fb6..3aa4d4288 100644 --- a/internal/api/vm/vm.go +++ b/internal/api/vm/vm.go @@ -35,3 +35,15 @@ type ServiceInstance struct { Name string `json:"name"` Namespace string `json:"namespace"` } + +type ServiceOfferingDetails struct { + LongDescription string `json:"longDescription"` + Plans []ServiceOfferingPlan `json:"plans"` +} + +type ServiceOfferingPlan struct { + Name string `json:"name"` + Description string `json:"description"` + DocumentationUrl string `json:"documentationUrl"` + SupportUrl string `json:"supportUrl"` +} diff --git a/ui/src/components/ServiceOfferingsView.tsx b/ui/src/components/ServiceOfferingsView.tsx index 950bc6fb4..1cb95754b 100644 --- a/ui/src/components/ServiceOfferingsView.tsx +++ b/ui/src/components/ServiceOfferingsView.tsx @@ -1,261 +1,289 @@ import * as ui5 from "@ui5/webcomponents-react"; -import { useEffect, useState, useRef } from "react"; -import { createPortal } from "react-dom"; +import {useEffect, useRef, useState} from "react"; +import {createPortal} from "react-dom"; import axios from "axios"; -import { ServiceOfferingDetails, ServiceOfferings } from "../shared/models"; +import {ServiceOfferingDetails, ServiceOfferings} from "../shared/models"; import api from "../shared/api"; import "@ui5/webcomponents-icons/dist/AllIcons.js" import Ok from "../shared/validator"; function ServiceOfferingsView(props: any) { - const [offerings, setOfferings] = useState(); - const [offeringsCachced, setOfferingsCached] = useState(); - const [serviceOfferingDetails, setServiceOfferingDetails] = - useState(); - const [loading, setLoading] = useState(true); - const [error, setError] = useState(null); - const [labels, setLabels] = useState(); - const dialogRef = useRef(null); - const handleOpen = (id: any) => { - // @ts-ignore - dialogRef.current.show(); - console.log("handleOpen id: ", id) - load(id); - }; - const handleClose = () => { - // @ts-ignore - dialogRef.current.close(); - }; - - - useEffect(() => { - if (props.secret == null) { - return; - } - const splited = splitSecret(props.secret); - if (splited) { - setLoading(true); - axios - .get( - api( - `service-offerings/${splited.namespace}/${splited.secretName}` - ) - ) - .then((response) => { - setLoading(false); - setOfferings(response.data); - }) - .catch((error) => { - setLoading(false); - setError(error); - }); - } - }, []); + const [offerings, setOfferings] = useState(); + const [offeringsCachced, setOfferingsCached] = useState(); + const [serviceOfferingDetails, setServiceOfferingDetails] = + useState(); + const [loading, setLoading] = useState(true); + const [error, setError] = useState(null); + const [labels, setLabels] = useState(); + const dialogRef = useRef(null); + const [planDesc, setPlanDesc] = useState(); + const handleOpen = (id: any) => { + // @ts-ignore + dialogRef.current.show(); + console.log("handleOpen id: ", id) + load(id); + }; + const handleClose = () => { + // @ts-ignore + dialogRef.current.close(); + }; + + + useEffect(() => { + if (props.secret == null) { + return; + } + const splited = splitSecret(props.secret); + if (splited) { + setLoading(true); + axios + .get( + api( + `service-offerings/${splited.namespace}/${splited.secretName}` + ) + ) + .then((response) => { + setLoading(false); + setOfferings(response.data); + }) + .catch((error) => { + setLoading(false); + setError(error); + }); + } + }, []); - if (loading) { - return - } + if (loading) { + return + } + + if (error) { + return + } - if (error) { - return - } - - function filter(e: string) { - return; - console.log("filtering") - // @ts-ignore - setOfferings(offeringsCachced); - const ServiceOfferings = offeringsCachced; - let ii = 0; - // @ts-ignore - for (let i = 0; i < offerings?.items.length; i++) { + function filter(e: string) { + return; + console.log("filtering") // @ts-ignore - if (offerings?.items[i].metadata.displayName.includes(e)) { + setOfferings(offeringsCachced); + const ServiceOfferings = offeringsCachced; + let ii = 0; + // @ts-ignore + for (let i = 0; i < offerings?.items.length; i++) { // @ts-ignore - ServiceOfferings.items[ii] = [offerings?.items[i]]; - ii++; + if (offerings?.items[i].metadata.displayName.includes(e)) { + // @ts-ignore + ServiceOfferings.items[ii] = [offerings?.items[i]]; + ii++; + } } } - } - function getImg(b64: string) { - if (b64 == null) { - return ""; - } else { - return b64; + function getImg(b64: string) { + if (b64 == null) { + return ""; + } else { + return b64; + } } - } - function load(id: string) { - console.log("loading id: ", id) - setLoading(true); - axios - .get(api(`service-offering/${id}`)) - .then((response) => { - console.log("load response: ", response) + function load(id: string) { + console.log("loading id: ", id) + setLoading(true); + axios + .get(api(`service-offering-details/${id}`)) + .then((response) => { + console.log("load response: ", response) + setLoading(false); + setServiceOfferingDetails(response.data); + }) + .catch((error) => { + setLoading(false); + setError(error); + console.log("load error: ", error) + }); setLoading(false); - setServiceOfferingDetails(response.data); - }) - .catch((error) => { - setLoading(false); - setError(error); - console.log("load error: ", error) - }); - setLoading(false); - } + } - const renderData = () => { - // @ts-ignore - if (!Ok(offerings) || !Ok(offerings.items)){ - return - } - //console.log("renderData") - //filter(props.phrase) + const renderData = () => { + // @ts-ignore + if (!Ok(offerings) || !Ok(offerings.items)) { + return + } + //console.log("renderData") + //filter(props.phrase) - return offerings?.items.map((offering, index) => { - return ( - <> - { - console.log("opening id: ", offering.id) - handleOpen(offering.id); - }} - header={ - - - - } - subtitleText={offering.metadata.displayName} - titleText={offering.catalogName} - status={formatStatus(index, offerings?.numItems)} - interactive - /> - } - > + return offerings?.items.map((offering, index) => { + // @ts-ignore + // @ts-ignore + return ( + <> + { + console.log("opening id: ", offering.id) + handleOpen(offering.id); + }} + header={ + + + + } + subtitleText={offering.metadata.displayName} + titleText={offering.catalogName} + status={formatStatus(index, offerings?.numItems)} + interactive + /> + } + > - <> - {createPortal( - Close - } - /> - } - onAfterClose={function _a() {}} - onAfterOpen={function _a() {}} - onBeforeClose={function _a() {}} - onBeforeOpen={function _a() {}} - > - {serviceOfferingDetails?.longDescription} + <> + {createPortal( + Close + } + /> + } + onAfterClose={function _a() { + }} + onAfterOpen={function _a() { + }} + onBeforeClose={function _a() { + }} + onBeforeOpen={function _a() { + }} + > +
+ + {serviceOfferingDetails?.longDescription} + +
- - - - - - - - - - - - - - Option 1 - - - { - const it = ( - - - - - ); - // @ts-ignore - setLabels([...labels, it]); - }} - /> - {labels} - - - - - - - - - - - - Create - - - - -
, - document.body - )} - - - ); - }); - }; + + + + + + + + + + + + + + { + serviceOfferingDetails?.plans.map((plan, index) => + ( + { + console.log("onLoad") + setPlanDesc(plan.description); + }} onClick={() => { + console.log("onClick") + }} onFocus={() => { + console.log("onFocus") + }} + key={index}>{plan.name} X + + ))} + + {planDesc} + + { + const it = ( + + + + + ); + // @ts-ignore + setLabels([...labels, it]); + }} + /> + {labels} + + + + + + + + + + + + Create + + + + +
, + document.body + )} + + + ); + }); + }; - return <>{renderData()}; + return <>{renderData()}; } function splitSecret(secret: string) { - if (secret == null) { - return {}; - } - const secretParts = secret.split(" "); - const secretName = secretParts[0]; - let namespace = secretParts[2].replace("(", ""); - namespace = namespace.replace(")", ""); - return { secretName, namespace }; + if (secret == null) { + return {}; + } + const secretParts = secret.split(" "); + const secretName = secretParts[0]; + let namespace = secretParts[2].replace("(", ""); + namespace = namespace.replace(")", ""); + return {secretName, namespace}; } function formatStatus(i: number, j: number) { - return `${++i} of ${j}`; + return `${++i} of ${j}`; } export default ServiceOfferingsView; diff --git a/ui/src/shared/models.tsx b/ui/src/shared/models.tsx index 8ec33bfc8..77b3d5d38 100644 --- a/ui/src/shared/models.tsx +++ b/ui/src/shared/models.tsx @@ -27,6 +27,14 @@ export interface ServiceOfferingMetadata { export interface ServiceOfferingDetails { longDescription: string; + plans: ServiceOfferingPlan[]; +} + +export interface ServiceOfferingPlan { + name: string; + description: string; + supportUrl: string; + documentationUrl: string; } export interface ServiceInstances { @@ -45,12 +53,4 @@ export interface ServiceInstanceBindings { id: string; name: string; namespace: string; -} - -export interface ServiceInstanceDetails { - id: string; - name: string; - context: string; - namespace: string; -} - +} \ No newline at end of file From e36a69fb19a8cb6cbe02e23392cee794e5f9bbea Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Tue, 11 Jun 2024 16:42:50 +0200 Subject: [PATCH 18/23] wip --- ui/pkg/sumdb/sum.golang.org/latest | 5 + ui/src/components/ServiceOfferingsView.tsx | 137 +++++---------------- ui/src/components/View.tsx | 14 --- 3 files changed, 33 insertions(+), 123 deletions(-) create mode 100644 ui/pkg/sumdb/sum.golang.org/latest diff --git a/ui/pkg/sumdb/sum.golang.org/latest b/ui/pkg/sumdb/sum.golang.org/latest new file mode 100644 index 000000000..ce2ff0cf2 --- /dev/null +++ b/ui/pkg/sumdb/sum.golang.org/latest @@ -0,0 +1,5 @@ +go.sum database tree +25732566 +mi+TFQdCPfR1duAez/BG2HnZJzdfYFtcrG1pdQ3CgIc= + +— sum.golang.org Az3grjBLEZ3uav8UdDJMd9UI4Jz46U9abHAHqCIj7IzUFuZ1ZhcqNEcLOatkXUisTe2mSJPbx6kYSVr6ev7+m3/NKwI= diff --git a/ui/src/components/ServiceOfferingsView.tsx b/ui/src/components/ServiceOfferingsView.tsx index 1cb95754b..88444201d 100644 --- a/ui/src/components/ServiceOfferingsView.tsx +++ b/ui/src/components/ServiceOfferingsView.tsx @@ -5,30 +5,26 @@ import axios from "axios"; import {ServiceOfferingDetails, ServiceOfferings} from "../shared/models"; import api from "../shared/api"; import "@ui5/webcomponents-icons/dist/AllIcons.js" +import "@ui5/webcomponents-fiori/dist/illustrations/NoEntries.js" import Ok from "../shared/validator"; function ServiceOfferingsView(props: any) { const [offerings, setOfferings] = useState(); - const [offeringsCachced, setOfferingsCached] = useState(); - const [serviceOfferingDetails, setServiceOfferingDetails] = - useState(); + const [serviceOfferingDetails, setServiceOfferingDetails] = useState(); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); - const [labels, setLabels] = useState(); const dialogRef = useRef(null); - const [planDesc, setPlanDesc] = useState(); + const handleOpen = (id: any) => { // @ts-ignore dialogRef.current.show(); - console.log("handleOpen id: ", id) load(id); }; const handleClose = () => { // @ts-ignore dialogRef.current.close(); }; - - + useEffect(() => { if (props.secret == null) { return; @@ -51,35 +47,18 @@ function ServiceOfferingsView(props: any) { setError(error); }); } + setLoading(false); }, []); if (loading) { - return + return } if (error) { return } - function filter(e: string) { - return; - console.log("filtering") - // @ts-ignore - setOfferings(offeringsCachced); - const ServiceOfferings = offeringsCachced; - let ii = 0; - // @ts-ignore - for (let i = 0; i < offerings?.items.length; i++) { - // @ts-ignore - if (offerings?.items[i].metadata.displayName.includes(e)) { - // @ts-ignore - ServiceOfferings.items[ii] = [offerings?.items[i]]; - ii++; - } - } - } - function getImg(b64: string) { if (b64 == null) { return ""; @@ -89,19 +68,16 @@ function ServiceOfferingsView(props: any) { } function load(id: string) { - console.log("loading id: ", id) setLoading(true); axios .get(api(`service-offering-details/${id}`)) .then((response) => { - console.log("load response: ", response) setLoading(false); setServiceOfferingDetails(response.data); }) .catch((error) => { setLoading(false); setError(error); - console.log("load error: ", error) }); setLoading(false); } @@ -111,11 +87,7 @@ function ServiceOfferingsView(props: any) { if (!Ok(offerings) || !Ok(offerings.items)) { return } - //console.log("renderData") - //filter(props.phrase) - return offerings?.items.map((offering, index) => { - // @ts-ignore // @ts-ignore return ( <> @@ -124,10 +96,8 @@ function ServiceOfferingsView(props: any) { style={{ width: "20%", height: "0", - padding: "10px" }} onClick={() => { - console.log("opening id: ", offering.id) handleOpen(offering.id); }} header={ @@ -137,7 +107,7 @@ function ServiceOfferingsView(props: any) { } - subtitleText={offering.metadata.displayName} + subtitleText={offering.description} titleText={offering.catalogName} status={formatStatus(index, offerings?.numItems)} interactive @@ -159,104 +129,53 @@ function ServiceOfferingsView(props: any) { } /> } - onAfterClose={function _a() { - }} - onAfterOpen={function _a() { - }} - onBeforeClose={function _a() { - }} - onBeforeOpen={function _a() { - }} > -
{serviceOfferingDetails?.longDescription} -
+ + + + + + { + serviceOfferingDetails?.plans.map((plan, index) => + ( + {plan.name} + + )) + } + + + + - + - - - { - serviceOfferingDetails?.plans.map((plan, index) => - ( - { - console.log("onLoad") - setPlanDesc(plan.description); - }} onClick={() => { - console.log("onClick") - }} onFocus={() => { - console.log("onFocus") - }} - key={index}>{plan.name} X - - ))} - - {planDesc} - - { - const it = ( - - - - - ); - // @ts-ignore - setLabels([...labels, it]); - }} - /> - {labels} - - - - - - - - - - - - Create - - , diff --git a/ui/src/components/View.tsx b/ui/src/components/View.tsx index 7c07ab633..78d8daa89 100644 --- a/ui/src/components/View.tsx +++ b/ui/src/components/View.tsx @@ -11,10 +11,6 @@ function Overview(props: any) { function handler(e: any) { setSecret(e); } - function handler2(e: any) { - console.log("handler2") - setPhrase(e); - } return ( <> @@ -29,14 +25,6 @@ function Overview(props: any) { startContent={Select your credentials:} > handler(e)} style={{ width: "100vw" }} /> - ){ - console.log("onInput") - const phrase=event.target.value; - handler2(phrase); - }} - valueState="None" - /> <>
@@ -54,14 +42,12 @@ function Overview(props: any) { > { setPageContent(); }} /> { setPageContent(); }} From ad0c30a616921a4e0f86a57c44a16aec17fe277e Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Tue, 11 Jun 2024 16:50:40 +0200 Subject: [PATCH 19/23] wip --- internal/api/api.go | 15 +-------------- internal/api/vm/converters.go | 21 --------------------- internal/api/vm/vm.go | 12 ------------ ui/pkg/sumdb/sum.golang.org/latest | 5 ----- 4 files changed, 1 insertion(+), 52 deletions(-) delete mode 100644 ui/pkg/sumdb/sum.golang.org/latest diff --git a/internal/api/api.go b/internal/api/api.go index 60e0ec9e4..15042c9da 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -28,10 +28,9 @@ func (a *API) Start() { mux := http.NewServeMux() mux.HandleFunc("GET /api/secrets", a.ListSecrets) mux.HandleFunc("GET /api/service-instances", a.ListServiceInstances) - mux.HandleFunc("PUT /api/service-instance", a.CreateServiceInstance) + mux.HandleFunc("PUT /api/service-instance/{id}", a.CreateServiceInstance) mux.HandleFunc("GET /api/service-instance/{id}", a.GetServiceInstance) mux.HandleFunc("GET /api/service-offerings/{namespace}/{name}", a.ListServiceOfferings) - mux.HandleFunc("GET /api/service-offering-details/{id}", a.GetServiceOfferingDetails) go func() { err := http.ListenAndServe(":3006", mux) if err != nil { @@ -75,18 +74,6 @@ func (a *API) GetServiceInstance(writer http.ResponseWriter, request *http.Reque // not implemented in SM } -func (a *API) GetServiceOfferingDetails(writer http.ResponseWriter, request *http.Request) { - a.setupCors(writer, request) - // not implemented in SM - serviceOfferingId := request.PathValue("id") - details, err := a.serviceManager.ServiceOfferingDetails(serviceOfferingId) - if returnError(writer, err) { - return - } - response, err := json.Marshal(vm.ToServiceOfferingDetailsVM(details)) - returnResponse(writer, response, err) -} - func (a *API) ListServiceInstances(writer http.ResponseWriter, request *http.Request) { a.setupCors(writer, request) // will be taken from SM diff --git a/internal/api/vm/converters.go b/internal/api/vm/converters.go index 90b535b59..ae1747117 100644 --- a/internal/api/vm/converters.go +++ b/internal/api/vm/converters.go @@ -43,24 +43,3 @@ func ToServiceOfferingsVM(offerings *types.ServiceOfferings) ServiceOfferings { } return serviceOfferings } - -func ToServiceOfferingDetailsVM(serviceOfferings *types.ServiceOfferingDetails) ServiceOfferingDetails { - details := ServiceOfferingDetails{ - Plans: []ServiceOfferingPlan{}, - } - - for _, plan := range serviceOfferings.ServicePlans.ServicePlans { - details.LongDescription, _ = serviceOfferings.MetadataValueByFieldName(types.ServiceOfferingLongDescription) - supportUrl, _ := serviceOfferings.MetadataValueByFieldName(types.ServiceOfferingSupportURL) - documentationUrl, _ := serviceOfferings.MetadataValueByFieldName(types.ServiceOfferingDocumentationUrl) - planReturn := ServiceOfferingPlan{ - Name: plan.Name, - Description: plan.Description, - DocumentationUrl: documentationUrl, - SupportUrl: supportUrl, - } - details.Plans = append(details.Plans, planReturn) - } - - return details -} diff --git a/internal/api/vm/vm.go b/internal/api/vm/vm.go index 3aa4d4288..031a86fb6 100644 --- a/internal/api/vm/vm.go +++ b/internal/api/vm/vm.go @@ -35,15 +35,3 @@ type ServiceInstance struct { Name string `json:"name"` Namespace string `json:"namespace"` } - -type ServiceOfferingDetails struct { - LongDescription string `json:"longDescription"` - Plans []ServiceOfferingPlan `json:"plans"` -} - -type ServiceOfferingPlan struct { - Name string `json:"name"` - Description string `json:"description"` - DocumentationUrl string `json:"documentationUrl"` - SupportUrl string `json:"supportUrl"` -} diff --git a/ui/pkg/sumdb/sum.golang.org/latest b/ui/pkg/sumdb/sum.golang.org/latest deleted file mode 100644 index ce2ff0cf2..000000000 --- a/ui/pkg/sumdb/sum.golang.org/latest +++ /dev/null @@ -1,5 +0,0 @@ -go.sum database tree -25732566 -mi+TFQdCPfR1duAez/BG2HnZJzdfYFtcrG1pdQ3CgIc= - -— sum.golang.org Az3grjBLEZ3uav8UdDJMd9UI4Jz46U9abHAHqCIj7IzUFuZ1ZhcqNEcLOatkXUisTe2mSJPbx6kYSVr6ev7+m3/NKwI= From 44b411f4fd61b8e8464ecf72303dc9a454488011 Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:17:37 +0200 Subject: [PATCH 20/23] wip --- internal/api/api.go | 29 ++++++++++++++++++++++ internal/api/vm/converters.go | 21 ++++++++++++++++ internal/api/vm/vm.go | 12 +++++++++ ui/src/components/SecretsView.tsx | 1 + ui/src/components/ServiceInstancesView.tsx | 10 +------- ui/src/components/ServiceOfferingsView.tsx | 7 +++--- 6 files changed, 68 insertions(+), 12 deletions(-) diff --git a/internal/api/api.go b/internal/api/api.go index 15042c9da..799eb21da 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -31,6 +31,8 @@ func (a *API) Start() { mux.HandleFunc("PUT /api/service-instance/{id}", a.CreateServiceInstance) mux.HandleFunc("GET /api/service-instance/{id}", a.GetServiceInstance) mux.HandleFunc("GET /api/service-offerings/{namespace}/{name}", a.ListServiceOfferings) + mux.HandleFunc("GET /api/service-offering/{id}", a.GetServiceOffering) + go func() { err := http.ListenAndServe(":3006", mux) if err != nil { @@ -43,6 +45,28 @@ func (a *API) CreateServiceInstance(writer http.ResponseWriter, request *http.Re return } +func (a *API) GetServiceOffering(writer http.ResponseWriter, request *http.Request) { + a.setupCors(writer, request) + id := request.PathValue("id") + details, err := a.serviceManager.ServiceOfferingDetails(id) + if returnError(writer, err) { + return + } + response, err := json.Marshal(vm.ToServiceOfferingDetailsVM(details)) + returnResponse(writer, response, err) +} + +func (a *API) GetServiceOfferingDetails(writer http.ResponseWriter, request *http.Request) { + a.setupCors(writer, request) + serviceOfferingId := request.PathValue("id") + details, err := a.serviceManager.ServiceOfferingDetails(serviceOfferingId) + if returnError(writer, err) { + return + } + response, err := json.Marshal(vm.ToServiceOfferingDetailsVM(details)) + returnResponse(writer, response, err) +} + func (a *API) ListServiceOfferings(writer http.ResponseWriter, request *http.Request) { a.setupCors(writer, request) namespace := request.PathValue("namespace") @@ -59,6 +83,11 @@ func (a *API) ListServiceOfferings(writer http.ResponseWriter, request *http.Req returnResponse(writer, response, err) } +func (a *API) ListServiceOfferingsDetails(writer http.ResponseWriter, request *http.Request) { + a.setupCors(writer, request) + // not implemented in SM +} + func (a *API) ListSecrets(writer http.ResponseWriter, request *http.Request) { a.setupCors(writer, request) secrets, err := a.secretProvider.All(context.Background()) diff --git a/internal/api/vm/converters.go b/internal/api/vm/converters.go index ae1747117..90b535b59 100644 --- a/internal/api/vm/converters.go +++ b/internal/api/vm/converters.go @@ -43,3 +43,24 @@ func ToServiceOfferingsVM(offerings *types.ServiceOfferings) ServiceOfferings { } return serviceOfferings } + +func ToServiceOfferingDetailsVM(serviceOfferings *types.ServiceOfferingDetails) ServiceOfferingDetails { + details := ServiceOfferingDetails{ + Plans: []ServiceOfferingPlan{}, + } + + for _, plan := range serviceOfferings.ServicePlans.ServicePlans { + details.LongDescription, _ = serviceOfferings.MetadataValueByFieldName(types.ServiceOfferingLongDescription) + supportUrl, _ := serviceOfferings.MetadataValueByFieldName(types.ServiceOfferingSupportURL) + documentationUrl, _ := serviceOfferings.MetadataValueByFieldName(types.ServiceOfferingDocumentationUrl) + planReturn := ServiceOfferingPlan{ + Name: plan.Name, + Description: plan.Description, + DocumentationUrl: documentationUrl, + SupportUrl: supportUrl, + } + details.Plans = append(details.Plans, planReturn) + } + + return details +} diff --git a/internal/api/vm/vm.go b/internal/api/vm/vm.go index 031a86fb6..3aa4d4288 100644 --- a/internal/api/vm/vm.go +++ b/internal/api/vm/vm.go @@ -35,3 +35,15 @@ type ServiceInstance struct { Name string `json:"name"` Namespace string `json:"namespace"` } + +type ServiceOfferingDetails struct { + LongDescription string `json:"longDescription"` + Plans []ServiceOfferingPlan `json:"plans"` +} + +type ServiceOfferingPlan struct { + Name string `json:"name"` + Description string `json:"description"` + DocumentationUrl string `json:"documentationUrl"` + SupportUrl string `json:"supportUrl"` +} diff --git a/ui/src/components/SecretsView.tsx b/ui/src/components/SecretsView.tsx index 5a377fb5b..072292c0e 100644 --- a/ui/src/components/SecretsView.tsx +++ b/ui/src/components/SecretsView.tsx @@ -29,6 +29,7 @@ function SecretsView(props: any) { setSecrets(undefined); props.handler(formatSecretText("", "")); }); + setLoading(false); }, []); if (loading) { diff --git a/ui/src/components/ServiceInstancesView.tsx b/ui/src/components/ServiceInstancesView.tsx index f6bcc57c7..cb8f94253 100644 --- a/ui/src/components/ServiceInstancesView.tsx +++ b/ui/src/components/ServiceInstancesView.tsx @@ -32,6 +32,7 @@ function ServiceInstancesView() { setLoading(false); setError(error); }); + setLoading(false) }, []); if (loading) { @@ -74,10 +75,6 @@ function ServiceInstancesView() { } onClick={handleOpen} - onLoadMore={function _a() {}} - onPopinChange={function _a() {}} - onRowClick={function _a() { }} - onSelectionChange={function _a() {}} > {renderData()} @@ -101,14 +98,9 @@ function ServiceInstancesView() { } headerText="Dialog Header" - onAfterClose={function _a() {}} - onAfterOpen={function _a() {}} - onBeforeClose={function _a() {}} - onBeforeOpen={function _a() {}} > - List Item 1 , diff --git a/ui/src/components/ServiceOfferingsView.tsx b/ui/src/components/ServiceOfferingsView.tsx index 88444201d..45f9b24ee 100644 --- a/ui/src/components/ServiceOfferingsView.tsx +++ b/ui/src/components/ServiceOfferingsView.tsx @@ -6,6 +6,7 @@ import {ServiceOfferingDetails, ServiceOfferings} from "../shared/models"; import api from "../shared/api"; import "@ui5/webcomponents-icons/dist/AllIcons.js" import "@ui5/webcomponents-fiori/dist/illustrations/NoEntries.js" +import "@ui5/webcomponents-fiori/dist/illustrations/AllIllustrations.js" import Ok from "../shared/validator"; function ServiceOfferingsView(props: any) { @@ -46,8 +47,8 @@ function ServiceOfferingsView(props: any) { setLoading(false); setError(error); }); + setLoading(false); } - setLoading(false); }, []); @@ -70,7 +71,7 @@ function ServiceOfferingsView(props: any) { function load(id: string) { setLoading(true); axios - .get(api(`service-offering-details/${id}`)) + .get(api(`service-offering/${id}`)) .then((response) => { setLoading(false); setServiceOfferingDetails(response.data); @@ -81,7 +82,7 @@ function ServiceOfferingsView(props: any) { }); setLoading(false); } - + const renderData = () => { // @ts-ignore if (!Ok(offerings) || !Ok(offerings.items)) { From e6ebbd7d67673dd8a24f886d0f2f2023a11c7b76 Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:19:40 +0200 Subject: [PATCH 21/23] wip --- internal/api/api.go | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/internal/api/api.go b/internal/api/api.go index 799eb21da..4cdff694b 100644 --- a/internal/api/api.go +++ b/internal/api/api.go @@ -56,17 +56,6 @@ func (a *API) GetServiceOffering(writer http.ResponseWriter, request *http.Reque returnResponse(writer, response, err) } -func (a *API) GetServiceOfferingDetails(writer http.ResponseWriter, request *http.Request) { - a.setupCors(writer, request) - serviceOfferingId := request.PathValue("id") - details, err := a.serviceManager.ServiceOfferingDetails(serviceOfferingId) - if returnError(writer, err) { - return - } - response, err := json.Marshal(vm.ToServiceOfferingDetailsVM(details)) - returnResponse(writer, response, err) -} - func (a *API) ListServiceOfferings(writer http.ResponseWriter, request *http.Request) { a.setupCors(writer, request) namespace := request.PathValue("namespace") @@ -83,11 +72,6 @@ func (a *API) ListServiceOfferings(writer http.ResponseWriter, request *http.Req returnResponse(writer, response, err) } -func (a *API) ListServiceOfferingsDetails(writer http.ResponseWriter, request *http.Request) { - a.setupCors(writer, request) - // not implemented in SM -} - func (a *API) ListSecrets(writer http.ResponseWriter, request *http.Request) { a.setupCors(writer, request) secrets, err := a.secretProvider.All(context.Background()) From dee2f138edc3cc2a566b079fe7636a883076980f Mon Sep 17 00:00:00 2001 From: ukff <110393214+ukff@users.noreply.github.com> Date: Tue, 11 Jun 2024 17:51:41 +0200 Subject: [PATCH 22/23] wip --- ui/src/components/SecretsView.tsx | 6 +++++- ui/src/components/View.tsx | 7 ++++--- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/ui/src/components/SecretsView.tsx b/ui/src/components/SecretsView.tsx index 072292c0e..d3f15b7a2 100644 --- a/ui/src/components/SecretsView.tsx +++ b/ui/src/components/SecretsView.tsx @@ -4,6 +4,7 @@ import {useEffect, useState} from "react"; import {Secrets} from "../shared/models"; import Ok from "../shared/validator"; import api from "../shared/api"; +import ServiceOfferingsView from "./ServiceOfferingsView"; function SecretsView(props: any) { const [secrets, setSecrets] = useState(); @@ -18,7 +19,9 @@ function SecretsView(props: any) { setLoading(false); setSecrets(response.data); if (Ok(response.data) && Ok(response.data.items)) { - props.handler(formatSecretText(response.data.items[0].name, response.data.items[0].namespace)); + const secret = formatSecretText(response.data.items[0].name, response.data.items[0].namespace) + props.handler(secret); + props.setPageContent(); } else { props.handler(formatSecretText("", "")); } @@ -66,6 +69,7 @@ function SecretsView(props: any) { onChange={(e) => { // @ts-ignore props.handler(e.target.value); + props.setPageContent(); }} > {renderData()} diff --git a/ui/src/components/View.tsx b/ui/src/components/View.tsx index 78d8daa89..5fd835c79 100644 --- a/ui/src/components/View.tsx +++ b/ui/src/components/View.tsx @@ -6,7 +6,6 @@ import React from "react"; function Overview(props: any) { const [secret, setSecret] = React.useState(null); - const [phrase, setPhrase] = React.useState(null); const [pageContent, setPageContent] = React.useState(); function handler(e: any) { setSecret(e); @@ -24,7 +23,9 @@ function Overview(props: any) { endContent={SAP BTP, Kyma runtime} startContent={Select your credentials:} > - handler(e)} style={{ width: "100vw" }} /> + handler(e)} style={{ width: "100vw" }} + setPageContent={(e: any) => setPageContent(e)} + /> <>
@@ -43,7 +44,7 @@ function Overview(props: any) { { - setPageContent(); + setPageContent(); }} /> Date: Tue, 11 Jun 2024 19:09:16 +0200 Subject: [PATCH 23/23] wip --- ui/src/components/SecretsView.tsx | 7 +++--- ui/src/components/ServiceInstancesView.tsx | 6 ++--- ui/src/components/ServiceOfferingsView.tsx | 26 ++++++++++++---------- ui/src/components/View.tsx | 4 ++-- 4 files changed, 22 insertions(+), 21 deletions(-) diff --git a/ui/src/components/SecretsView.tsx b/ui/src/components/SecretsView.tsx index d3f15b7a2..af37c28a3 100644 --- a/ui/src/components/SecretsView.tsx +++ b/ui/src/components/SecretsView.tsx @@ -41,7 +41,7 @@ function SecretsView(props: any) { if (error) { props.handler(formatSecretText("", "")); - return + return } const renderData = () => { @@ -68,8 +68,9 @@ function SecretsView(props: any) { style={{width: "20vw"}} onChange={(e) => { // @ts-ignore - props.handler(e.target.value); - props.setPageContent(); + const secret = e .target.value; + props.handler(secret); + props.setPageContent(); }} > {renderData()} diff --git a/ui/src/components/ServiceInstancesView.tsx b/ui/src/components/ServiceInstancesView.tsx index cb8f94253..dc1d54ff1 100644 --- a/ui/src/components/ServiceInstancesView.tsx +++ b/ui/src/components/ServiceInstancesView.tsx @@ -40,13 +40,13 @@ function ServiceInstancesView() { } if (error) { - return + return } const renderData = () => { // @ts-ignore if (!Ok(serviceInstances) || !Ok(serviceInstances.items)) { - return + return } return serviceInstances?.items.map((brief, index) => { return ( @@ -100,8 +100,6 @@ function ServiceInstancesView() { headerText="Dialog Header" > - - , document.body diff --git a/ui/src/components/ServiceOfferingsView.tsx b/ui/src/components/ServiceOfferingsView.tsx index 45f9b24ee..2a9a66b3e 100644 --- a/ui/src/components/ServiceOfferingsView.tsx +++ b/ui/src/components/ServiceOfferingsView.tsx @@ -27,16 +27,16 @@ function ServiceOfferingsView(props: any) { }; useEffect(() => { - if (props.secret == null) { + if (!Ok(props.secret)) { return; } - const splited = splitSecret(props.secret); - if (splited) { + const secretText = splitSecret(props.secret); + if (Ok(secretText)) { setLoading(true); axios .get( api( - `service-offerings/${splited.namespace}/${splited.secretName}` + `service-offerings/${secretText.namespace}/${secretText.secretName}` ) ) .then((response) => { @@ -49,7 +49,7 @@ function ServiceOfferingsView(props: any) { }); setLoading(false); } - }, []); + }, [props.secret]); if (loading) { @@ -57,12 +57,13 @@ function ServiceOfferingsView(props: any) { } if (error) { - return + return } function getImg(b64: string) { - if (b64 == null) { - return ""; + if (!Ok(b64) || b64 === "not found") { + // grey color + return "data:image/gif;base64,R0lGODlhAQABAIAAAMLCwgAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=="; } else { return b64; } @@ -86,7 +87,7 @@ function ServiceOfferingsView(props: any) { const renderData = () => { // @ts-ignore if (!Ok(offerings) || !Ok(offerings.items)) { - return + return } return offerings?.items.map((offering, index) => { // @ts-ignore @@ -96,7 +97,7 @@ function ServiceOfferingsView(props: any) { key={index} style={{ width: "20%", - height: "0", + height: "5%", }} onClick={() => { handleOpen(offering.id); @@ -114,12 +115,13 @@ function ServiceOfferingsView(props: any) { interactive /> } - > + > + <> {createPortal( (); - function handler(e: any) { - setSecret(e); + function handler(s: any) { + setSecret(s); } return (