diff --git a/api/server/router/cluster/cluster.go b/api/server/router/cluster/cluster.go index 4702b402..d847f175 100644 --- a/api/server/router/cluster/cluster.go +++ b/api/server/router/cluster/cluster.go @@ -85,14 +85,4 @@ func (cr *clusterRouter) initRoutes(httpEngine *gin.Engine) { indexerRoute.GET("/clusters/:cluster/resources/:resource/namespaces/:namespace", cr.listIndexerResources) } - // 调用 helm 对象 - helmRoute := httpEngine.Group(helmBaseURL) - { - // Helm Release API 列表 - helmRoute.POST("/clusters/:cluster/v1/namespaces/:namespace/releases", cr.InstallRelease) - helmRoute.PUT("/clusters/:cluster/v1/namespaces/:namespace/releases", cr.UpgradeRelease) - helmRoute.DELETE("/clusters/:cluster/v1/namespaces/:namespace/releases/:name", cr.UninstallRelease) - helmRoute.GET("/clusters/:cluster/v1/namespaces/:namespace/releases/:name", cr.GetRelease) - helmRoute.GET("/clusters/:cluster/v1/namespaces/:namespace/releases", cr.ListReleases) - } } diff --git a/api/server/router/helm/helm.go b/api/server/router/helm/helm.go new file mode 100644 index 00000000..b4048259 --- /dev/null +++ b/api/server/router/helm/helm.go @@ -0,0 +1,66 @@ +/* +Copyright 2021 The Pixiu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package helm + +import ( + "github.com/gin-gonic/gin" + + "github.com/caoyingjunz/pixiu/cmd/app/options" + "github.com/caoyingjunz/pixiu/pkg/controller" +) + +const ( + helmBaseURL = "/pixiu/helms" +) + +type helmRouter struct { + c controller.PixiuInterface +} + +func NewRouter(o *options.Options) { + hr := &helmRouter{ + c: o.Controller, + } + hr.initRoutes(o.HttpEngine) +} + +func (hr *helmRouter) initRoutes(httpEngine *gin.Engine) { + + helmRoute := httpEngine.Group(helmBaseURL) + { + // helm Repository + helmRoute.POST("/repositories", hr.createRepository) + helmRoute.PUT("/repositories/:id", hr.updateRepository) + helmRoute.DELETE("/repositories/:id", hr.deleteRepository) + helmRoute.GET("/repositories/:id", hr.getRepository) + helmRoute.GET("/repositories", hr.listRepositories) + + helmRoute.GET("/repositories/:id/charts", hr.getRepoCharts) + helmRoute.GET("/repositories/charts", hr.getRepoChartsByURL) + helmRoute.GET("/repositories/values", hr.getChartValues) + + // Helm Release + helmRoute.POST("/clusters/:cluster/namespaces/:namespace/releases", hr.InstallRelease) + helmRoute.PUT("/clusters/:cluster/namespaces/:namespace/releases", hr.UpgradeRelease) + helmRoute.DELETE("/clusters/:cluster/namespaces/:namespace/releases/:name", hr.UninstallRelease) + helmRoute.GET("/clusters/:cluster/namespaces/:namespace/releases/:name", hr.GetRelease) + helmRoute.GET("/clusters/:cluster/namespaces/:namespace/releases", hr.ListReleases) + + helmRoute.GET("/clusters/:cluster/namespaces/:namespace/releases/:name/history", hr.GetReleaseHistory) + helmRoute.POST("/clusters/:cluster/namespaces/:namespace/releases/:name/rollback", hr.RollbackRelease) + } +} diff --git a/api/server/router/cluster/helm_routes.go b/api/server/router/helm/release_routes.go similarity index 74% rename from api/server/router/cluster/helm_routes.go rename to api/server/router/helm/release_routes.go index f0e07e08..bda1bc09 100644 --- a/api/server/router/cluster/helm_routes.go +++ b/api/server/router/helm/release_routes.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package cluster +package helm import ( "github.com/gin-gonic/gin" @@ -23,10 +23,10 @@ import ( "github.com/caoyingjunz/pixiu/pkg/types" ) -// GetRelease retrieves a release by its name from the specified namespace and cluster +// GetRelease retrieves a release by its name in the specified namespace and cluster // -// @Summary get a release by name -// @Description retrieves a release from the specified namespace and cluster using the provided name +// @Summary get a release +// @Description retrieves a release from the specified namespace and cluster // @Tags helm // @Accept json // @Produce json @@ -37,8 +37,8 @@ import ( // @Failure 400 {object} httputils.Response // @Failure 404 {object} httputils.Response // @Failure 500 {object} httputils.Response -// @Router /helm/release/{cluster}/{namespace}/{name} [get] -func (cr *clusterRouter) GetRelease(c *gin.Context) { +// @Router /helm/releases/{cluster}/{namespace}/{name} [get] +func (hr *helmRouter) GetRelease(c *gin.Context) { r := httputils.NewResponse() var ( err error @@ -49,18 +49,17 @@ func (cr *clusterRouter) GetRelease(c *gin.Context) { return } - if r.Result, err = cr.c.Cluster().Helm(helmMeta.Cluster).Releases(helmMeta.Namespace).GetRelease(c, helmMeta.Name); err != nil { + if r.Result, err = hr.c.Helm().Release(helmMeta.Cluster, helmMeta.Namespace).Get(c, helmMeta.Name); err != nil { httputils.SetFailed(c, r, err) return } - httputils.SetSuccess(c, r) } -// ListReleases retrieves a list of all releases in the specified namespace and cluster +// ListReleases lists all releases in the specified namespace and cluster // -// @Summary list all releases -// @Description retrieves a list of all releases from the specified namespace and cluster +// @Summary list releases +// @Description lists all releases in the specified namespace and cluster // @Tags helm // @Accept json // @Produce json @@ -71,7 +70,7 @@ func (cr *clusterRouter) GetRelease(c *gin.Context) { // @Failure 404 {object} httputils.Response // @Failure 500 {object} httputils.Response // @Router /helm/releases/{cluster}/{namespace} [get] -func (cr *clusterRouter) ListReleases(c *gin.Context) { +func (hr *helmRouter) ListReleases(c *gin.Context) { r := httputils.NewResponse() var ( err error @@ -82,7 +81,7 @@ func (cr *clusterRouter) ListReleases(c *gin.Context) { return } - if r.Result, err = cr.c.Cluster().Helm(helmMeta.Cluster).Releases(helmMeta.Namespace).ListRelease(c); err != nil { + if r.Result, err = hr.c.Helm().Release(helmMeta.Cluster, helmMeta.Namespace).List(c); err != nil { httputils.SetFailed(c, r, err) return } @@ -92,8 +91,8 @@ func (cr *clusterRouter) ListReleases(c *gin.Context) { // InstallRelease installs a new release in the specified namespace and cluster // -// @Summary install a new release -// @Description installs a new release into the specified Kubernetes namespace and cluster +// @Summary install a release +// @Description installs a release in the specified Kubernetes namespace and cluster // @Tags helm // @Accept json // @Produce json @@ -102,10 +101,9 @@ func (cr *clusterRouter) ListReleases(c *gin.Context) { // @Param body body types.ReleaseForm true "Release information" // @Success 200 {object} httputils.Response // @Failure 400 {object} httputils.Response -// @Failure 404 {object} httputils.Response // @Failure 500 {object} httputils.Response // @Router /helm/releases/{cluster}/{namespace} [post] -func (cr *clusterRouter) InstallRelease(c *gin.Context) { +func (hr *helmRouter) InstallRelease(c *gin.Context) { r := httputils.NewResponse() var ( err error @@ -117,7 +115,7 @@ func (cr *clusterRouter) InstallRelease(c *gin.Context) { return } - if r.Result, err = cr.c.Cluster().Helm(helmMeta.Cluster).Releases(helmMeta.Namespace).InstallRelease(c, &releaseOpt); err != nil { + if r.Result, err = hr.c.Helm().Release(helmMeta.Cluster, helmMeta.Namespace).Install(c, &releaseOpt); err != nil { httputils.SetFailed(c, r, err) return } @@ -128,7 +126,7 @@ func (cr *clusterRouter) InstallRelease(c *gin.Context) { // UninstallRelease uninstalls a release from the specified namespace and cluster // // @Summary uninstall a release -// @Description uninstalls a release from the specified namespace and cluster +// @Description uninstalls a release from the specified Kubernetes namespace and cluster // @Tags helm // @Accept json // @Produce json @@ -140,7 +138,7 @@ func (cr *clusterRouter) InstallRelease(c *gin.Context) { // @Failure 404 {object} httputils.Response // @Failure 500 {object} httputils.Response // @Router /helm/releases/{cluster}/{namespace}/{name} [delete] -func (cr *clusterRouter) UninstallRelease(c *gin.Context) { +func (hr *helmRouter) UninstallRelease(c *gin.Context) { r := httputils.NewResponse() var ( err error @@ -151,7 +149,7 @@ func (cr *clusterRouter) UninstallRelease(c *gin.Context) { return } - if r.Result, err = cr.c.Cluster().Helm(helmMeta.Cluster).Releases(helmMeta.Namespace).UninstallRelease(c, helmMeta.Name); err != nil { + if r.Result, err = hr.c.Helm().Release(helmMeta.Cluster, helmMeta.Namespace).Uninstall(c, helmMeta.Name); err != nil { httputils.SetFailed(c, r, err) return } @@ -162,7 +160,7 @@ func (cr *clusterRouter) UninstallRelease(c *gin.Context) { // UpgradeRelease upgrades a release in the specified namespace and cluster // // @Summary upgrade a release -// @Description upgrades a release in the specified namespace and cluster +// @Description upgrades a release in the specified Kubernetes namespace and cluster // @Tags helm // @Accept json // @Produce json @@ -172,10 +170,9 @@ func (cr *clusterRouter) UninstallRelease(c *gin.Context) { // @Param body body types.ReleaseForm true "Release information" // @Success 200 {object} httputils.Response // @Failure 400 {object} httputils.Response -// @Failure 404 {object} httputils.Response // @Failure 500 {object} httputils.Response // @Router /helm/releases/{cluster}/{namespace}/{name} [put] -func (cr *clusterRouter) UpgradeRelease(c *gin.Context) { +func (hr *helmRouter) UpgradeRelease(c *gin.Context) { r := httputils.NewResponse() var ( err error @@ -187,7 +184,7 @@ func (cr *clusterRouter) UpgradeRelease(c *gin.Context) { return } - if r.Result, err = cr.c.Cluster().Helm(helmMeta.Cluster).Releases(helmMeta.Namespace).UpgradeRelease(c, &releaseOpt); err != nil { + if r.Result, err = hr.c.Helm().Release(helmMeta.Cluster, helmMeta.Namespace).Upgrade(c, &releaseOpt); err != nil { httputils.SetFailed(c, r, err) return } @@ -210,7 +207,7 @@ func (cr *clusterRouter) UpgradeRelease(c *gin.Context) { // @Failure 404 {object} httputils.Response // @Failure 500 {object} httputils.Response // @Router /helm/releases/history/{cluster}/{namespace}/{name} [get] -func (cr *clusterRouter) GetReleaseHistory(c *gin.Context) { +func (hr *helmRouter) GetReleaseHistory(c *gin.Context) { r := httputils.NewResponse() var ( err error @@ -221,7 +218,7 @@ func (cr *clusterRouter) GetReleaseHistory(c *gin.Context) { return } - if r.Result, err = cr.c.Cluster().Helm(helmMeta.Cluster).Releases(helmMeta.Namespace).GetReleaseHistory(c, helmMeta.Name); err != nil { + if r.Result, err = hr.c.Helm().Release(helmMeta.Cluster, helmMeta.Namespace).History(c, helmMeta.Name); err != nil { httputils.SetFailed(c, r, err) return } @@ -229,23 +226,23 @@ func (cr *clusterRouter) GetReleaseHistory(c *gin.Context) { httputils.SetSuccess(c, r) } -// RollbackRelease rolls back a release in the specified namespace and cluster to a specific revision +// RollbackRelease rolls back a release in the specified namespace and cluster to the specified revision // // @Summary rollback a release -// @Description rolls back a release from the specified Kubernetes namespace and cluster to a specific revision +// @Description rolls back a release from the specified Kubernetes namespace and cluster to the specified revision // @Tags helm // @Accept json // @Produce json // @Param cluster path string true "Kubernetes cluster name" // @Param namespace path string true "Kubernetes namespace" // @Param name path string true "Release name" -// @Param version query int true "Release version" +// @Param version query int true "Release revision" // @Success 200 {object} httputils.Response // @Failure 400 {object} httputils.Response // @Failure 404 {object} httputils.Response // @Failure 500 {object} httputils.Response // @Router /helm/releases/rollback/{cluster}/{namespace}/{name} [post] -func (cr *clusterRouter) RollbackRelease(c *gin.Context) { +func (hr *helmRouter) RollbackRelease(c *gin.Context) { r := httputils.NewResponse() var ( err error @@ -257,7 +254,7 @@ func (cr *clusterRouter) RollbackRelease(c *gin.Context) { return } - if err = cr.c.Cluster().Helm(helmMeta.Cluster).Releases(helmMeta.Namespace).RollbackRelease(c, helmMeta.Name, reverionMeta.Version); err != nil { + if err = hr.c.Helm().Release(helmMeta.Cluster, helmMeta.Namespace).Rollback(c, helmMeta.Name, reverionMeta.Version); err != nil { httputils.SetFailed(c, r, err) return } diff --git a/api/server/router/helm/respository_routes.go b/api/server/router/helm/respository_routes.go new file mode 100644 index 00000000..fa7ec229 --- /dev/null +++ b/api/server/router/helm/respository_routes.go @@ -0,0 +1,276 @@ +/* +Copyright 2021 The Pixiu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package helm + +import ( + "github.com/gin-gonic/gin" + + "github.com/caoyingjunz/pixiu/api/server/httputils" + "github.com/caoyingjunz/pixiu/pkg/types" +) + +// createRepository creates a new repository in the specified cluster +// +// @Summary create a repository +// @Description creates a new repository in the specified Kubernetes cluster +// @Tags repositories +// @Accept json +// @Produce json +// @Param cluster query string true "Kubernetes cluster name" +// @Param body body types.RepoForm true "Repository information" +// @Success 200 {object} httputils.Response +// @Failure 400 {object} httputils.Response +// @Failure 500 {object} httputils.Response +// @Router /repositories [post] +func (hr *helmRouter) createRepository(c *gin.Context) { + r := httputils.NewResponse() + + var ( + err error + req types.CreateRepository + ) + if err = httputils.ShouldBindAny(c, &req, nil, nil); err != nil { + httputils.SetFailed(c, r, err) + return + } + + if err = hr.c.Helm().Repository().Create(c, &req); err != nil { + httputils.SetFailed(c, r, err) + return + } + + httputils.SetSuccess(c, r) +} + +// deleteRepository deletes a repository by its ID +// +// @Summary delete a repository by ID +// @Description deletes a repository from the system using the provided ID +// @Tags repositories +// @Accept json +// @Produce json +// @Param id path int true "Repository ID" +// @Success 200 {object} httputils.Response +// @Failure 400 {object} httputils.Response +// @Failure 404 {object} httputils.Response +// @Failure 500 {object} httputils.Response +// @Router /repositories/{id} [delete] +func (hr *helmRouter) deleteRepository(c *gin.Context) { + r := httputils.NewResponse() + + var ( + err error + repoMeta types.RepoId + ) + if err = c.ShouldBindUri(&repoMeta); err != nil { + httputils.SetFailed(c, r, err) + return + } + if err = hr.c.Helm().Repository().Delete(c, repoMeta.Id); err != nil { + httputils.SetFailed(c, r, err) + return + } + + httputils.SetSuccess(c, r) +} + +// updateRepository updates a repository by its ID +// +// @Summary update a repository by ID +// @Description updates a repository in the system using the provided ID and update information +// @Tags repositories +// @Accept json +// @Produce json +// @Param id path int true "Repository ID" +// @Param body body types.RepoUpdateForm true "Repository update information" +// @Success 200 {object} httputils.Response +// @Failure 400 {object} httputils.Response +// @Failure 404 {object} httputils.Response +// @Failure 500 {object} httputils.Response +func (hr *helmRouter) updateRepository(c *gin.Context) { + r := httputils.NewResponse() + + var ( + err error + repoMeta types.RepoId + formData types.UpdateRepository + ) + if err = httputils.ShouldBindAny(c, &formData, &repoMeta, nil); err != nil { + httputils.SetFailed(c, r, err) + return + } + if err = hr.c.Helm().Repository().Update(c, repoMeta.Id, &formData); err != nil { + httputils.SetFailed(c, r, err) + return + } + + httputils.SetSuccess(c, r) +} + +// getRepository retrieves a repository by its ID +// +// @Summary get a repository by ID +// @Description retrieves a repository from the system using the provided ID +// @Tags repositories +// @Accept json +// @Produce json +// @Param id path int true "Repository ID" +// @Success 200 {object} httputils.Response{result=types.Repository} +// @Failure 400 {object} httputils.Response +// @Failure 404 {object} httputils.Response +// @Failure 500 {object} httputils.Response +// @Router /repositories/{id} [get] +func (hr *helmRouter) getRepository(c *gin.Context) { + r := httputils.NewResponse() + + var ( + err error + repoMeta types.RepoId + ) + if err = c.ShouldBindUri(&repoMeta); err != nil { + httputils.SetFailed(c, r, err) + return + } + if r.Result, err = hr.c.Helm().Repository().Get(c, repoMeta.Id); err != nil { + httputils.SetFailed(c, r, err) + return + } + + httputils.SetSuccess(c, r) +} + +// listRepositories retrieves a list of all repositories +// +// @Summary list repositories +// @Description retrieves a list of all repositories in the system +// @Tags repositories +// @Accept json +// @Produce json +// @Success 200 {object} httputils.Response{result=[]types.Repository} +// @Failure 400 {object} httputils.Response +// @Failure 500 {object} httputils.Response +// @Router /repositories [get] +func (hr *helmRouter) listRepositories(c *gin.Context) { + r := httputils.NewResponse() + var err error + + if r.Result, err = hr.c.Helm().Repository().List(c); err != nil { + httputils.SetFailed(c, r, err) + return + } + + httputils.SetSuccess(c, r) +} + +// getRepoCharts retrieves charts of a repository by its ID +// +// @Summary get repository charts by ID +// @Description retrieves charts associated with a repository from the system using the provided ID +// @Tags repositories +// @Accept json +// @Produce json +// @Param id path int true "Repository ID" +// @Success 200 {object} httputils.Response{result=model.ChartIndex} +// @Failure 400 {object} httputils.Response +// @Failure 404 {object} httputils.Response +// @Failure 500 {object} httputils.Response +// @Router /repositories/{id}/charts [get] +func (hr *helmRouter) getRepoCharts(c *gin.Context) { + r := httputils.NewResponse() + var ( + err error + repoMeta types.RepoId + ) + + if err = c.ShouldBindUri(&repoMeta); err != nil { + httputils.SetFailed(c, r, err) + return + } + if r.Result, err = hr.c.Helm().Repository().GetChartsById(c, repoMeta.Id); err != nil { + httputils.SetFailed(c, r, err) + return + } + + httputils.SetSuccess(c, r) +} + +// getRepoChartsByURL retrieves charts of a repository by its URL +// +// @Summary get repository charts by URL +// @Description retrieves charts associated with a repository from the system using the provided URL +// @Tags repositories +// @Accept json +// @Produce json +// @Param url query string true "Repository URL" +// @Success 200 {object} httputils.Response{result=model.ChartIndex} +// @Failure 400 {object} httputils.Response +// @Failure 404 {object} httputils.Response +// @Failure 500 {object} httputils.Response +// @Router /repositories/charts [get] +func (hr *helmRouter) getRepoChartsByURL(c *gin.Context) { + r := httputils.NewResponse() + var ( + err error + repoMeta types.RepoURL + ) + + if err = httputils.ShouldBindAny(c, nil, nil, &repoMeta); err != nil { + httputils.SetFailed(c, r, err) + return + } + if r.Result, err = hr.c.Helm().Repository().GetChartsByURL(c, repoMeta.Url); err != nil { + httputils.SetFailed(c, r, err) + return + } + + httputils.SetSuccess(c, r) +} + +// getChartValues retrieves the values of a specific chart version +// +// @Summary get chart values +// @Description retrieves values for a specific chart version using the provided chart name and version +// @Tags charts +// @Accept json +// @Produce json +// @Param chart query string true "Chart name" +// @Param version query string true "Chart version" +// @Success 200 {object} httputils.Response{result=types.ChartValues} +// @Failure 400 {object} httputils.Response +// @Failure 404 {object} httputils.Response +// @Failure 500 {object} httputils.Response +// @Router /repositories/chartvalues [get] +func (hr *helmRouter) getChartValues(c *gin.Context) { + + r := httputils.NewResponse() + var ( + err error + repoMeta types.ChartValues + ) + + if err = httputils.ShouldBindAny(c, nil, nil, &repoMeta); err != nil { + httputils.SetFailed(c, r, err) + return + } + if r.Result, err = hr.c.Helm().Repository().GetChartValues(c, repoMeta.Chart, repoMeta.Version); err != nil { + httputils.SetFailed(c, r, err) + return + } + + httputils.SetSuccess(c, r) + +} diff --git a/api/server/router/router.go b/api/server/router/router.go index 1ebcb740..c94e03f9 100644 --- a/api/server/router/router.go +++ b/api/server/router/router.go @@ -32,6 +32,7 @@ import ( "github.com/caoyingjunz/pixiu/api/server/router/audit" "github.com/caoyingjunz/pixiu/api/server/router/auth" "github.com/caoyingjunz/pixiu/api/server/router/cluster" + "github.com/caoyingjunz/pixiu/api/server/router/helm" "github.com/caoyingjunz/pixiu/api/server/router/plan" "github.com/caoyingjunz/pixiu/api/server/router/proxy" "github.com/caoyingjunz/pixiu/api/server/router/tenant" @@ -49,6 +50,7 @@ func InstallRouters(o *options.Options) { fs := []RegisterFunc{ middleware.InstallMiddlewares, cluster.NewRouter, + helm.NewRouter, proxy.NewRouter, tenant.NewRouter, user.NewRouter, diff --git a/pkg/client/helm.go b/pkg/client/helm.go new file mode 100644 index 00000000..3ab80c98 --- /dev/null +++ b/pkg/client/helm.go @@ -0,0 +1,73 @@ +/* +Copyright 2024 The Pixiu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package client + +import ( + "k8s.io/apimachinery/pkg/api/meta" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/client-go/discovery" + memory "k8s.io/client-go/discovery/cached" + "k8s.io/client-go/rest" + "k8s.io/client-go/restmapper" + "k8s.io/client-go/tools/clientcmd" +) + +type HelmRESTClientGetter struct { + kubeConfig *rest.Config +} + +var _ genericclioptions.RESTClientGetter = &HelmRESTClientGetter{} + +// ToDiscoveryClient implements action.RESTClientGetter. +func (h *HelmRESTClientGetter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { + h.kubeConfig.Burst = 100 + discoveryClient, err := discovery.NewDiscoveryClientForConfig(h.kubeConfig) + if err != nil { + return nil, err + } + return memory.NewMemCacheClient(discoveryClient), nil +} + +// ToRESTConfig implements action.RESTClientGetter. +func (h *HelmRESTClientGetter) ToRESTConfig() (*rest.Config, error) { + return h.kubeConfig, nil +} + +// ToRESTMapper implements action.RESTClientGetter. +func (h *HelmRESTClientGetter) ToRESTMapper() (meta.RESTMapper, error) { + + discoveryClient, err := h.ToDiscoveryClient() + if err != nil { + return nil, err + } + mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) + expander := restmapper.NewShortcutExpander(mapper, discoveryClient) + return expander, nil +} + +func (h *HelmRESTClientGetter) ToRawKubeConfigLoader() clientcmd.ClientConfig { + loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() + loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig + overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults} + return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) +} + +func NewHelmRESTClientGetter(kubeConfig *rest.Config) *HelmRESTClientGetter { + return &HelmRESTClientGetter{ + kubeConfig: kubeConfig, + } +} diff --git a/pkg/controller/cluster/cluster.go b/pkg/controller/cluster/cluster.go index 90ec50bd..a0d10ee5 100644 --- a/pkg/controller/cluster/cluster.go +++ b/pkg/controller/cluster/cluster.go @@ -92,15 +92,12 @@ type Interface interface { // Run 启动 cluster worker 处理协程 Run(ctx context.Context, workers int) error - - // Helm 命令 - Helm(cluster string) HelmInterface } -var clusterIndexer client.Cache +var ClusterIndexer client.Cache func init() { - clusterIndexer = *client.NewClusterCache() + ClusterIndexer = *client.NewClusterCache() } type ( @@ -124,15 +121,6 @@ type cluster struct { getterFuncs map[string]getterFunc } -func (c *cluster) Helm(cluster string) HelmInterface { - kubeConfig, err := c.GetKubeConfigByName(context.TODO(), cluster) - if err != nil { - klog.Errorf("failed to get kube config: %v", err) - return &Helm{} - } - return newHelm(kubeConfig, cluster, c.factory) -} - func (c *cluster) preCreate(ctx context.Context, req *types.CreateClusterRequest) error { // 实际创建前,先创建集群的连通性 if err := c.Ping(ctx, req.KubeConfig); err != nil { @@ -183,7 +171,7 @@ func (c *cluster) Create(ctx context.Context, req *types.CreateClusterRequest) e } // TODO: 暂时不做创建后动作 - clusterIndexer.Set(req.Name, *cs) + ClusterIndexer.Set(req.Name, *cs) return nil } @@ -254,7 +242,7 @@ func (c *cluster) Delete(ctx context.Context, cid int64) error { } // 从缓存中移除 clusterSet - clusterIndexer.Delete(cluster.Name) + ClusterIndexer.Delete(cluster.Name) return nil } @@ -611,7 +599,7 @@ func (c *cluster) GetKubeConfigByName(ctx context.Context, name string) (*restcl // GetClusterSetByName 获取 ClusterSet, 缓存中不存在时,构建缓存再返回 func (c *cluster) GetClusterSetByName(ctx context.Context, name string) (client.ClusterSet, error) { - cs, ok := clusterIndexer.Get(name) + cs, ok := ClusterIndexer.Get(name) if ok { klog.Infof("Get %s clusterSet from indexer", name) return cs, nil @@ -632,7 +620,7 @@ func (c *cluster) GetClusterSetByName(ctx context.Context, name string) (client. } klog.Infof("set %s clusterSet into indexer", name) - clusterIndexer.Set(name, *newClusterSet) + ClusterIndexer.Set(name, *newClusterSet) return *newClusterSet, nil } diff --git a/pkg/controller/cluster/helm.go b/pkg/controller/cluster/helm.go deleted file mode 100644 index 82119d61..00000000 --- a/pkg/controller/cluster/helm.go +++ /dev/null @@ -1,118 +0,0 @@ -/* -Copyright 2021 The Pixiu Authors. - -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -*/ - -package cluster - -import ( - "os" - - "helm.sh/helm/v3/pkg/action" - "helm.sh/helm/v3/pkg/cli" - "k8s.io/apimachinery/pkg/api/meta" - "k8s.io/cli-runtime/pkg/genericclioptions" - "k8s.io/client-go/discovery" - "k8s.io/client-go/discovery/cached/memory" - "k8s.io/client-go/rest" - "k8s.io/client-go/restmapper" - "k8s.io/client-go/tools/clientcmd" - "k8s.io/klog/v2" - - "github.com/caoyingjunz/pixiu/pkg/db" -) - -type HelmInterface interface { - Releases(namespace string) ReleaseInterface -} - -type Helm struct { - cluster string - factory db.ShareDaoFactory - settings *cli.EnvSettings - actionConfig *action.Configuration - resetClientGetter *HelmRESTClientGeeter -} - -func (h *Helm) Releases(namespace string) ReleaseInterface { - h.settings.SetNamespace(namespace) - if err := h.actionConfig.Init( - h.resetClientGetter, - h.settings.Namespace(), - os.Getenv("HELM_DRIVER"), - klog.Infof, - ); err != nil { - klog.Errorf("failed to init helm action config: %v", err) - return nil - } - return newReleases(h.actionConfig, h.settings) -} - -func newHelm(kubeConfig *rest.Config, cluster string, factory db.ShareDaoFactory) *Helm { - settings := cli.New() - actionConfig := new(action.Configuration) - resetClientGetter := newHelmRESTClientGeeter(kubeConfig) - return &Helm{ - settings: settings, - actionConfig: actionConfig, - resetClientGetter: resetClientGetter, - cluster: cluster, - factory: factory, - } -} - -type HelmRESTClientGeeter struct { - kubeConfig *rest.Config -} - -var _ genericclioptions.RESTClientGetter = &HelmRESTClientGeeter{} - -// ToDiscoveryClient implements action.RESTClientGetter. -func (h *HelmRESTClientGeeter) ToDiscoveryClient() (discovery.CachedDiscoveryInterface, error) { - h.kubeConfig.Burst = 100 - discoveryClient, err := discovery.NewDiscoveryClientForConfig(h.kubeConfig) - if err != nil { - return nil, err - } - return memory.NewMemCacheClient(discoveryClient), nil -} - -// ToRESTConfig implements action.RESTClientGetter. -func (h *HelmRESTClientGeeter) ToRESTConfig() (*rest.Config, error) { - return h.kubeConfig, nil -} - -// ToRESTMapper implements action.RESTClientGetter. -func (h *HelmRESTClientGeeter) ToRESTMapper() (meta.RESTMapper, error) { - - discoveryClient, err := h.ToDiscoveryClient() - if err != nil { - return nil, err - } - mapper := restmapper.NewDeferredDiscoveryRESTMapper(discoveryClient) - expander := restmapper.NewShortcutExpander(mapper, discoveryClient) - return expander, nil -} -func (h *HelmRESTClientGeeter) ToRawKubeConfigLoader() clientcmd.ClientConfig { - loadingRules := clientcmd.NewDefaultClientConfigLoadingRules() - loadingRules.DefaultClientConfig = &clientcmd.DefaultClientConfig - overrides := &clientcmd.ConfigOverrides{ClusterDefaults: clientcmd.ClusterDefaults} - return clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) -} - -func newHelmRESTClientGeeter(kubeConfig *rest.Config) *HelmRESTClientGeeter { - return &HelmRESTClientGeeter{ - kubeConfig: kubeConfig, - } -} diff --git a/pkg/controller/controller.go b/pkg/controller/controller.go index b9f93032..d8ef91c9 100644 --- a/pkg/controller/controller.go +++ b/pkg/controller/controller.go @@ -23,6 +23,7 @@ import ( "github.com/caoyingjunz/pixiu/pkg/controller/audit" "github.com/caoyingjunz/pixiu/pkg/controller/auth" "github.com/caoyingjunz/pixiu/pkg/controller/cluster" + "github.com/caoyingjunz/pixiu/pkg/controller/helm" "github.com/caoyingjunz/pixiu/pkg/controller/plan" "github.com/caoyingjunz/pixiu/pkg/controller/tenant" "github.com/caoyingjunz/pixiu/pkg/controller/user" @@ -36,6 +37,7 @@ type PixiuInterface interface { plan.PlanGetter audit.AuditGetter auth.AuthGetter + helm.HelmGetter } type pixiu struct { @@ -50,6 +52,7 @@ func (p *pixiu) User() user.Interface { return user.NewUser(p.cc, p.factor func (p *pixiu) Plan() plan.Interface { return plan.NewPlan(p.cc, p.factory) } func (p *pixiu) Audit() audit.Interface { return audit.NewAudit(p.cc, p.factory) } func (p *pixiu) Auth() auth.Interface { return auth.NewAuth(p.factory, p.enforcer) } +func (p *pixiu) Helm() helm.Interface { return helm.NewHelm(p.factory) } func New(cfg config.Config, f db.ShareDaoFactory, enforcer *casbin.SyncedEnforcer) PixiuInterface { return &pixiu{ diff --git a/pkg/controller/helm/helm.go b/pkg/controller/helm/helm.go new file mode 100644 index 00000000..4a554f9e --- /dev/null +++ b/pkg/controller/helm/helm.go @@ -0,0 +1,93 @@ +/* +Copyright 2024 The Pixiu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package helm + +import ( + "context" + + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/cli" + "k8s.io/klog/v2" + + "github.com/caoyingjunz/pixiu/pkg/client" + "github.com/caoyingjunz/pixiu/pkg/controller/cluster" + "github.com/caoyingjunz/pixiu/pkg/db" +) + +type HelmGetter interface { + Helm() Interface +} + +type Interface interface { + Release(cluster, namespace string) ReleaseInterface + Repository() RepositoryInterface +} + +type Helm struct { + factory db.ShareDaoFactory +} + +func (h *Helm) Release(cluster, namespace string) ReleaseInterface { + cs := h.MustGetClusterSetByName(context.Background(), cluster) + settings := cli.New() + settings.SetNamespace(namespace) + actionConfig := new(action.Configuration) + resetClientGetter := client.NewHelmRESTClientGetter(cs.Config) + actionConfig.Init( + resetClientGetter, + settings.Namespace(), + "secrets", + klog.Infof, + ) + return NewReleases(actionConfig, settings) +} + +func (h *Helm) Repository() RepositoryInterface { + return NewRepository(h.factory) +} + +func NewHelm(factory db.ShareDaoFactory) Interface { + return &Helm{ + factory: factory, + } +} + +func (h *Helm) MustGetClusterSetByName(ctx context.Context, name string) client.ClusterSet { + cs, ok := cluster.ClusterIndexer.Get(name) + if ok { + klog.Infof("Get %s clusterSet from indexer", name) + return cs + } + + klog.Infof("building clusterSet for %s", name) + // 缓存中不存在,则新建并重写回缓存 + object, err := h.factory.Cluster().GetClusterByName(ctx, name) + if err != nil { + return client.ClusterSet{} + } + if object == nil { + return client.ClusterSet{} + } + newClusterSet, err := client.NewClusterSet(object.KubeConfig) + if err != nil { + return client.ClusterSet{} + } + + klog.Infof("set %s clusterSet into indexer", name) + cluster.ClusterIndexer.Set(name, *newClusterSet) + return *newClusterSet +} diff --git a/pkg/controller/cluster/releases.go b/pkg/controller/helm/releases.go similarity index 78% rename from pkg/controller/cluster/releases.go rename to pkg/controller/helm/releases.go index 7c7e56c8..dc0ae015 100644 --- a/pkg/controller/cluster/releases.go +++ b/pkg/controller/helm/releases.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package cluster +package helm import ( "context" @@ -35,14 +35,14 @@ import ( ) type ReleaseInterface interface { - InstallRelease(ctx context.Context, form *types.Release) (*release.Release, error) - - GetRelease(ctx context.Context, name string) (*release.Release, error) - ListRelease(ctx context.Context) ([]*release.Release, error) - UninstallRelease(ctx context.Context, name string) (*release.UninstallReleaseResponse, error) - UpgradeRelease(ctx context.Context, form *types.Release) (*release.Release, error) - GetReleaseHistory(ctx context.Context, name string) ([]*release.Release, error) - RollbackRelease(ctx context.Context, name string, toVersion int) error + Install(ctx context.Context, form *types.Release) (*release.Release, error) + + Get(ctx context.Context, name string) (*release.Release, error) + List(ctx context.Context) ([]*release.Release, error) + Uninstall(ctx context.Context, name string) (*release.UninstallReleaseResponse, error) + Upgrade(ctx context.Context, form *types.Release) (*release.Release, error) + History(ctx context.Context, name string) ([]*release.Release, error) + Rollback(ctx context.Context, name string, toVersion int) error } type Releases struct { @@ -50,7 +50,7 @@ type Releases struct { actionConfig *action.Configuration } -func newReleases(actionConfig *action.Configuration, settings *cli.EnvSettings) *Releases { +func NewReleases(actionConfig *action.Configuration, settings *cli.EnvSettings) *Releases { return &Releases{ actionConfig: actionConfig, settings: settings, @@ -59,18 +59,18 @@ func newReleases(actionConfig *action.Configuration, settings *cli.EnvSettings) var _ ReleaseInterface = &Releases{} -func (r *Releases) GetRelease(ctx context.Context, name string) (*release.Release, error) { +func (r *Releases) Get(ctx context.Context, name string) (*release.Release, error) { client := action.NewGet(r.actionConfig) return client.Run(name) } -func (r *Releases) ListRelease(ctx context.Context) ([]*release.Release, error) { +func (r *Releases) List(ctx context.Context) ([]*release.Release, error) { client := action.NewList(r.actionConfig) return client.Run() } // InstallRelease install release -func (r *Releases) InstallRelease(ctx context.Context, form *types.Release) (*release.Release, error) { +func (r *Releases) Install(ctx context.Context, form *types.Release) (*release.Release, error) { client := action.NewInstall(r.actionConfig) client.ReleaseName = form.Name client.Namespace = r.settings.Namespace() @@ -91,13 +91,13 @@ func (r *Releases) InstallRelease(ctx context.Context, form *types.Release) (*re return out, nil } -func (r *Releases) UninstallRelease(ctx context.Context, name string) (*release.UninstallReleaseResponse, error) { +func (r *Releases) Uninstall(ctx context.Context, name string) (*release.UninstallReleaseResponse, error) { client := action.NewUninstall(r.actionConfig) return client.Run(name) } // UpgradeRelease upgrade release -func (r *Releases) UpgradeRelease(ctx context.Context, form *types.Release) (*release.Release, error) { +func (r *Releases) Upgrade(ctx context.Context, form *types.Release) (*release.Release, error) { client := action.NewUpgrade(r.actionConfig) client.Namespace = r.settings.Namespace() client.DryRun = form.Preview @@ -117,14 +117,14 @@ func (r *Releases) UpgradeRelease(ctx context.Context, form *types.Release) (*re return out, nil } -func (r *Releases) GetReleaseHistory(ctx context.Context, name string) ([]*release.Release, error) { +func (r *Releases) History(ctx context.Context, name string) ([]*release.Release, error) { client := action.NewHistory(r.actionConfig) return client.Run(name) } -func (r *Releases) RollbackRelease(ctx context.Context, name string, toVersion int) error { +func (r *Releases) Rollback(ctx context.Context, name string, toVersion int) error { klog.Error("version: ", toVersion) - _, err := r.GetRelease(ctx, name) + _, err := r.Get(ctx, name) if err != nil { return err } diff --git a/pkg/controller/helm/repository.go b/pkg/controller/helm/repository.go new file mode 100644 index 00000000..53506924 --- /dev/null +++ b/pkg/controller/helm/repository.go @@ -0,0 +1,204 @@ +/* +Copyright 2021 The Pixiu Authors. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package helm + +import ( + "context" + "fmt" + "net/url" + "strings" + + "k8s.io/klog/v2" + + "helm.sh/helm/v3/pkg/action" + "helm.sh/helm/v3/pkg/cli" + "helm.sh/helm/v3/pkg/getter" + "helm.sh/helm/v3/pkg/repo" + "k8s.io/apimachinery/pkg/util/yaml" + + "github.com/caoyingjunz/pixiu/pkg/db" + "github.com/caoyingjunz/pixiu/pkg/db/model" + "github.com/caoyingjunz/pixiu/pkg/types" +) + +type RepositoryGetter interface { + Repository() RepositoryInterface +} + +type RepositoryInterface interface { + Create(ctx context.Context, repo *types.CreateRepository) error + Delete(ctx context.Context, id int64) error + Get(ctx context.Context, id int64) (*model.Repository, error) + List(ctx context.Context) ([]*model.Repository, error) + Update(ctx context.Context, id int64, update *types.UpdateRepository) error + + GetChartsById(ctx context.Context, id int64) (*model.ChartIndex, error) + GetChartsByURL(ctx context.Context, repoURL string) (*model.ChartIndex, error) + GetChartValues(ctx context.Context, chart, version string) (string, error) +} + +type Repository struct { + settings *cli.EnvSettings + actionConfig *action.Configuration + factory db.ShareDaoFactory +} + +func NewRepository(f db.ShareDaoFactory) *Repository { + settings := cli.New() + actionConfig := new(action.Configuration) + actionConfig.Init(settings.RESTClientGetter(), settings.Namespace(), "secrets", klog.Infof) + return &Repository{factory: f, settings: settings, actionConfig: actionConfig} +} + +var _ RepositoryInterface = &Repository{} + +func (r *Repository) Create(ctx context.Context, repo *types.CreateRepository) error { + + repoModel := &model.Repository{ + Name: repo.Name, + URL: repo.URL, + } + if res, _ := r.GetByName(ctx, repoModel.Name); res != nil { + return fmt.Errorf("repository %s already exists", repoModel.Name) + } + + _, err := r.factory.Repository().Create(ctx, repoModel) + return err +} + +func (r *Repository) Delete(ctx context.Context, id int64) error { + return r.factory.Repository().Delete(ctx, id) +} + +func (r *Repository) Get(ctx context.Context, id int64) (*model.Repository, error) { + return r.factory.Repository().Get(ctx, id) +} + +func (r *Repository) GetByName(ctx context.Context, name string) (*model.Repository, error) { + return r.factory.Repository().GetByName(ctx, name) +} + +func (r *Repository) List(ctx context.Context) ([]*model.Repository, error) { + return r.factory.Repository().List(ctx) +} + +func (r *Repository) Update(ctx context.Context, id int64, update *types.UpdateRepository) error { + updates := map[string]interface{}{ + "name": update.Name, + "url": update.URL, + "username": update.Username, + "password": update.Password, + } + return r.factory.Repository().Update(ctx, id, *update.ResourceVersion, updates) +} + +func (r *Repository) GetChartsById(ctx context.Context, id int64) (*model.ChartIndex, error) { + repository, err := r.Get(ctx, id) + if err != nil { + return nil, err + } + + entry := &repo.Entry{ + Name: repository.Name, + URL: repository.URL, + Username: repository.Username, + Password: repository.Password, + } + return r.fetch(ctx, entry) +} + +func (r *Repository) GetChartsByURL(ctx context.Context, repoURL string) (*model.ChartIndex, error) { + entry := &repo.Entry{ + URL: repoURL, + } + return r.fetch(ctx, entry) +} + +func (r *Repository) GetChartValues(_ context.Context, chart, version string) (string, error) { + client := action.NewShowWithConfig(action.ShowValues, r.actionConfig) + client.Version = version + cp, err := client.ChartPathOptions.LocateChart(chart, r.settings) + if err != nil { + return "", err + } + + out, err := client.Run(cp) + if err != nil { + return "", err + } + + return out, nil +} + +func (r *Repository) resolveReferenceURL(baseURL, refURL string) (string, error) { + parsedRefURL, err := url.Parse(refURL) + if err != nil { + return "", fmt.Errorf("failed to parse %s as URL, %v", refURL, err) + } + + if parsedRefURL.IsAbs() { + return refURL, nil + } + + parsedBaseURL, err := url.Parse(baseURL) + if err != nil { + return "", fmt.Errorf("failed to parse %s as URL, %v", baseURL, err) + } + + parsedBaseURL.RawPath = strings.TrimSuffix(parsedBaseURL.RawPath, "/") + "/" + parsedBaseURL.Path = strings.TrimSuffix(parsedBaseURL.Path, "/") + "/" + + resolvedURL := parsedBaseURL.ResolveReference(parsedRefURL) + resolvedURL.RawQuery = parsedBaseURL.RawQuery + return resolvedURL.String(), nil +} + +func (r *Repository) fetch(_ context.Context, entry *repo.Entry) (*model.ChartIndex, error) { + var charts model.ChartIndex + + rep, err := repo.NewChartRepository(entry, getter.All(r.settings)) + if err != nil { + return nil, err + } + + // download index + if _, err = rep.DownloadIndexFile(); err != nil { + return nil, err + } + + indexURL, err := r.resolveReferenceURL(rep.Config.URL, "index.yaml") + if err != nil { + return nil, err + } + + resp, err := rep.Client.Get(indexURL, + getter.WithURL(rep.Config.URL), + getter.WithInsecureSkipVerifyTLS(rep.Config.InsecureSkipTLSverify), + getter.WithTLSClientConfig(rep.Config.CertFile, rep.Config.KeyFile, rep.Config.CAFile), + getter.WithBasicAuth(rep.Config.Username, rep.Config.Password), + getter.WithPassCredentialsAll(rep.Config.PassCredentialsAll), + ) + if err != nil { + return nil, err + } + + err = yaml.Unmarshal(resp.Bytes(), &charts) + if err != nil { + return nil, err + } + return &charts, nil +} diff --git a/pkg/db/factory.go b/pkg/db/factory.go index 1e16aabe..9313ce76 100644 --- a/pkg/db/factory.go +++ b/pkg/db/factory.go @@ -26,17 +26,19 @@ type ShareDaoFactory interface { User() UserInterface Plan() PlanInterface Audit() AuditInterface + Repository() RepositoryInterface } type shareDaoFactory struct { db *gorm.DB } -func (f *shareDaoFactory) Cluster() ClusterInterface { return newCluster(f.db) } -func (f *shareDaoFactory) Tenant() TenantInterface { return newTenant(f.db) } -func (f *shareDaoFactory) User() UserInterface { return newUser(f.db) } -func (f *shareDaoFactory) Plan() PlanInterface { return newPlan(f.db) } -func (f *shareDaoFactory) Audit() AuditInterface { return newAudit(f.db) } +func (f *shareDaoFactory) Cluster() ClusterInterface { return newCluster(f.db) } +func (f *shareDaoFactory) Tenant() TenantInterface { return newTenant(f.db) } +func (f *shareDaoFactory) User() UserInterface { return newUser(f.db) } +func (f *shareDaoFactory) Plan() PlanInterface { return newPlan(f.db) } +func (f *shareDaoFactory) Audit() AuditInterface { return newAudit(f.db) } +func (f *shareDaoFactory) Repository() RepositoryInterface { return newRepository(f.db) } func NewDaoFactory(db *gorm.DB, migrate bool) (ShareDaoFactory, error) { if migrate { diff --git a/pkg/db/model/repository.go b/pkg/db/model/repository.go index 56e40d64..8b4a5032 100644 --- a/pkg/db/model/repository.go +++ b/pkg/db/model/repository.go @@ -23,24 +23,18 @@ import ( ) func init() { - register(&Repositories{}) + register(&Repository{}) } -type Repositories struct { +type Repository struct { pixiu.Model - Cluster string `gorm:"column:cluster; not null" json:"cluster"` - Name string `gorm:"column:name; not null" json:"name"` - URL string `gorm:"column:url;not null" json:"url"` - Username string `gorm:"column:username" json:"username"` - Password string `gorm:"column:password" json:"password"` - CertFile string `gorm:"column:cert_file" json:"certFile"` - KeyFile string `gorm:"column:key_file" json:"keyFile"` - CAFile string `gorm:"column:ca_file" json:"caFile"` - InsecureSkipTLSverify bool `gorm:"column:insecure_skip_tls_verify" json:"insecure_skip_tls_verify"` - PassCredentialsAll bool `gorm:"column:pass_credentials_all" json:"pass_credentials_all"` + Name string `gorm:"column:name; index:idx_name,unique; not null" json:"name"` + URL string `gorm:"column:url;not null" json:"url"` + Username string `gorm:"column:username" json:"username"` + Password string `gorm:"column:password" json:"password"` } -func (*Repositories) TableName() string { +func (*Repository) TableName() string { return "repositories" } diff --git a/pkg/db/repository.go b/pkg/db/repository.go index 4933892c..bd60760b 100644 --- a/pkg/db/repository.go +++ b/pkg/db/repository.go @@ -25,26 +25,26 @@ import ( "gorm.io/gorm" ) -type RepoInterface interface { - Create(ctx context.Context, object *model.Repositories) (*model.Repositories, error) - Update(ctx context.Context, cluster string, id int64, resourceVersion int64, updates map[string]interface{}) error - Delete(ctx context.Context, cluster string, id int64) error - Get(ctx context.Context, cluster string, id int64) (*model.Repositories, error) - GetByName(ctx context.Context, cluster, name string) (*model.Repositories, error) - List(ctx context.Context, cluster string) ([]*model.Repositories, error) +type RepositoryInterface interface { + Create(ctx context.Context, object *model.Repository) (*model.Repository, error) + Update(ctx context.Context, id int64, resourceVersion int64, updates map[string]interface{}) error + Delete(ctx context.Context, id int64) error + Get(ctx context.Context, id int64) (*model.Repository, error) + GetByName(ctx context.Context, name string) (*model.Repository, error) + List(ctx context.Context) ([]*model.Repository, error) } type repository struct { db *gorm.DB } -func newRepository(db *gorm.DB) RepoInterface { +func newRepository(db *gorm.DB) RepositoryInterface { return &repository{db} } -var _ RepoInterface = &repository{} +var _ RepositoryInterface = &repository{} -func (r *repository) Create(ctx context.Context, object *model.Repositories) (*model.Repositories, error) { +func (r *repository) Create(ctx context.Context, object *model.Repository) (*model.Repository, error) { now := time.Now() object.GmtCreate = now object.GmtModified = now @@ -55,11 +55,11 @@ func (r *repository) Create(ctx context.Context, object *model.Repositories) (*m return object, nil } -func (r *repository) Update(ctx context.Context, cluster string, id int64, resourceVersion int64, updates map[string]interface{}) error { +func (r *repository) Update(ctx context.Context, id int64, resourceVersion int64, updates map[string]interface{}) error { updates["gmt_modified"] = time.Now() updates["resource_version"] = resourceVersion + 1 - f := r.db.WithContext(ctx).Model(&model.Repositories{}).Where("id = ? and resource_version = ? and cluster = ?", id, resourceVersion, cluster).Updates(updates) + f := r.db.WithContext(ctx).Model(&model.Repository{}).Where("id = ? and resource_version = ? ", id, resourceVersion).Updates(updates) if f.Error != nil { return f.Error } @@ -72,8 +72,8 @@ func (r *repository) Update(ctx context.Context, cluster string, id int64, resou } -func (r *repository) Delete(ctx context.Context, cluster string, id int64) error { - f := r.db.WithContext(ctx).Where("id = ? and cluster = ?", id, cluster).Delete(&model.Repositories{}) +func (r *repository) Delete(ctx context.Context, id int64) error { + f := r.db.WithContext(ctx).Where("id = ?", id).Delete(&model.Repository{}) if f.Error != nil { return f.Error } @@ -85,27 +85,27 @@ func (r *repository) Delete(ctx context.Context, cluster string, id int64) error return nil } -func (r *repository) Get(ctx context.Context, cluster string, id int64) (*model.Repositories, error) { - var repo model.Repositories - if err := r.db.WithContext(ctx).Where("id = ? and cluster = ?", id, cluster).First(&repo).Error; err != nil { +func (r *repository) Get(ctx context.Context, id int64) (*model.Repository, error) { + var repo model.Repository + if err := r.db.WithContext(ctx).Where("id = ?", id).First(&repo).Error; err != nil { return nil, err } return &repo, nil } -func (r *repository) GetByName(ctx context.Context, cluster string, name string) (*model.Repositories, error) { - var repo model.Repositories - if err := r.db.WithContext(ctx).Where("name = ? and cluster = ?", name, cluster).First(&repo).Error; err != nil { +func (r *repository) GetByName(ctx context.Context, name string) (*model.Repository, error) { + var repo model.Repository + if err := r.db.WithContext(ctx).Where("name = ?", name).First(&repo).Error; err != nil { return nil, err } return &repo, nil } -func (r *repository) List(ctx context.Context, cluster string) ([]*model.Repositories, error) { - var repos []*model.Repositories - if err := r.db.WithContext(ctx).Where("cluster = ?", cluster).Find(&repos).Error; err != nil { +func (r *repository) List(ctx context.Context) ([]*model.Repository, error) { + var repos []*model.Repository + if err := r.db.WithContext(ctx).Find(&repos).Error; err != nil { return nil, err } diff --git a/pkg/types/helm.go b/pkg/types/helm.go index b9c76cb2..0c6d2a89 100644 --- a/pkg/types/helm.go +++ b/pkg/types/helm.go @@ -25,8 +25,7 @@ type Release struct { } type RepoId struct { - Cluster string `uri:"cluster" binding:"required"` - Id int64 `uri:"id" binding:"required"` + Id int64 `uri:"id" binding:"required"` } type RepoName struct { @@ -41,40 +40,22 @@ type ChartValues struct { Chart string `form:"chart" binding:"required"` Version string `form:"version" binding:"required"` } -type RepoObjectMeta struct { - Cluster string `uri:"cluster" binding:"required"` -} type ReleaseHistory struct { Version int `form:"version"` } -type RepoForm struct { - Name string `json:"name" binding:"required"` - URL string `json:"url" binding:"required"` - Username string `json:"username"` - Password string `json:"password"` - CertFile string `json:"certFile"` - KeyFile string `json:"keyFile"` - CAFile string `json:"caFile"` - InsecureSkipTLSverify bool `json:"insecure_skip_tls_verify"` - PassCredentialsAll bool `json:"pass_credentials_all"` -} - -type RepoUpdateForm struct { - Name string `json:"name" binding:"required"` - URL string `json:"url" binding:"required"` - Username string `json:"username"` - Password string `json:"password"` - CertFile string `json:"certFile"` - KeyFile string `json:"keyFile"` - CAFile string `json:"caFile"` - InsecureSkipTLSverify bool `json:"insecure_skip_tls_verify"` - PassCredentialsAll bool `json:"pass_credentials_all"` - ResourceVersion *int64 `json:"resource_version" binding:"required"` +type CreateRepository struct { + Name string `json:"name" binding:"required"` + URL string `json:"url" binding:"required"` + Username string `json:"username"` + Password string `json:"password"` } -type HelmObjectMeta struct { - Cluster string `uri:"cluster" binding:"required"` - Namespace string `uri:"namespace" binding:"required"` +type UpdateRepository struct { + Name string `json:"name" binding:"required"` + URL string `json:"url" binding:"required"` + Username string `json:"username"` + Password string `json:"password"` + ResourceVersion *int64 `json:"resource_version" binding:"required"` }