diff --git a/Makefile b/Makefile index 99e72e6ca0747e5fdb23324eae5e21dd242416d5..cadb48b43b68a25dcd05a6f72a2a880f019f2069 100644 --- a/Makefile +++ b/Makefile @@ -88,7 +88,7 @@ docker-build-no-test: ks-apiserver ks-controller-manager # Run tests test: fmt vet - export KUBEBUILDER_CONTROLPLANE_START_TIMEOUT=1m; go test ./pkg/... ./cmd/... -covermode=atomic -coverprofile=coverage.txt + export KUBEBUILDER_CONTROLPLANE_START_TIMEOUT=2m; go test ./pkg/... ./cmd/... -covermode=atomic -coverprofile=coverage.txt .PHONY: clean clean: diff --git a/build/ks-apiserver/Dockerfile b/build/ks-apiserver/Dockerfile index 05a4d0f15f6e3f38ff367fe1e5e9e5a9046f2d9b..be3530ba435fac51cc29fc8e6469424cb744d204 100644 --- a/build/ks-apiserver/Dockerfile +++ b/build/ks-apiserver/Dockerfile @@ -1,10 +1,12 @@ # Copyright 2020 The KubeSphere Authors. All rights reserved. # Use of this source code is governed by an Apache license # that can be found in the LICENSE file. -FROM alpine:3.11 +FROM alpine/helm:3.4.2 as helm-base -RUN apk add --no-cache ca-certificates +FROM alpine:3.11 +RUN apk add --no-cache ca-certificates +COPY --from=helm-base /usr/bin/helm /usr/bin/helm # To speed up building process, we copy binary directly from make # result instead of building it again, so make sure you run the # following command first before building docker image diff --git a/build/ks-controller-manager/Dockerfile b/build/ks-controller-manager/Dockerfile index c7ba5dd400e4b95b717f553f83c6027f20e8d74a..e0f2e853eb5294cd07bab0f73bae9becfcd87b72 100644 --- a/build/ks-controller-manager/Dockerfile +++ b/build/ks-controller-manager/Dockerfile @@ -1,10 +1,12 @@ # Copyright 2020 The KubeSphere Authors. All rights reserved. # Use of this source code is governed by an Apache license # that can be found in the LICENSE file. +FROM alpine/helm:3.4.2 as helm-base + FROM alpine:3.11 RUN apk add --no-cache ca-certificates - +COPY --from=helm-base /usr/bin/helm /usr/bin/helm COPY /bin/cmd/controller-manager /usr/local/bin/ EXPOSE 8443 8080 diff --git a/cmd/controller-manager/app/controllers.go b/cmd/controller-manager/app/controllers.go index 6cd510f213a89b7945aceecd94554fc81f104d78..d792f5928e70a5470b90748a0ded6f4d2f8deeee 100644 --- a/cmd/controller-manager/app/controllers.go +++ b/cmd/controller-manager/app/controllers.go @@ -51,7 +51,6 @@ import ( "kubesphere.io/kubesphere/pkg/simple/client/multicluster" "kubesphere.io/kubesphere/pkg/simple/client/network" ippoolclient "kubesphere.io/kubesphere/pkg/simple/client/network/ippool" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" "kubesphere.io/kubesphere/pkg/simple/client/s3" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/kubefed/pkg/controller/util" @@ -66,7 +65,6 @@ func addControllers( ldapClient ldapclient.Interface, options *k8s.KubernetesOptions, authenticationOptions *authoptions.AuthenticationOptions, - openpitrixClient openpitrix.Client, multiClusterOptions *multicluster.Options, networkOptions *network.Options, serviceMeshEnabled bool, @@ -233,7 +231,6 @@ func addControllers( client.Config(), kubesphereInformer.Cluster().V1alpha1().Clusters(), client.KubeSphere().ClusterV1alpha1().Clusters(), - openpitrixClient, multiClusterOptions.ClusterControllerResyncSecond) } diff --git a/cmd/controller-manager/app/server.go b/cmd/controller-manager/app/server.go index 2434dab33baeaa23c96a543704e5d2d7aaafcbcd..233dc6bb8372867e0fb28fe3da2914f83fe9fe5c 100644 --- a/cmd/controller-manager/app/server.go +++ b/cmd/controller-manager/app/server.go @@ -18,12 +18,9 @@ package app import ( "fmt" + "github.com/spf13/cobra" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" - "kubesphere.io/kubesphere/pkg/controller/application" - "os" - - "github.com/spf13/cobra" utilerrors "k8s.io/apimachinery/pkg/util/errors" cliflag "k8s.io/component-base/cli/flag" "k8s.io/klog" @@ -31,8 +28,13 @@ import ( "kubesphere.io/kubesphere/cmd/controller-manager/app/options" "kubesphere.io/kubesphere/pkg/apis" controllerconfig "kubesphere.io/kubesphere/pkg/apiserver/config" + "kubesphere.io/kubesphere/pkg/controller/application" "kubesphere.io/kubesphere/pkg/controller/namespace" "kubesphere.io/kubesphere/pkg/controller/network/webhooks" + "kubesphere.io/kubesphere/pkg/controller/openpitrix/helmapplication" + "kubesphere.io/kubesphere/pkg/controller/openpitrix/helmcategory" + "kubesphere.io/kubesphere/pkg/controller/openpitrix/helmrelease" + "kubesphere.io/kubesphere/pkg/controller/openpitrix/helmrepo" "kubesphere.io/kubesphere/pkg/controller/quota" "kubesphere.io/kubesphere/pkg/controller/serviceaccount" "kubesphere.io/kubesphere/pkg/controller/user" @@ -45,10 +47,10 @@ import ( "kubesphere.io/kubesphere/pkg/simple/client/devops/jenkins" "kubesphere.io/kubesphere/pkg/simple/client/k8s" ldapclient "kubesphere.io/kubesphere/pkg/simple/client/ldap" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" "kubesphere.io/kubesphere/pkg/simple/client/s3" "kubesphere.io/kubesphere/pkg/utils/metrics" "kubesphere.io/kubesphere/pkg/utils/term" + "os" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/manager" "sigs.k8s.io/controller-runtime/pkg/runtime/signals" @@ -142,14 +144,6 @@ func run(s *options.KubeSphereControllerManagerOptions, stopCh <-chan struct{}) klog.Warning("ks-controller-manager starts without ldap provided, it will not sync user into ldap") } - var openpitrixClient openpitrix.Client - if s.OpenPitrixOptions != nil && !s.OpenPitrixOptions.IsEmpty() { - openpitrixClient, err = openpitrix.NewClient(s.OpenPitrixOptions) - if err != nil { - return fmt.Errorf("failed to connect to openpitrix, please check openpitrix status, error: %v", err) - } - } - var s3Client s3.Interface if s.S3Options != nil && len(s.S3Options.Endpoint) != 0 { s3Client, err = s3.NewS3Client(s.S3Options) @@ -224,6 +218,41 @@ func run(s *options.KubeSphereControllerManagerOptions, stopCh <-chan struct{}) klog.Fatalf("Unable to create namespace controller: %v", err) } + err = helmrepo.Add(mgr) + if err != nil { + klog.Fatal("Unable to create helm repo controller") + } + + err = helmcategory.Add(mgr) + if err != nil { + klog.Fatal("Unable to create helm category controller") + } + + if !s.OpenPitrixOptions.IsEmpty() { + storageClient, err := s3.NewS3Client(s.OpenPitrixOptions.S3Options) + if err != nil { + klog.Fatalf("failed to connect to s3, please check openpitrix s3 service status, error: %v", err) + } + err = (&helmapplication.ReconcileHelmApplication{}).SetupWithManager(mgr) + if err != nil { + klog.Fatalf("Unable to create helm application controller, error: %s", err) + } + + err = (&helmapplication.ReconcileHelmApplicationVersion{}).SetupWithManager(mgr) + if err != nil { + klog.Fatalf("Unable to create helm application version controller, error: %s ", err) + } + + err = (&helmrelease.ReconcileHelmRelease{ + StorageClient: storageClient, + KsFactory: informerFactory.KubeSphereSharedInformerFactory(), + }).SetupWithManager(mgr) + + if err != nil { + klog.Fatalf("Unable to create helm release controller, error: %s", err) + } + } + selector, _ := labels.Parse(s.ApplicationSelector) applicationReconciler := &application.ApplicationReconciler{ Scheme: mgr.GetScheme(), @@ -255,7 +284,6 @@ func run(s *options.KubeSphereControllerManagerOptions, stopCh <-chan struct{}) ldapClient, s.KubernetesOptions, s.AuthenticationOptions, - openpitrixClient, s.MultiClusterOptions, s.NetworkOptions, servicemeshEnabled, @@ -283,7 +311,9 @@ func run(s *options.KubeSphereControllerManagerOptions, stopCh <-chan struct{}) hookServer.Register("/validate-quota-kubesphere-io-v1alpha2", &webhook.Admission{Handler: resourceQuotaAdmission}) klog.V(2).Info("registering metrics to the webhook server") - hookServer.Register("/metrics", metrics.Handler()) + // Add an extra metric endpoint, so we can use the the same metric definition with ks-apiserver + // /kapis/metrics is independent of controller-manager's built-in /metrics + mgr.AddMetricsExtraHandler("/kapis/metrics", metrics.Handler()) klog.V(0).Info("Starting the controllers.") if err = mgr.Start(stopCh); err != nil { diff --git a/cmd/ks-apiserver/app/options/options.go b/cmd/ks-apiserver/app/options/options.go index d8f5bfab49dd834a14ec439c439905ab136a7907..45b8b7ece6f9e319cc0aff5adfb2b7d55789ccbf 100644 --- a/cmd/ks-apiserver/app/options/options.go +++ b/cmd/ks-apiserver/app/options/options.go @@ -39,7 +39,6 @@ import ( esclient "kubesphere.io/kubesphere/pkg/simple/client/logging/elasticsearch" "kubesphere.io/kubesphere/pkg/simple/client/monitoring/metricsserver" "kubesphere.io/kubesphere/pkg/simple/client/monitoring/prometheus" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" "kubesphere.io/kubesphere/pkg/simple/client/s3" fakes3 "kubesphere.io/kubesphere/pkg/simple/client/s3/fake" "kubesphere.io/kubesphere/pkg/simple/client/sonarqube" @@ -196,14 +195,6 @@ func (s *ServerRunOptions) NewAPIServer(stopCh <-chan struct{}) (*apiserver.APIS apiServer.AuditingClient = auditingClient } - if s.OpenPitrixOptions != nil && !s.OpenPitrixOptions.IsEmpty() { - opClient, err := openpitrix.NewClient(s.OpenPitrixOptions) - if err != nil { - return nil, fmt.Errorf("failed to connect to openpitrix, please check openpitrix status, error: %v", err) - } - apiServer.OpenpitrixClient = opClient - } - if s.AlertingOptions != nil && (s.AlertingOptions.PrometheusEndpoint != "" || s.AlertingOptions.ThanosRulerEndpoint != "") { alertingClient, err := alerting.NewRuleClient(s.AlertingOptions) if err != nil { diff --git a/config/crds/application.kubesphere.io_helmapplications.yaml b/config/crds/application.kubesphere.io_helmapplications.yaml new file mode 100644 index 0000000000000000000000000000000000000000..89bb4327dd438e3bd83987799b790bd600bcc651 --- /dev/null +++ b/config/crds/application.kubesphere.io_helmapplications.yaml @@ -0,0 +1,101 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: (devel) + creationTimestamp: null + name: helmapplications.application.kubesphere.io +spec: + group: application.kubesphere.io + names: + kind: HelmApplication + listKind: HelmApplicationList + plural: helmapplications + shortNames: + - happ + singular: helmapplication + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.name + name: application name + type: string + - jsonPath: .metadata.labels.kubesphere\.io/workspace + name: workspace + type: string + - jsonPath: .status.state + name: State + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: HelmApplication is the Schema for the helmapplications 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: HelmApplicationSpec defines the desired state of HelmApplication + properties: + abstraction: + description: info from frontend + type: string + appHome: + type: string + attachments: + description: attachments id + items: + type: string + type: array + description: + description: description from chart's description or frontend + type: string + icon: + description: The attachment id of the icon + type: string + name: + description: the name of the helm application + type: string + required: + - name + type: object + status: + description: HelmApplicationStatus defines the observed state of HelmApplication + properties: + latestVersion: + description: If this application belong to appStore, latestVersion is the the latest version of the active application version. otherwise latestVersion is the latest version of all application version + type: string + state: + description: 'the state of the helm application: draft, submitted, passed, rejected, suspended, active' + type: string + statusTime: + format: date-time + type: string + updateTime: + format: date-time + type: string + required: + - statusTime + - updateTime + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crds/application.kubesphere.io_helmapplicationversions.yaml b/config/crds/application.kubesphere.io_helmapplicationversions.yaml new file mode 100644 index 0000000000000000000000000000000000000000..481c82306adb554777560ad125bfbf192bb934e4 --- /dev/null +++ b/config/crds/application.kubesphere.io_helmapplicationversions.yaml @@ -0,0 +1,205 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: (devel) + creationTimestamp: null + name: helmapplicationversions.application.kubesphere.io +spec: + group: application.kubesphere.io + names: + kind: HelmApplicationVersion + listKind: HelmApplicationVersionList + plural: helmapplicationversions + shortNames: + - happver + singular: helmapplicationversion + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.name + name: application name + type: string + - jsonPath: .status.state + name: State + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: HelmApplicationVersion is the Schema for the helmapplicationversions 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: HelmApplicationVersionSpec defines the desired state of HelmApplicationVersion + properties: + annotations: + additionalProperties: + type: string + description: Annotations are additional mappings uninterpreted by Helm, made available for inspection by other applications. + type: object + apiVersion: + description: The API Version of this chart. + type: string + appVersion: + description: The version of the application enclosed inside of this chart. + type: string + condition: + description: The condition to check to enable chart + type: string + created: + description: chart create time + format: date-time + type: string + data: + description: raw data of chart, it will !!!NOT!!! be save to etcd + format: byte + type: string + dataKey: + description: dataKey in the storage + type: string + dependencies: + description: Dependencies are a list of dependencies for a chart. + items: + description: Dependency describes a chart upon which another chart depends. Dependencies can be used to express developer intent, or to capture the state of a chart. + properties: + alias: + description: Alias usable alias to be used for the chart + type: string + condition: + description: A yaml path that resolves to a boolean, used for enabling/disabling charts (e.g. subchart1.enabled ) + type: string + enabled: + description: Enabled bool determines if chart should be loaded + type: boolean + name: + description: Name is the name of the dependency. This must mach the name in the dependency's Chart.yaml. + type: string + repository: + description: The URL to the repository. Appending `index.yaml` to this string should result in a URL that can be used to fetch the repository index. + type: string + tags: + description: Tags can be used to group charts for enabling/disabling together + items: + type: string + type: array + version: + description: Version is the version (range) of this chart. A lock file will always produce a single version, while a dependency may contain a semantic version range. + type: string + required: + - name + - repository + type: object + type: array + deprecated: + description: Whether or not this chart is deprecated + type: boolean + description: + description: A one-sentence description of the chart + type: string + digest: + description: chart digest + type: string + home: + description: The URL to a relevant project page, git repo, or contact person + type: string + icon: + description: The URL to an icon file. + type: string + keywords: + description: A list of string keywords + items: + type: string + type: array + kubeVersion: + description: KubeVersion is a SemVer constraint specifying the version of Kubernetes required. + type: string + maintainers: + description: A list of name and URL/email address combinations for the maintainer(s) + items: + description: Maintainer describes a Chart maintainer. + properties: + email: + description: Email is an optional email address to contact the named maintainer + type: string + name: + description: Name is a user name or organization name + type: string + url: + description: URL is an optional URL to an address for the named maintainer + type: string + type: object + type: array + name: + description: The name of the chart + type: string + sources: + description: Source is the URL to the source code of this chart + items: + type: string + type: array + tags: + description: The tags to check to enable chart + type: string + type: + description: 'Specifies the chart type: application or library' + type: string + urls: + description: chart url + items: + type: string + type: array + version: + description: A SemVer 2 conformant version string of the chart + type: string + type: object + status: + description: HelmApplicationVersionStatus defines the observed state of HelmApplicationVersion + properties: + audit: + items: + properties: + message: + description: audit message + type: string + operator: + description: audit operator + type: string + operatorType: + type: string + state: + description: 'audit state: submitted, passed, draft, active, rejected, suspended' + type: string + time: + description: audit time + format: date-time + type: string + required: + - time + type: object + type: array + state: + type: string + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crds/application.kubesphere.io_helmcategories.yaml b/config/crds/application.kubesphere.io_helmcategories.yaml new file mode 100644 index 0000000000000000000000000000000000000000..a7339d454e0047ab0b54f961e0ee8a889e84990c --- /dev/null +++ b/config/crds/application.kubesphere.io_helmcategories.yaml @@ -0,0 +1,76 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: (devel) + creationTimestamp: null + name: helmcategories.application.kubesphere.io +spec: + group: application.kubesphere.io + names: + kind: HelmCategory + listKind: HelmCategoryList + plural: helmcategories + shortNames: + - hctg + singular: helmcategory + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.name + name: name + type: string + - jsonPath: .status.total + name: total + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: HelmCategory is the Schema for the helmcategories 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: HelmCategorySpec defines the desired state of HelmRepo + properties: + description: + description: info from frontend + type: string + locale: + type: string + name: + description: name of the category + type: string + required: + - name + type: object + status: + properties: + total: + description: total helmapplications belong to this category + type: integer + required: + - total + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crds/application.kubesphere.io_helmreleases.yaml b/config/crds/application.kubesphere.io_helmreleases.yaml new file mode 100644 index 0000000000000000000000000000000000000000..801276375322d7ad32fed24d3ca827602ee06853 --- /dev/null +++ b/config/crds/application.kubesphere.io_helmreleases.yaml @@ -0,0 +1,145 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: (devel) + creationTimestamp: null + name: helmreleases.application.kubesphere.io +spec: + group: application.kubesphere.io + names: + kind: HelmRelease + listKind: HelmReleaseList + plural: helmreleases + shortNames: + - hrls + singular: helmrelease + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.name + name: Release Name + type: string + - jsonPath: .metadata.labels.kubesphere\.io/workspace + name: Workspace + type: string + - jsonPath: .metadata.labels.kubesphere\.io/cluster + name: Cluster + type: string + - jsonPath: .metadata.labels.kubesphere\.io/namespace + name: Namespace + type: string + - jsonPath: .status.state + name: State + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: HelmRelease is the Schema for the helmreleases 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: HelmReleaseSpec defines the desired state of HelmRelease + properties: + appId: + description: id of the helmapplication + type: string + appVerId: + description: application version id + type: string + chartAppVer: + description: appVersion from Chart.yaml + type: string + chartName: + description: The name of the chart which will be installed. + type: string + chartVersion: + description: Specify the exact chart version to install. If this is not specified, the latest version is installed + type: string + description: + description: Message got from frontend + type: string + name: + description: Name of the release + type: string + repoId: + description: id of the repo + type: string + values: + description: helm release values.yaml + format: byte + type: string + version: + description: expected release version, when this version is not equal status.version, the release need upgrade this filed should be modified when any filed of the spec modified. + type: integer + required: + - chartName + - chartVersion + - name + - version + type: object + status: + description: HelmReleaseStatus defines the observed state of HelmRelease + properties: + deployStatus: + description: deploy status list of history, which will store at most 10 state + items: + properties: + deployTime: + description: deploy time + format: date-time + type: string + message: + description: A human readable message indicating details about why the release is in this state. + type: string + state: + description: deploy state + type: string + required: + - deployTime + - state + type: object + type: array + lastDeployed: + description: last successful deploy time + format: date-time + type: string + lastUpdate: + description: last update time + format: date-time + type: string + message: + description: A human readable message indicating details about why the release is in this state. + type: string + state: + description: current state + type: string + version: + description: current release version + type: integer + required: + - state + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/config/crds/application.kubesphere.io_helmrepos.yaml b/config/crds/application.kubesphere.io_helmrepos.yaml new file mode 100644 index 0000000000000000000000000000000000000000..6b0e01c2217c2dd2d5970f1e175e5d874e8f88c2 --- /dev/null +++ b/config/crds/application.kubesphere.io_helmrepos.yaml @@ -0,0 +1,142 @@ + +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: (devel) + creationTimestamp: null + name: helmrepos.application.kubesphere.io +spec: + group: application.kubesphere.io + names: + kind: HelmRepo + listKind: HelmRepoList + plural: helmrepos + shortNames: + - hrepo + singular: helmrepo + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .spec.name + name: name + type: string + - jsonPath: .metadata.labels.kubesphere\\.io/workspace + name: Workspace + type: string + - jsonPath: .spec.url + name: url + type: string + - jsonPath: .status.state + name: State + type: string + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: HelmRepo is the Schema for the helmrepoes 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: HelmRepoSpec defines the desired state of HelmRepo + properties: + credential: + description: helm repo credential + properties: + accessKeyID: + type: string + caFile: + description: verify certificates of HTTPS-enabled servers using this CA bundle + type: string + certFile: + description: identify HTTPS client using this SSL certificate file + type: string + insecureSkipTLSVerify: + description: skip tls certificate checks for the repository, default is ture + type: boolean + keyFile: + description: identify HTTPS client using this SSL key file + type: string + password: + description: chart repository password + type: string + secretAccessKey: + type: string + username: + description: chart repository username + type: string + type: object + description: + description: chart repo description from frontend + type: string + name: + description: name of the repo + type: string + syncPeriod: + description: sync period in seconds, no sync when SyncPeriod=0, the minimum SyncPeriod is 180s + type: integer + url: + description: helm repo url + type: string + version: + description: expected repo version, when this version is not equal status.version, the repo need upgrade this filed should be modified when any filed of the spec modified. + type: integer + required: + - name + - url + type: object + status: + description: HelmRepoStatus defines the observed state of HelmRepo + properties: + data: + description: repo index + type: string + lastUpdateTime: + description: status last update time + format: date-time + type: string + state: + description: current state of the repo, successful, failed or syncing + type: string + syncState: + description: sync state list of history, which will store at most 10 state + items: + properties: + message: + description: A human readable message indicating details about why the repo is in this state. + type: string + state: + description: 'last sync state, valid state are: "failed", "success", and ""' + type: string + syncTime: + format: date-time + type: string + required: + - syncTime + type: object + type: array + version: + description: if status.version!=spec.Version, we need sync the repo now + type: integer + type: object + type: object + served: true + storage: true + subresources: + status: {} +status: + acceptedNames: + kind: "" + plural: "" + conditions: [] + storedVersions: [] diff --git a/go.mod b/go.mod index 4fd18bad158ea2f63c028bb565c9efa150ddb381..302f8574ffcc116782555cf6d438f198730141b6 100644 --- a/go.mod +++ b/go.mod @@ -8,8 +8,9 @@ go 1.13 require ( code.cloudfoundry.org/bytefmt v0.0.0-20190710193110-1eb035ffe2b6 + github.com/Masterminds/semver/v3 v3.1.0 github.com/PuerkitoBio/goquery v1.5.0 - github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 + github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 github.com/aws/aws-sdk-go v1.33.12 github.com/beevik/etree v1.1.0 github.com/container-storage-interface/spec v1.2.0 @@ -18,7 +19,7 @@ require ( github.com/davecgh/go-spew v1.1.1 github.com/dgrijalva/jwt-go v3.2.0+incompatible github.com/docker/distribution v2.7.1+incompatible - github.com/docker/docker v1.4.2-0.20190822205725-ed20165a37b4 + github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce github.com/elastic/go-elasticsearch/v5 v5.6.1 github.com/elastic/go-elasticsearch/v6 v6.8.2 github.com/elastic/go-elasticsearch/v7 v7.3.0 @@ -53,7 +54,7 @@ require ( github.com/onsi/ginkgo v1.14.0 github.com/onsi/gomega v1.10.1 github.com/open-policy-agent/opa v0.18.0 - github.com/opencontainers/go-digest v1.0.0-rc1 + github.com/opencontainers/go-digest v1.0.0 github.com/patrickmn/go-cache v2.1.0+incompatible // indirect github.com/pkg/errors v0.9.1 github.com/projectcalico/kube-controllers v3.8.8+incompatible @@ -66,6 +67,7 @@ require ( github.com/prometheus/prometheus v1.8.2-0.20200907175821-8219b442c864 github.com/sony/sonyflake v1.0.0 github.com/speps/go-hashids v2.0.0+incompatible + github.com/spf13/afero v1.2.2 github.com/spf13/cobra v1.0.0 github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.4.0 @@ -83,6 +85,7 @@ require ( gopkg.in/yaml.v2 v2.3.0 gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 gotest.tools v2.2.0+incompatible + helm.sh/helm/v3 v3.3.0 istio.io/api v0.0.0-20201113182140-d4b7e3fc2b44 istio.io/client-go v0.0.0-20201113183938-0734e976e785 istio.io/gogo-genproto v0.0.0-20201113182723-5b8563d8a012 // indirect @@ -106,6 +109,7 @@ require ( sigs.k8s.io/controller-runtime v0.6.4 sigs.k8s.io/controller-tools v0.4.0 sigs.k8s.io/kubefed v0.4.0 + sigs.k8s.io/yaml v1.2.0 ) replace ( @@ -250,7 +254,7 @@ replace ( github.com/disintegration/imaging => github.com/disintegration/imaging v1.6.1 github.com/docker/cli => github.com/docker/cli v0.0.0-20190506213505-d88565df0c2d github.com/docker/distribution => github.com/docker/distribution v2.7.1+incompatible - github.com/docker/docker => github.com/docker/engine v1.4.2-0.20190822205725-ed20165a37b4 + github.com/docker/docker => github.com/docker/engine v1.4.2-0.20200203170920-46ec8731fbce github.com/docker/docker-credential-helpers => github.com/docker/docker-credential-helpers v0.6.1 github.com/docker/go-connections => github.com/docker/go-connections v0.4.0 github.com/docker/go-metrics => github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 @@ -528,7 +532,7 @@ replace ( github.com/onsi/gomega => github.com/onsi/gomega v1.10.1 github.com/op/go-logging => github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/open-policy-agent/opa => github.com/open-policy-agent/opa v0.18.0 - github.com/opencontainers/go-digest => github.com/opencontainers/go-digest v1.0.0-rc1 + github.com/opencontainers/go-digest => github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec => github.com/opencontainers/image-spec v1.0.1 github.com/opencontainers/runc => github.com/opencontainers/runc v0.1.1 github.com/opentracing-contrib/go-grpc => github.com/opentracing-contrib/go-grpc v0.0.0-20180928155321-4b5a12d3ff02 @@ -661,7 +665,7 @@ replace ( go.uber.org/multierr => go.uber.org/multierr v1.3.0 go.uber.org/tools => go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee go.uber.org/zap => go.uber.org/zap v1.13.0 - golang.org/x/crypto => golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 + golang.org/x/crypto => golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 golang.org/x/exp => golang.org/x/exp v0.0.0-20190121172915-509febef88a4 golang.org/x/image => golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81 golang.org/x/lint => golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f @@ -714,7 +718,7 @@ replace ( gopkg.in/yaml.v2 => gopkg.in/yaml.v2 v2.3.0 gopkg.in/yaml.v3 => gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c gotest.tools => gotest.tools v2.2.0+incompatible - helm.sh/helm/v3 => helm.sh/helm/v3 v3.0.1 + helm.sh/helm/v3 => helm.sh/helm/v3 v3.3.0 honnef.co/go/tools => honnef.co/go/tools v0.0.1-2020.1.3 howett.net/plist => howett.net/plist v0.0.0-20181124034731-591f970eefbb istio.io/api => istio.io/api v0.0.0-20201113182140-d4b7e3fc2b44 diff --git a/go.sum b/go.sum index 3d874ad6de2c69d0f7343e6908cd9fd89b87a615..c05028c4836316dafb13cdd6c66f0d74c42d750b 100644 --- a/go.sum +++ b/go.sum @@ -25,15 +25,16 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03 github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/DataDog/datadog-go v3.2.0+incompatible/go.mod h1:LButxg5PwREeZtORoXG3tL4fMGNddJ+vMq1mwgfaqoQ= github.com/Knetic/govaluate v3.0.1-0.20171022003610-9aa49832a739+incompatible/go.mod h1:r7JcOSlj0wfOMncg0iLm8Leh48TZaKVeNIfJntJ2wa0= +github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e h1:eb0Pzkt15Bm7f2FFYv7sjY7NPFi3cPkS3tv1CcrFBWA= github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e/go.mod h1:64YHyfSL2R96J44Nlwm39UHepQbyR5q10x7iYa1ks2E= github.com/Masterminds/goutils v1.1.0/go.mod h1:8cTjp+g8YejhMuvIA5y2vz3BpJxksy863GQaJW2MFNU= github.com/Masterminds/semver v1.5.0 h1:H65muMkzWKEuNDnfl9d70GUjFniHKHRbFPGBuZ3QEww= github.com/Masterminds/semver v1.5.0/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y= +github.com/Masterminds/semver/v3 v3.0.1 h1:2kKm5lb7dKVrt5TYUiAavE6oFc1cFT0057UVGT+JqLk= github.com/Masterminds/semver/v3 v3.0.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/Masterminds/sprig/v3 v3.0.0/go.mod h1:NEUY/Qq8Gdm2xgYA+NwJM6wmfdRV9xkh8h/Rld20R0U= github.com/Masterminds/squirrel v0.0.0-20161115235646-20f192218cf5/go.mod h1:xnKTFzjGUiZtiOagBsfnvomW+nJg2usB1ZpordQWqNM= github.com/Masterminds/vcs v1.13.0/go.mod h1:N09YCmOQr6RLxC6UNHzuVwAdodYbbnycGHSmwVJjcKA= -github.com/Microsoft/go-winio v0.4.12 h1:xAfWHN1IrQ0NJ9TBC0KBZoqLjzDTr1ML+4MywiUOryc= github.com/Microsoft/go-winio v0.4.12/go.mod h1:VhR8bwka0BXejwEJY73c50VrPtXAaKcyvVC4A4RozmA= github.com/Microsoft/hcsshim v0.8.6/go.mod h1:Op3hHsoHPAvb6lceZHDtd9OkTew38wNoXnJs8iY7rUg= github.com/NYTimes/gziphandler v1.1.1 h1:ZUDjpQae29j0ryrS0u/B8HZfJBtBQHjqw2rQ2cqUQ3I= @@ -55,7 +56,6 @@ github.com/VividCortex/gohistogram v1.0.0/go.mod h1:Pf5mBqqDxYaXu3hDrrU+w6nw50o/ github.com/afex/hystrix-go v0.0.0-20180502004556-fa1af6a1f4f5/go.mod h1:SkGFH1ia65gfNATL8TAiHDNxPzPdmEL5uirI2Uyuz6c= github.com/agnivade/levenshtein v1.0.1/go.mod h1:CURSv5d9Uaml+FovSIICkLbAUZ9S4RqaHDIsdSBg7lM= github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= -github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7 h1:uSoVVbwJiQipAclBbw+8quDsfcvFjOpI5iCf4p/cqCs= github.com/alcortesm/tgz v0.0.0-20161220082320-9c5fe88206d7/go.mod h1:6zEj6s6u/ghQa61ZWa/C2Aw3RkjiTBOix7dkqa1VLIs= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -66,7 +66,6 @@ github.com/aliyun/aliyun-oss-go-sdk v2.0.4+incompatible/go.mod h1:T/Aws4fEfogEE9 github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= github.com/andybalholm/cascadia v1.0.0 h1:hOCXnnZ5A+3eVDX8pvgl4kofXv2ELss0bKcqRySc45o= github.com/andybalholm/cascadia v1.0.0/go.mod h1:GsXiBklL0woXo1j/WYWtSYYC4ouU9PqHO0sqidkEA4Y= -github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= github.com/antihax/optional v0.0.0-20180407024304-ca021399b1a6/go.mod h1:V8iCPQYkqmusNa815XgQio277wI47sdRh1dUOLdyC6Q= github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= @@ -90,11 +89,9 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= github.com/bitly/go-hostpool v0.0.0-20171023180738-a3a6125de932/go.mod h1:NOuUCSz6Q9T7+igc/hlvDOUdtWKryOrtFyIVABv/p7k= -github.com/bitly/go-simplejson v0.5.0 h1:6IH+V8/tVMab511d5bn4M7EwGXZf9Hj6i2xSwkNEM+Y= github.com/bitly/go-simplejson v0.5.0/go.mod h1:cXHtHw4XUPsvGaxgjIAn8PhEWG9NfngEKAMDJEczWVA= github.com/blang/semver v3.5.0+incompatible h1:CGxCgetQ64DKk7rdZ++Vfnb1+ogGNnB17OJKJXD2Cfs= github.com/blang/semver v3.5.0+incompatible/go.mod h1:kRBLl5iJ+tD4TcOOxsy/0fnwebNt5EWlYSAyrTnjyyk= -github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869 h1:DDGfHa7BWjL4YnC6+E63dPcxHo2sUxDIu8g3QgEJdRY= github.com/bmizerany/assert v0.0.0-20160611221934-b7ed37b82869/go.mod h1:Ekp36dRnpXw/yCqJaO+ZrUyxD+3VXMFFr56k5XYrpB4= github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= @@ -124,9 +121,7 @@ github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp github.com/clbanning/x2j v0.0.0-20191024224557-825249438eec/go.mod h1:jMjuTZXRI4dUb/I5gc9Hdhagfvm9+RyrPryS/auMzxE= github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= github.com/cockroachdb/cockroach-go v0.0.0-20181001143604-e0a95dfd547c/go.mod h1:XGLbWH/ujMcbPbhZq52Nv6UrCghb1yGn//133kEsvDk= -github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa h1:OaNxuTZr7kxeODyLWsRMC+OD03aFUH+mW6r2d+MWa5Y= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= -github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd h1:qMd81Ts1T2OTKmB4acZcyKaMtRnY5Y44NuXGX2GFJ1w= github.com/codahale/hdrhistogram v0.0.0-20161010025455-3a0bb77429bd/go.mod h1:sE/e/2PUdi/liOCUjSTXgM1o87ZssimdTWN964YiIeI= github.com/container-storage-interface/spec v1.2.0 h1:bD9KIVgaVKKkQ/UbVUY9kCaH/CJbhNxe0eeB4JeJV2s= github.com/container-storage-interface/spec v1.2.0/go.mod h1:6URME8mwIBbpVyZV93Ce5St17xBiQJQY67NDsuohiy4= @@ -141,7 +136,6 @@ github.com/coreos/etcd v3.3.17+incompatible h1:f/Z3EoDSx1yjaIjLQGo1diYUlQYSBrrAQ github.com/coreos/etcd v3.3.17+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= github.com/coreos/go-oidc v2.1.0+incompatible h1:sdJrfw8akMnCuUlaZU3tE/uYXFgfqom8DBE9so9EBsM= github.com/coreos/go-oidc v2.1.0+incompatible/go.mod h1:CgnwVTmzoESiwO9qyAFEMiHoZ1nMCKZlZ9V6mm3/LKc= -github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM= github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f h1:JOrtw2xFKzlg+cbHpyrpLDmnN1HqhBfnX7WDiW7eG2c= github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= @@ -165,7 +159,6 @@ github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhr github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/daviddengcn/go-colortext v0.0.0-20160507010035-511bcaf42ccd/go.mod h1:dv4zxwHi5C/8AeI+4gX4dCWOIvNi7I6JCSX0HvlKPgE= -github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= github.com/deislabs/oras v0.7.0/go.mod h1:sqMKPG3tMyIX9xwXUBRLhZ24o+uT4y6jgBD2RzUTKDM= github.com/denisenkom/go-mssqldb v0.0.0-20190204142019-df6d76eb9289/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= @@ -181,8 +174,8 @@ github.com/docker/distribution v2.7.1+incompatible h1:a5mlkVzth6W5A4fOsS3D2EO5BU github.com/docker/distribution v2.7.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= github.com/docker/docker-credential-helpers v0.6.1 h1:Dq4iIfcM7cNtddhLVWe9h4QDjsi4OER3Z8voPu/I52g= github.com/docker/docker-credential-helpers v0.6.1/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y= -github.com/docker/engine v1.4.2-0.20190822205725-ed20165a37b4 h1:+VAGRKyn9Ca+ckzV/PJsaRO7UXO9KQjFmSffcSDrWdE= -github.com/docker/engine v1.4.2-0.20190822205725-ed20165a37b4/go.mod h1:3CPr2caMgTHxxIAZgEMd3uLYPDlRvPqCpyeRf6ncPcY= +github.com/docker/engine v1.4.2-0.20200203170920-46ec8731fbce h1:9Etplkui0JcHdExVif7vMl/Q8aqOde4FWtfTW7VcVsk= +github.com/docker/engine v1.4.2-0.20200203170920-46ec8731fbce/go.mod h1:3CPr2caMgTHxxIAZgEMd3uLYPDlRvPqCpyeRf6ncPcY= github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ= github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec= github.com/docker/go-metrics v0.0.0-20181218153428-b84716841b82 h1:X0fj836zx99zFu83v/M79DuBn84IL/Syx1SY6Y5ZEMA= @@ -193,7 +186,6 @@ github.com/docker/libtrust v0.0.0-20160708172513-aabc10ec26b7/go.mod h1:cyGadeNE github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c h1:ZfSZ3P3BedhKGUhzj7BQlPSU4OvT6tfOKe3DVHzOA7s= github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM= github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE= -github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo= github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= @@ -209,9 +201,7 @@ github.com/elastic/go-elasticsearch/v7 v7.3.0 h1:H29Nqf9cB9dVxX6LwS+zTDC2D4t9s+8 github.com/elastic/go-elasticsearch/v7 v7.3.0/go.mod h1:OJ4wdbtDNk5g503kvlHLyErCgQwwzmDtaFC4XyOxXA4= github.com/elastic/go-sysinfo v1.1.1/go.mod h1:i1ZYdU10oLNfRzq4vq62BEwD2fH8KaWh6eh0ikPT9F0= github.com/elastic/go-windows v1.0.1/go.mod h1:FoVvqWSun28vaDQPbj2Elfc0JahhPB7WQEGa3c814Ss= -github.com/elazarl/goproxy v0.0.0-20200315184450-1f3cb6622dad h1:zPs0fNF2Io1Qytf92EI2CDJ9oCXZr+NmjEVexrUEdq4= github.com/elazarl/goproxy v0.0.0-20200315184450-1f3cb6622dad/go.mod h1:Ro8st/ElPeALwNFlcTpWmkr6IoMFfkjXAvTHpevnDsM= -github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2 h1:dWB6v3RcOy03t/bUadywsbyrQwCqZeNIEX6M1OtSZOM= github.com/elazarl/goproxy/ext v0.0.0-20190711103511-473e67f1d7d2/go.mod h1:gNh8nYJoAm43RfaxurUnxr+N1PwuFV3ZMl/efxlIlY8= github.com/ema/qdisc v0.0.0-20190904071900-b82c76788043/go.mod h1:ix4kG2zvdUd8kEKSW0ZTr1XLks0epFpI4j745DXxlNE= github.com/emicklei/go-restful v2.14.3+incompatible h1:i59XyRHAxKCVBw3vHzQlpP/+pi89wH1v1HL+RKyVgxk= @@ -226,18 +216,16 @@ github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses= github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk= github.com/evanphx/json-patch/v5 v5.0.0/go.mod h1:G79N1coSVB93tBe7j6PhzjmR3/2VvlbKOFpnXhI9Bw4= +github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d h1:105gxyaGwCFad8crR9dcMQWvV9Hvulu6hwUh4tWPJnM= github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d/go.mod h1:ZZMPRZwes7CROmyNKgQzC3XPs6L/G2EJLHddWejkmf4= github.com/facette/natsort v0.0.0-20181210072756-2cd4dd1e2dcb/go.mod h1:bH6Xx7IW64qjjJq8M2u4dxNaBiDfKK+z/3eGDpXEQhc= -github.com/fatih/camelcase v1.0.0 h1:hxNvNX/xYBp0ovncs8WyWZrOrpBNub/JfaMvbURyft8= github.com/fatih/camelcase v1.0.0/go.mod h1:yN2Sb0lFhZJUdVvtELVWefmrXpuZESvPmqwoZc+/fpc= -github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/fatih/structs v1.1.0 h1:Q7juDM0QtcnhCpeyLGQKyg4TOIghuNXrkL32pHAUMxo= github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M= github.com/fatih/structtag v1.1.0/go.mod h1:mBJUNpUnHmRKrKlQQlmCrh5PuhftFbNv8Ys4/aAZl94= github.com/felixge/fgprof v0.9.1/go.mod h1:7/HK6JFtFaARhIljgP2IV8rJLIoHDoOYoUphsnGvqxE= github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568 h1:BHsljHzVlRcyQhjrss6TZTdY2VfCqZPbv5k3iBFa2ZQ= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= github.com/franela/goblin v0.0.0-20200105215937-c9ffbefa60db/go.mod h1:7dvUGVsVBjqR7JHJk0brhHOZYGmfBYOrK0ZhYMEtBr4= @@ -250,7 +238,6 @@ github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk= github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gin-contrib/sse v0.0.0-20190301062529-5545eab6dad3/go.mod h1:VJ0WA2NBN22VlZ2dKZQPAPnyWw5XTlK1KymzLKsr59s= github.com/gin-gonic/gin v1.4.0/go.mod h1:OW2EZn3DO8Ln9oIKOvM++LBO+5UPHJJDH72/q/3rZdM= -github.com/gliderlabs/ssh v0.1.1 h1:j3L6gSLQalDETeEg/Jg0mGY0/y/N6zI2xX1978P0Uqw= github.com/gliderlabs/ssh v0.1.1/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0= github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= @@ -262,7 +249,6 @@ github.com/go-logfmt/logfmt v0.5.0 h1:TrB8swr/68K7m9CcGut2g3UOihhbcbiMAYiuTXdEih github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-logr/logr v0.1.0 h1:M1Tv3VzNlEHg6uyACnRdtrploV2P7wZqH8BoQMtz0cg= github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas= -github.com/go-logr/zapr v0.1.1 h1:qXBXPDdNncunGs7XeEpsJt8wCjYBygluzfdLO0G5baE= github.com/go-logr/zapr v0.1.1/go.mod h1:tabnROwaDl0UNxkVeFRbY8bwB37GwRv0P8lg6aAiEnk= github.com/go-ole/go-ole v1.2.1/go.mod h1:7FAglXiTm7HKlQRDeOQ6ZNUHidzCWXuZWq/1dTyBNF8= github.com/go-openapi/analysis v0.19.10 h1:5BHISBAXOc/aJK25irLZnx2D3s6WyYaY9D4gmuz9fdE= @@ -296,7 +282,6 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/gobuffalo/attrs v0.0.0-20190224210810-a9411de4debd/go.mod h1:4duuawTqi2wkkpB4ePgWMaai6/Kc6WEz83bhFwpHzj0= github.com/gobuffalo/depgen v0.1.0/go.mod h1:+ifsuy7fhi15RWncXQQKjWS9JPkdah5sZvtHc2RXGlg= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= -github.com/gobuffalo/flect v0.2.0 h1:EWCvMGGxOjsgwlWaP+f4+Hh6yrrte7JeFL2S6b+0hdM= github.com/gobuffalo/flect v0.2.0/go.mod h1:W3K3X9ksuZfir8f/LrfVtWmCDQFfayuylOJ7sz/Fj80= github.com/gobuffalo/genny v0.1.1/go.mod h1:5TExbEyY48pfunL4QSXxlDOmdsD44RRq4mVZ0Ex28Xk= github.com/gobuffalo/gitgen v0.0.0-20190315122116-cc086187d211/go.mod h1:vEHJk/E9DmhejeLeNt7UVvlSGv3ziL+djtTr3yyzcOw= @@ -315,6 +300,7 @@ github.com/gocql/gocql v0.0.0-20200526081602-cd04bd7f22a7/go.mod h1:DL0ekTmBSTdl github.com/gocraft/dbr v0.0.0-20180507214907-a0fd650918f6 h1:kumyNm8Vr8cbVm/aLQYTbDE3SKCbbn5HEVoDp/Dyyfc= github.com/gocraft/dbr v0.0.0-20180507214907-a0fd650918f6/go.mod h1:K/9g3pPouf13kP5K7pdriQEJAy272R9yXuWuDIEWJTM= github.com/godbus/dbus v0.0.0-20190402143921-271e53dc4968/go.mod h1:/YcGZj5zSblfDWMMoOzV4fas9FZnQYTkDnsGvmh2Grw= +github.com/godror/godror v0.13.3/go.mod h1:2ouUT4kdhUBk7TAkHWD4SN0CdI0pgEQbo8FVHhbSKWg= github.com/gofrs/flock v0.7.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/googleapis v1.1.0 h1:kFkMAZBNAn4j7K0GiZr8cRYzejq68VbheufiV3YuyFI= @@ -367,13 +353,12 @@ github.com/gophercloud/gophercloud v0.10.0/go.mod h1:gmC5oQqMDOMO1t1gq5DquX/yAU8 github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/handlers v1.4.0/go.mod h1:Qkdc/uu4tH4g6mTK6auzZ766c4CA0Ng8+o/OAirnOIQ= -github.com/gorilla/mux v1.7.3 h1:gnP5JzjVOuiZD07fKKToCAOjS0yOpj/qPETTXCCS6hw= github.com/gorilla/mux v1.7.3/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= github.com/gosuri/uitable v0.0.1/go.mod h1:tKR86bXuXPZazfOTG1FIzvjIdXzd0mo4Vtn16vt0PJo= +github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f h1:ShTPMJQes6tubcjzGMODIVG5hlrCeImaBnZzKF2N8SM= github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA= -github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 h1:THDBEeQ9xZ8JEaCLyLQqXMMdRqNr0QAUJTIkQAUtFjg= github.com/grpc-ecosystem/go-grpc-middleware v1.1.0/go.mod h1:f5nM7jw/oeRSadq3xCzHAvxcr8HZnzsqU6ILg/0NiiE= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= @@ -409,7 +394,6 @@ github.com/hudl/fargo v1.3.0/go.mod h1:y3CKSmjA+wD2gak7sUSXTAoopbhU08POFhmITJgmK github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/imdario/mergo v0.3.9 h1:UauaLniWCFHWd+Jp9oCEkTBj8VO/9DKg3PV3VCNMDIg= github.com/imdario/mergo v0.3.9/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA= -github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/influxdata/flux v0.65.0/go.mod h1:BwN2XG2lMszOoquQaFdPET8FRQfrXiZsWmcMO9rkaVY= github.com/influxdata/influxdb v1.8.0/go.mod h1:SIzcnsjaHRFpmlxpJ4S3NT64qtEKYweNTUMb/vh0OMQ= @@ -430,9 +414,9 @@ github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLl github.com/jinzhu/now v1.0.0/go.mod h1:oHTiXerJ20+SfYcrdlBO7rzZRJWGwSTQ0iUY2jI6Gfc= github.com/jmespath/go-jmespath v0.3.0 h1:OS12ieG61fsCg5+qLJ+SsW9NicxNkg3b25OyT2yCeUc= github.com/jmespath/go-jmespath v0.3.0/go.mod h1:9QtRXoHjLGCJ5IBSaohpXITPlowMeeYCZ7fLUTSywik= +github.com/jmoiron/sqlx v1.2.0/go.mod h1:1FEQNm3xlJgrMD+FBdI9+xvCksHtbpVBBw5dYhBSsks= github.com/joeshaw/multierror v0.0.0-20140124173710-69b34d4ec901/go.mod h1:Z86h9688Y0wesXCyonoVr47MasHilkuLMqGhRZ4Hpak= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= -github.com/jonboulle/clockwork v0.1.0 h1:VKV+ZcuP6l3yW9doeqz6ziZGgcynBVQO+obU0+0hcPo= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4= github.com/jsimonetti/rtnetlink v0.0.0-20200117123717-f846d4f6c1f4/go.mod h1:WGuG/smIU4J/54PblvSbh+xvCZmpJnFgr3ds6Z55XMQ= @@ -448,7 +432,6 @@ github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= github.com/kardianos/osext v0.0.0-20170510131534-ae77be60afb1/go.mod h1:1NbS8ALrpOvjt0rHPNLyCIeMtbizbir8U//inJ+zuB8= github.com/karrick/godirwalk v1.10.3/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= -github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8= github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e h1:RgQk53JHp/Cjunrr1WlsXSZpqXn+uREuHvUVcK82CV8= github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= @@ -460,14 +443,10 @@ github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM52 github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= github.com/knq/sysutil v0.0.0-20191005231841-15668db23d08/go.mod h1:dFWs1zEqDjFtnBXsd1vPOZaLsESovai349994nHx3e0= -github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7 h1:SWlt7BoQNASbhTUD0Oy5yysI2seJ7vWuGUp///OM4TM= github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7/go.mod h1:Y2SaZf2Rzd0pXkLVhLlCiAXFCLSXAIbTKDivVgff/AM= -github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.2.0 h1:s5hAObm+yFO5uHYt5dYjxi2rXrsnmRpJx4OYvIWUaQs= github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= github.com/kr/pty v1.1.5/go.mod h1:9r2w37qlBe7rQ6e1fg1S/9xpWHSnaqNdHD3WcMdbPDA= -github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kshvakov/clickhouse v1.3.5/go.mod h1:DMzX7FxRymoNkVgizH0DWAL8Cur7wHLgx3MUnGwJqpE= github.com/kubernetes-csi/external-snapshotter/client/v3 v3.0.0 h1:OYDCOjVcx/5wNzlZ/At8otRibUlw0T6R0xOD31f32bw= @@ -477,7 +456,6 @@ github.com/kubesphere/sonargo v0.0.2/go.mod h1:ww8n9ANlDXhX5PBZ18iaRnCgEkXN0GMml github.com/kylelemons/godebug v0.0.0-20160406211939-eadb3ce320cb/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/leanovate/gopter v0.2.4/go.mod h1:gNcbPWNEWRe4lm+bycKqxUYoH5uoVje5SkOJ3uoLer8= github.com/leodido/go-urn v0.0.0-20181204092800-a67a23e1c1af/go.mod h1:+cyI34gQWZcE1eQU7NVgKkkzdXDQHr1dBMtdAPozLkw= -github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0= github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE= @@ -492,14 +470,12 @@ github.com/mailru/easyjson v0.7.1 h1:mdxE1MF9o53iCb2Ghj1VfWvh7ZOwHpnVG/xwXrV90U8 github.com/mailru/easyjson v0.7.1/go.mod h1:KAzv3t3aY1NaHWoQz1+4F1ccyAH66Jk7yos7ldAVICs= github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE= github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0= -github.com/mattn/go-colorable v0.1.6 h1:6Su7aK7lXmJ/U79bYtBjLNaha4Fs1Rg9plHpcH+vvnE= github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= github.com/mattn/go-ieproxy v0.0.0-20191113090002-7c0f6868bffe/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-oci8 v0.0.7/go.mod h1:wjDx6Xm9q7dFtHJvIlrI99JytznLw5wQ4R+9mNXJwGI= github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-shellwords v1.0.5/go.mod h1:3xCvwCdWdlDJUrvuMn7Wuy9eWs4pE8vqg+NOMyg4B2o= -github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= github.com/mattn/go-xmlrpc v0.0.3/go.mod h1:mqc2dz7tP5x5BKlCahN/n+hs7OSZKJkS9JsHNBRlrxA= @@ -518,6 +494,7 @@ github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFW github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/hashstructure v0.0.0-20170609045927-2bca23e0e452/go.mod h1:QjSHrPWS+BGUVBYkbTZWEnOh3G1DutKwClXU/ABz6AQ= github.com/mitchellh/mapstructure v1.2.2 h1:dxe5oCinTXiTIcfgmZecdCzPmAJKd46KsCWc35r0TV4= @@ -529,7 +506,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= -github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c h1:nXxl5PrvVm2L/wCy8dQu6DMTwH4oIuGN8GJDAlqDdVE= github.com/morikuni/aec v0.0.0-20170113033406-39771216ff4c/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/mozillazg/go-cos v0.13.0/go.mod h1:Zp6DvvXn0RUOXGJ2chmWt2bLEqRAnJnS3DnAZsJsoaE= github.com/mozillazg/go-httpheader v0.2.1/go.mod h1:jJ8xECTlalr6ValeXYdOF8fFUISeBAdw6E61aqQma60= @@ -560,8 +536,8 @@ github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1y github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/open-policy-agent/opa v0.18.0 h1:EC81mO3/517Kq5brJHydqKE5MLzJ+4cdJvUQKxLzHy8= github.com/open-policy-agent/opa v0.18.0/go.mod h1:6pC1cMYDI92i9EY/GoA2m+HcZlcCrh3jbfny5F7JVTA= -github.com/opencontainers/go-digest v1.0.0-rc1 h1:WzifXhOVOEOuFYOJAW6aQqW0TooG2iki3E3Ii+WN7gQ= -github.com/opencontainers/go-digest v1.0.0-rc1/go.mod h1:cMLVZDEM3+U2I4VmLI6N8jQYUd2OVphdqWwCJHrFt2s= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1 h1:JMemWkRwHx4Zj+fVxWoMCFm/8sYGGrUVojFA6h/TRcI= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= github.com/opencontainers/runc v0.1.1 h1:GlxAyO6x8rfZYN9Tt0Kti5a/cP41iuiO2yYT0IJGY8Y= @@ -585,6 +561,7 @@ github.com/pelletier/go-buffruneio v0.2.0/go.mod h1:JkE26KsDizTr40EUHkXVtNPvgGtb github.com/pelletier/go-toml v1.7.0 h1:7utD74fnzVc/cpcyy8sjrlFr5vYpypUixARcHIMIGuI= github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE= github.com/performancecopilot/speed v3.0.0+incompatible/go.mod h1:/CLtqpZ5gBg1M9iaPbIdPPGyKcA8hKdoy6hAWba7Yac= +github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI= github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU= github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= github.com/phayes/freeport v0.0.0-20171002181615-b8543db493a5/go.mod h1:iIss55rKnNBTvrwdmkUpLnDpZoAHvWaiq5+iMmen4AE= @@ -599,11 +576,8 @@ github.com/posener/complete v1.1.1/go.mod h1:em0nMJCgc9GFtwrmVmEMR/ZL6WyhyjMBndr github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021 h1:0XM1XL/OFFJjXsYXlG30spTkV/E9+gmd5GD1w2HE8xM= github.com/pquerna/cachecontrol v0.0.0-20171018203845-0dec1b30a021/go.mod h1:prYjPmNq4d1NPVmpShWobRqXY3q7Vp+80DqgxxUrUIA= github.com/pquerna/ffjson v0.0.0-20190813045741-dac163c6c0a9/go.mod h1:YARuvh7BUWHNhzDq2OM5tzR2RiCcN2D7sapiKyCel/M= -github.com/projectcalico/go-json v0.0.0-20161128004156-6219dc7339ba h1:aaF2byUCZhzszHsfPEr2M3qcU4ibtD/yk/il2R7T1PU= github.com/projectcalico/go-json v0.0.0-20161128004156-6219dc7339ba/go.mod h1:q8EdCgBdMQzgiX/uk4GXLWLk+gIHd1a7mWUAamJKDb4= -github.com/projectcalico/go-yaml v0.0.0-20161201183616-955bc3e451ef h1:Di9BaA9apb6DEstin8RdhKmlzQG76UMbmjPzjCVkMpc= github.com/projectcalico/go-yaml v0.0.0-20161201183616-955bc3e451ef/go.mod h1:1Ra2BftSa7Go38Gbq1q0bfmBFSSgUv+Cdc3SY8IL/C0= -github.com/projectcalico/go-yaml-wrapper v0.0.0-20161127220527-598e54215bee h1:yVWsNSlAuYoJ0CznHsYRPiFgsotoj07k00k5rQvGlHM= github.com/projectcalico/go-yaml-wrapper v0.0.0-20161127220527-598e54215bee/go.mod h1:UgC0aTQ2KMDxlX3lU/stndk7DMUBJqzN40yFiILHgxc= github.com/projectcalico/kube-controllers v3.8.8+incompatible h1:ZbCg0wJ+gd7i81CB6vOASiUN//oR4ZBl+wEdy0Vk1uI= github.com/projectcalico/kube-controllers v3.8.8+incompatible/go.mod h1:ZEafKeKN5wiNARRw1LZP8l10uEfp04C7redU848MMZw= @@ -637,6 +611,8 @@ github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6So github.com/rogpeppe/go-charset v0.0.0-20180617210344-2471d30d28b4/go.mod h1:qgYeAmZ5ZIpBWTGllZSQnw97Dj+woV0toclVaRGI8pc= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rs/cors v1.6.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/rubenv/sql-migrate v0.0.0-20200616145509-8d140a17f351/go.mod h1:DCgfY80j8GYL7MLEfvcpSFvjD0L5yZq/aZUJmhZklyg= +github.com/russross/blackfriday v1.5.2 h1:HyvC0ARfnZBqnXwABFeSZHpKvJHJJfPz81GNueLj0oo= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/samuel/go-zookeeper v0.0.0-20190923202752-2cc03de413da/go.mod h1:gi+0XIa01GRL2eRQVjQkKGqKF3SF9vZR/HnPullcV2E= @@ -658,13 +634,11 @@ github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4 github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= -github.com/soheilhy/cmux v0.1.4 h1:0HKaf1o97UwFjHH9o5XsHUOF+tqmdA7KEzXLpiyaw0E= github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/sony/sonyflake v0.0.0-20181109022403-6d5bd6181009 h1:3wBL/e/qjpSYaXacpbIV+Bsj/nwQ4UO1llG/av54zzw= github.com/sony/sonyflake v0.0.0-20181109022403-6d5bd6181009/go.mod h1:dVvZuWJd174umvm5g8CmZD6S2GWwHKtpK/0ZPHswuNo= github.com/soundcloud/go-runit v0.0.0-20150630195641-06ad41a06c4a/go.mod h1:LeFCbQYJ3KJlPs/FvPz2dy1tkpxyeNESVyCNNzRXFR0= -github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72 h1:qLC7fQah7D6K1B0ujays3HV9gkFtllcxhzImRR7ArPQ= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/speps/go-hashids v2.0.0+incompatible h1:kSfxGfESueJKTx0mpER9Y/1XHl+FVQjtCqRyYcviFbw= github.com/speps/go-hashids v2.0.0+incompatible/go.mod h1:P7hqPzMdnZOfyIk+xrlG1QaSMw+gCBdHKsBDnhpaZvc= @@ -685,13 +659,10 @@ github.com/src-d/gcfg v1.4.0/go.mod h1:p/UMsR43ujA89BJY9duynAwIpvqEujIH/jFlfL7jW github.com/streadway/amqp v0.0.0-20190827072141-edfb9018d271/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw= github.com/streadway/handy v0.0.0-20190108123426-d5acb3125c2a/go.mod h1:qNTQ5P5JnDBl6z3cMAg/SywNDC5ABu5ApDIw6lUbRmI= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/thanos-io/thanos v0.13.1-0.20200910143741-e0b7f7b32e9c/go.mod h1:1IzeMKiS+pvxbG2M6ZJyi8ZHaAQKXNjDbP2gjhPbSXE= -github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tinylib/msgp v1.1.0/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= -github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5 h1:LnC5Kc/wtumK+WB441p7ynQJzVuNRJiqddSIE3IlSEQ= github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/tv42/httpunix v0.0.0-20150427012821-b75d8614f926/go.mod h1:9ESjWnEqriFuLhtthL60Sar/7RFoluCcXsuvEwTV5KM= github.com/uber/jaeger-client-go v2.23.0+incompatible h1:o2g11IUBdEsSZVzF3k7+bahLmxRP/dbOoW4zQ30UlKE= @@ -714,7 +685,6 @@ github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2 github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= github.com/xenolf/lego v0.3.2-0.20160613233155-a9d8cec0e656/go.mod h1:fwiGnfsIjG7OHPfOvgK7Y/Qo6+2Ox0iozjNTkZICKbY= -github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xlab/handysort v0.0.0-20150421192137-fb3537ed64a1/go.mod h1:QcJo0QPSfTONNIgpN5RA8prR7fF8nkF6cTWTcNerRO8= github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= @@ -724,12 +694,12 @@ github.com/yashtewari/glob-intersection v0.0.0-20180916065949-5c77d914dd0b/go.mo github.com/yvasiyarov/go-metrics v0.0.0-20150112132944-c25f46c4b940/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs= github.com/yvasiyarov/gorelic v0.0.6/go.mod h1:NUSPSUX/bi6SeDMUh6brw0nXpxHnc96TguQh0+r/ssA= github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f/go.mod h1:GlGEuHIJweS1mbCqG+7vt2nvWLzLLnRHbXz5JKd/Qbg= +github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= gitlab.com/nyarla/go-crypt v0.0.0-20160106005555-d9a5dc2b789b/go.mod h1:T3BPAOm2cqquPa0MKWeNkmOM5RQsRhkrwMWonFMN7fE= go.elastic.co/apm v1.5.0/go.mod h1:OdB9sPtM6Vt7oz3VXt7+KR96i9li74qrxBGHTQygFvk= go.elastic.co/apm/module/apmhttp v1.5.0/go.mod h1:1FbmNuyD3ddauwzgVwFB0fqY6KbZt3JkV187tGCYYhY= go.elastic.co/apm/module/apmot v1.5.0/go.mod h1:d2KYwhJParTpyw2WnTNy8geNlHKKFX+4oK3YLlsesWE= go.elastic.co/fastjson v1.0.0/go.mod h1:PmeUOMMtLHQr9ZS9J9owrAVg0FkaZDRZJEFTTGHtchs= -go.etcd.io/bbolt v1.3.3 h1:MUGmc65QhB3pIlaQ5bB4LwqSj6GIonVJXpZiaKNyaKk= go.etcd.io/bbolt v1.3.3/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738 h1:VcrIfasaLFkyjk6KNlXQSzO+B0fZcnECiDrKJsfxka0= go.etcd.io/etcd v0.0.0-20191023171146-3cf2f69b5738/go.mod h1:dnLIgRNXwCJa5e+c6mIZCrds/GIG4ncV9HhK5PX7jPg= @@ -742,15 +712,13 @@ go.uber.org/automaxprocs v1.2.0/go.mod h1:YfO3fm683kQpzETxlTGZhGIVmXAhaw3gxeBADb go.uber.org/goleak v1.1.0/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= go.uber.org/multierr v1.3.0 h1:sFPn2GLc3poCkfrpIXGhBD2X0CMIo4Q/zSULXrj/+uc= go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee h1:0mgffUl7nfd+FpvXMVz4IDEaUSmT1ysygQC7qYo7sG4= go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= go.uber.org/zap v1.13.0 h1:nR6NoDBgAf67s68NhaXbsojM+2gxp3S1hWkHDl27pVU= go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 h1:VklqNMn3ovrHsnt90PveolxSbWFaJdECFbxSq0Mqo2M= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f h1:hX65Cu3JDlGH3uEdK7I99Ii+9kjD6mvnnpfLdEAH0x4= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190620200207-3b0461eec859 h1:R/3boaszxrf1GEUWTVDzSKVwLmSJpwZ1yqXm8j0v2QI= @@ -765,7 +733,6 @@ golang.org/x/text v0.3.0 h1:g61tztE5qeGQ89tm6NTjjM9VPIm088od1l6aSorWRWg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4 h1:SvFZT6jyqRaOeXpc5h/JSfZenJ2O330aBsf7JfSUXmQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20190710153321-831012c29e42 h1:4IOeC7p+OItq3+O5BWkcmVu2uBe3jekXau5S4QZX9DU= golang.org/x/tools v0.0.0-20190710153321-831012c29e42/go.mod h1:jcCCGcm9btYwXyDqrUWc6MKQKKGJCWEQ3AfLSRIbEuI= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7 h1:9zdDQZ7Thm29KFXgAX/+yaf3eVbP7djjWp/dXAppNCc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -775,7 +742,6 @@ gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE= -google.golang.org/appengine v1.6.6 h1:lMO5rYAqUxkmaj76jAkRUvt5JZgFymx/+Q5Mzfivuhc= google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/genproto v0.0.0-20200420144010-e5e8543f8aeb h1:nAFaltAMbNVA0rixtwvdnqgSVLX3HFUUvMkEklmzbYM= google.golang.org/genproto v0.0.0-20200420144010-e5e8543f8aeb/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= @@ -803,6 +769,7 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8 gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/go-playground/validator.v9 v9.27.0/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ= gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df/go.mod h1:LRQQ+SO6ZHR7tOkpBDuZnXENFzX8qRjMDMyPD6BRkCw= +gopkg.in/gorp.v1 v1.7.2/go.mod h1:Wo3h+DBQZIxATwftsglhdD/62zRFPhGhTiu5jUJmCaw= gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc= gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw= gopkg.in/ini.v1 v1.57.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= @@ -814,7 +781,6 @@ gopkg.in/square/go-jose.v2 v2.4.0 h1:0kXPskUMGAXXWJlP05ktEMOV0vmzFQUWw6d+aZJQU8A gopkg.in/square/go-jose.v2 v2.4.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= gopkg.in/src-d/go-billy.v4 v4.3.0 h1:KtlZ4c1OWbIs4jCv5ZXrTqG8EQocr0g/d4DjNg70aek= gopkg.in/src-d/go-billy.v4 v4.3.0/go.mod h1:tm33zBoOwxjYHZIE+OV8bxTWFMJLrconzFMd38aARFk= -gopkg.in/src-d/go-git-fixtures.v3 v3.1.1 h1:XWW/s5W18RaJpmo1l0IYGqXKuJITWRFuA45iOf1dKJs= gopkg.in/src-d/go-git-fixtures.v3 v3.1.1/go.mod h1:dLBcvytrw/TYZsNTWCnkNF2DSIlzWYqTe3rJR56Ac7g= gopkg.in/src-d/go-git.v4 v4.11.0 h1:cJwWgJ0DXifrNrXM6RGN1Y2yR60Rr1zQ9Q5DX5S9qgU= gopkg.in/src-d/go-git.v4 v4.11.0/go.mod h1:Vtut8izDyrM8BUVQnzJ+YvmNcem2J89EmfZYCkLokZk= @@ -827,10 +793,9 @@ gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU= gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools v2.2.0+incompatible h1:VsBPFP1AI068pPrMxtb/S8Zkgf9xEmTLJjfM+P5UIEo= gotest.tools v2.2.0+incompatible/go.mod h1:DsYFclhRJ6vuDpmuTbkuFWG+y2sxOXAzmJt81HFBacw= -helm.sh/helm/v3 v3.0.1/go.mod h1:sI7B9yfvMgxtTPMWdk1jSKJ2aa59UyP9qhPydqW6mgo= -honnef.co/go/tools v0.0.1-2020.1.3 h1:sXmLre5bzIR6ypkjXCDI3jHPssRhc8KD/Ome589sc3U= +helm.sh/helm/v3 v3.3.0 h1:7BUpW5NI1pauKDnIh0ju53pNc3Ra/UyqqBr0b5OgBwY= +helm.sh/helm/v3 v3.3.0/go.mod h1:cWRDbGk4EiIL0/+jN0GI8T7m96Cps81/ta1kcacl85g= honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k= howett.net/plist v0.0.0-20181124034731-591f970eefbb/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= istio.io/api v0.0.0-20201113182140-d4b7e3fc2b44 h1:mfs4UJtpH8ElVEohFZw39qDGv9gg7TOkYVTwJZGQ5Yc= @@ -851,11 +816,9 @@ k8s.io/cli-runtime v0.18.6 h1:I8BkH5NyqMQ4zqUBmpXJ1LxIqpCH88H/1edPkPVWzjQ= k8s.io/cli-runtime v0.18.6/go.mod h1:+G/WTNqHgUv636e5y7rhOQ7epUbRXnwmPnhOhD6t9uM= k8s.io/client-go v0.18.6 h1:I+oWqJbibLSGsZj8Xs8F0aWVXJVIoUHWaaJV3kUN/Zw= k8s.io/client-go v0.18.6/go.mod h1:/fwtGLjYMS1MaM5oi+eXhKwG+1UHidUEXRh6cNsdO0Q= -k8s.io/code-generator v0.18.6 h1:QdfvGfs4gUCS1dru+rLbCKIFxYEV0IRfF8MXwY/ozLk= k8s.io/code-generator v0.18.6/go.mod h1:TgNEVx9hCyPGpdtCWA34olQYLkh3ok9ar7XfSsr8b6c= k8s.io/component-base v0.18.6 h1:Wd6cHGwJN2qpufnirVOB3oMhyhbioGsKEi5HeDBsV+s= k8s.io/component-base v0.18.6/go.mod h1:knSVsibPR5K6EW2XOjEHik6sdU5nCvKMrzMt2D4In14= -k8s.io/gengo v0.0.0-20200114144118-36b2048a9120 h1:RPscN6KhmG54S33L+lr3GS+oD1jmchIU0ll519K6FA4= k8s.io/gengo v0.0.0-20200114144118-36b2048a9120/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0= k8s.io/klog v1.0.0 h1:Pt+yjF5aB1xDSVbau4VsWe+dQNzA0qv1LlXdC2dF6Q8= k8s.io/klog v1.0.0/go.mod h1:4Bi6QPql/J/LkTDqv7R/cd3hPo4k2DG6Ptcz060Ez5I= @@ -869,9 +832,7 @@ k8s.io/metrics v0.18.6 h1:IRMCn0KKNhbOSnxNZ+MhooRi8c67iIMjpGkKpm6oqOM= k8s.io/metrics v0.18.6/go.mod h1:iAwGeabusQNO3duHDM7BBExTUB8L+iq8PM7N9EtQw6g= k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 h1:v8ud2Up6QK1lNOKFgiIVrZdMg7MpmSnvtrOieolJKoE= k8s.io/utils v0.0.0-20200603063816-c1c6865ac451/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA= -kubesphere.io/im v0.1.0 h1:Isu/WBOawUb4fzSlQeD1f6Vbq9pqFS0PmDg8v8iFYaY= kubesphere.io/im v0.1.0/go.mod h1:DHJj/JngMUFyaXecLjBPXj/zk5Oi7ifIixLRp0qJkyA= -openpitrix.io/iam v0.1.0 h1:cb1mCusim7EGeoXEfuaVa1m7Co/pzim3keoxxKdv944= openpitrix.io/iam v0.1.0/go.mod h1:EcZE8CPBg+1fEKCDEhpsIZ8isWWO7javpu84mSqoVn4= openpitrix.io/libqueue v0.4.1/go.mod h1:qUuS2viIR86Fm1rLfLRFMMAyltUeGxNt8zoCNkmf/Gk= openpitrix.io/logger v0.1.0/go.mod h1:SV8Btt2cTSmeL9H/1XCkYmQ+WQ2upVY4e0wlr07RP28= @@ -890,11 +851,11 @@ sigs.k8s.io/application v0.8.4-0.20201016185654-c8e2959e57a0 h1:cH3Q4uNycL9Lgzly sigs.k8s.io/application v0.8.4-0.20201016185654-c8e2959e57a0/go.mod h1:wdTrELsIgKk8lnlRaoKWao9YpLelXpABdEgCM1aEEE4= sigs.k8s.io/controller-runtime v0.6.4 h1:4013CKsBs5bEqo+LevzDett+LLxag/FjQWG94nVZ/9g= sigs.k8s.io/controller-runtime v0.6.4/go.mod h1:WlZNXcM0++oyaQt4B7C2lEE5JYRs8vJUzRP4N4JpdAY= -sigs.k8s.io/controller-tools v0.4.0 h1:9zIdrc6q9RKke8+DnVPVBVZ+cfF9L0TwM01cxNnklYo= sigs.k8s.io/controller-tools v0.4.0/go.mod h1:G9rHdZMVlBDocIxGkK3jHLWqcTMNvveypYJwrvYKjWU= sigs.k8s.io/kind v0.8.1/go.mod h1:oNKTxUVPYkV9lWzY6CVMNluVq8cBsyq+UgPJdvA3uu4= sigs.k8s.io/kubefed v0.4.0 h1:eNZ5SpblUBQEzPHs8XtAjEwmkbs498IhrGvqzdynHOY= sigs.k8s.io/kubefed v0.4.0/go.mod h1:YBq2sF7Usjfh1xmop6E7k+5USBYfhB5IMLitCoOnOkM= +sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0= sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU= sigs.k8s.io/structured-merge-diff/v3 v3.0.0 h1:dOmIZBMfhcHS09XZkMyUgkq5trg3/jRyJYFZUiaOp8E= sigs.k8s.io/structured-merge-diff/v3 v3.0.0/go.mod h1:PlARxl6Hbt/+BC80dRLi1qAmnMqwqDg62YvvVkZjemw= diff --git a/hack/generate_client.sh b/hack/generate_client.sh index fced9d97076eeaa989aa8a32b95b6b84764cc35e..9fc15dc03037fe8acff196d8be8bc016ca65bc82 100755 --- a/hack/generate_client.sh +++ b/hack/generate_client.sh @@ -2,7 +2,8 @@ set -e -GV="network:v1alpha1 servicemesh:v1alpha2 tenant:v1alpha1 tenant:v1alpha2 devops:v1alpha1 iam:v1alpha2 devops:v1alpha3 cluster:v1alpha1 storage:v1alpha1 auditing:v1alpha1 types:v1beta1 quota:v1alpha2" + +GV="network:v1alpha1 servicemesh:v1alpha2 tenant:v1alpha1 tenant:v1alpha2 devops:v1alpha1 iam:v1alpha2 devops:v1alpha3 cluster:v1alpha1 storage:v1alpha1 auditing:v1alpha1 types:v1beta1 quota:v1alpha2 application:v1alpha1" rm -rf ./pkg/client ./hack/generate_group.sh "client,lister,informer" kubesphere.io/kubesphere/pkg/client kubesphere.io/kubesphere/pkg/apis "$GV" --output-base=./ -h "$PWD/hack/boilerplate.go.txt" diff --git a/pkg/apis/addtoscheme_application_v1alpha1.go b/pkg/apis/addtoscheme_application_v1alpha1.go new file mode 100644 index 0000000000000000000000000000000000000000..b0f457193748b5a0b29ec06e401fb4250e5a6ed1 --- /dev/null +++ b/pkg/apis/addtoscheme_application_v1alpha1.go @@ -0,0 +1,25 @@ +/* +Copyright 2019 The KubeSphere 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 apis + +import ( + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" +) + +func init() { + AddToSchemes = append(AddToSchemes, v1alpha1.SchemeBuilder.AddToScheme) +} diff --git a/pkg/apis/application/crdinstall/install.go b/pkg/apis/application/crdinstall/install.go new file mode 100644 index 0000000000000000000000000000000000000000..e8e975884d0d325abfd44edae50f90a658f35b88 --- /dev/null +++ b/pkg/apis/application/crdinstall/install.go @@ -0,0 +1,28 @@ +/* +Copyright 2020 KubeSphere 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 crdinstall + +import ( + k8sruntime "k8s.io/apimachinery/pkg/runtime" + urlruntime "k8s.io/apimachinery/pkg/util/runtime" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" +) + +func Install(scheme *k8sruntime.Scheme) { + urlruntime.Must(v1alpha1.AddToScheme(scheme)) + urlruntime.Must(scheme.SetVersionPriority(v1alpha1.SchemeGroupVersion)) +} diff --git a/pkg/apis/application/group.go b/pkg/apis/application/group.go new file mode 100644 index 0000000000000000000000000000000000000000..dced0f55a5bd4b6e3a9e6c93b0aa6c1223e1f2e6 --- /dev/null +++ b/pkg/apis/application/group.go @@ -0,0 +1,17 @@ +/* +Copyright 2020 The KubeSphere 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 application diff --git a/pkg/apis/application/v1alpha1/constants.go b/pkg/apis/application/v1alpha1/constants.go new file mode 100644 index 0000000000000000000000000000000000000000..816e2e149506967e685582f026a136c945a146e7 --- /dev/null +++ b/pkg/apis/application/v1alpha1/constants.go @@ -0,0 +1,61 @@ +/* +Copyright 2020 The KubeSphere 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 v1alpha1 + +const ( + MsgLen = 512 + HelmRepoSyncStateLen = 10 + + // app version state + StateDraft = "draft" + StateSubmitted = "submitted" + StatePassed = "passed" + StateRejected = "rejected" + StateSuspended = "suspended" + StateActive = "active" + + // repo state + RepoStateSuccessful = "successful" + RepoStateFailed = "failed" + RepoStateSyncing = "syncing" + + // helm release state + HelmStatusActive = "active" + HelmStatusCreating = "creating" + HelmStatusDeleting = "deleting" + HelmStatusUpgrading = "upgrading" + HelmStatusRollbacking = "rollbacking" + HelmStatusPending = "pending" + HelmStatusSuccessful = "successful" + HelmStatusFailed = "failed" + + AttachmentTypeScreenshot = "screenshot" + AttachmentTypeIcon = "icon" + + HelmApplicationAppStoreSuffix = "-store" + HelmApplicationIdPrefix = "app-" + HelmRepoIdPrefix = "repo-" + HelmApplicationVersionIdPrefix = "appv-" + HelmCategoryIdPrefix = "ctg-" + HelmAttachmentPrefix = "att-" + HelmReleasePrefix = "rls-" + UncategorizedName = "uncategorized" + UncategorizedId = "ctg-uncategorized" + AppStoreRepoId = "repo-helm" + + OriginWorkspaceLabelKey = "kubesphere.io/workspace-origin" +) diff --git a/pkg/apis/application/v1alpha1/doc.go b/pkg/apis/application/v1alpha1/doc.go new file mode 100644 index 0000000000000000000000000000000000000000..745b9bf45d4e04ac5954be3618a381fb2592475c --- /dev/null +++ b/pkg/apis/application/v1alpha1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// +k8s:deepcopy-gen=package,register +// +groupName=application.kubesphere.io + +package v1alpha1 diff --git a/pkg/apis/application/v1alpha1/helmapplication_types.go b/pkg/apis/application/v1alpha1/helmapplication_types.go new file mode 100644 index 0000000000000000000000000000000000000000..93fea801c7fb85960f371e4943382bf90f532d76 --- /dev/null +++ b/pkg/apis/application/v1alpha1/helmapplication_types.go @@ -0,0 +1,128 @@ +/* +Copyright 2020 The KubeSphere 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 v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "kubesphere.io/kubesphere/pkg/constants" + "strings" +) + +const ( + ResourceKindHelmApplication = "HelmApplication" + ResourceSingularHelmApplication = "helmapplication" + ResourcePluralHelmApplication = "helmapplications" +) + +// HelmApplicationSpec defines the desired state of HelmApplication +type HelmApplicationSpec struct { + // the name of the helm application + Name string `json:"name"` + // description from chart's description or frontend + Description string `json:"description,omitempty"` + // attachments id + Attachments []string `json:"attachments,omitempty"` + // info from frontend + Abstraction string `json:"abstraction,omitempty"` + AppHome string `json:"appHome,omitempty"` + // The attachment id of the icon + Icon string `json:"icon,omitempty"` +} + +// HelmApplicationStatus defines the observed state of HelmApplication +type HelmApplicationStatus struct { + // If this application belong to appStore, latestVersion is the the latest version of the active application version. + // otherwise latestVersion is the latest version of all application version + LatestVersion string `json:"latestVersion,omitempty"` + // the state of the helm application: draft, submitted, passed, rejected, suspended, active + State string `json:"state,omitempty"` + UpdateTime *metav1.Time `json:"updateTime"` + StatusTime *metav1.Time `json:"statusTime"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster,shortName=happ +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="application name",type=string,JSONPath=`.spec.name` +// +kubebuilder:printcolumn:name="workspace",type="string",JSONPath=".metadata.labels.kubesphere\\.io/workspace" +// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".status.state" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" +// +genclient +// +genclient:nonNamespaced + +// HelmApplication is the Schema for the helmapplications API +type HelmApplication struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec HelmApplicationSpec `json:"spec,omitempty"` + Status HelmApplicationStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// HelmApplicationList contains a list of HelmApplication +type HelmApplicationList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []HelmApplication `json:"items"` +} + +func init() { + SchemeBuilder.Register(&HelmApplication{}, &HelmApplicationList{}) +} + +func (in *HelmApplication) GetTrueName() string { + return in.Spec.Name +} + +func (in *HelmApplication) GetHelmRepoId() string { + return getValue(in.Labels, constants.ChartRepoIdLabelKey) +} + +func (in *HelmApplication) GetHelmApplicationId() string { + return strings.TrimSuffix(in.Name, HelmApplicationAppStoreSuffix) +} +func (in *HelmApplication) GetHelmCategoryId() string { + return getValue(in.Labels, constants.CategoryIdLabelKey) +} + +func (in *HelmApplication) GetWorkspace() string { + ws := getValue(in.Labels, constants.WorkspaceLabelKey) + if ws == "" { + return getValue(in.Labels, OriginWorkspaceLabelKey) + } + return ws +} + +func getValue(m map[string]string, key string) string { + if m == nil { + return "" + } + return m[key] +} + +func (in *HelmApplication) GetCategoryId() string { + return getValue(in.Labels, constants.CategoryIdLabelKey) +} + +func (in *HelmApplication) State() string { + if in.Status.State == "" { + return StateDraft + } + return in.Status.State +} diff --git a/pkg/apis/application/v1alpha1/helmapplicationversion_types.go b/pkg/apis/application/v1alpha1/helmapplicationversion_types.go new file mode 100644 index 0000000000000000000000000000000000000000..b908ba319accbd3254b40b87a248757981fe1c9a --- /dev/null +++ b/pkg/apis/application/v1alpha1/helmapplicationversion_types.go @@ -0,0 +1,229 @@ +/* +Copyright 2020 The KubeSphere 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 v1alpha1 + +import ( + "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "kubesphere.io/kubesphere/pkg/constants" + "strings" +) + +const ( + ResourceKindHelmApplicationVersion = "HelmApplicationVersion" + ResourceSingularHelmApplicationVersion = "helmapplicationversion" + ResourcePluralHelmApplicationVersion = "helmapplicationversions" +) + +// HelmApplicationVersionSpec defines the desired state of HelmApplicationVersion +type HelmApplicationVersionSpec struct { + // metadata from chart + *Metadata `json:",inline"` + // chart url + URLs []string `json:"urls,omitempty"` + // raw data of chart, it will !!!NOT!!! be save to etcd + Data []byte `json:"data,omitempty"` + + // dataKey in the storage + DataKey string `json:"dataKey,omitempty"` + + // chart create time + Created *metav1.Time `json:"created,omitempty"` + + // chart digest + Digest string `json:"digest,omitempty"` +} + +// HelmApplicationVersionStatus defines the observed state of HelmApplicationVersion +type HelmApplicationVersionStatus struct { + State string `json:"state,omitempty"` + Audit []Audit `json:"audit,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster,shortName=happver +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="application name",type=string,JSONPath=`.spec.name` +// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".status.state" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" +// +genclient +// +genclient:nonNamespaced + +// HelmApplicationVersion is the Schema for the helmapplicationversions API +type HelmApplicationVersion struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec HelmApplicationVersionSpec `json:"spec,omitempty"` + Status HelmApplicationVersionStatus `json:"status,omitempty"` +} + +// Maintainer describes a Chart maintainer. +type Maintainer struct { + // Name is a user name or organization name + Name string `json:"name,omitempty"` + // Email is an optional email address to contact the named maintainer + Email string `json:"email,omitempty"` + // URL is an optional URL to an address for the named maintainer + URL string `json:"url,omitempty"` +} + +// Metadata for a Chart file. This models the structure of a Chart.yaml file. +type Metadata struct { + // The name of the chart + Name string `json:"name,omitempty"` + // The URL to a relevant project page, git repo, or contact person + Home string `json:"home,omitempty"` + // Source is the URL to the source code of this chart + Sources []string `json:"sources,omitempty"` + // A SemVer 2 conformant version string of the chart + Version string `json:"version,omitempty"` + // A one-sentence description of the chart + Description string `json:"description,omitempty"` + // A list of string keywords + Keywords []string `json:"keywords,omitempty"` + // A list of name and URL/email address combinations for the maintainer(s) + Maintainers []*Maintainer `json:"maintainers,omitempty"` + // The URL to an icon file. + Icon string `json:"icon,omitempty"` + // The API Version of this chart. + APIVersion string `json:"apiVersion,omitempty"` + // The condition to check to enable chart + Condition string `json:"condition,omitempty"` + // The tags to check to enable chart + Tags string `json:"tags,omitempty"` + // The version of the application enclosed inside of this chart. + AppVersion string `json:"appVersion,omitempty"` + // Whether or not this chart is deprecated + Deprecated bool `json:"deprecated,omitempty"` + // Annotations are additional mappings uninterpreted by Helm, + // made available for inspection by other applications. + Annotations map[string]string `json:"annotations,omitempty"` + // KubeVersion is a SemVer constraint specifying the version of Kubernetes required. + KubeVersion string `json:"kubeVersion,omitempty"` + // Dependencies are a list of dependencies for a chart. + Dependencies []*Dependency `json:"dependencies,omitempty"` + // Specifies the chart type: application or library + Type string `json:"type,omitempty"` +} + +type Audit struct { + // audit message + Message string `json:"message,omitempty"` + // audit state: submitted, passed, draft, active, rejected, suspended + State string `json:"state,omitempty"` + // audit time + Time metav1.Time `json:"time"` + // audit operator + Operator string `json:"operator,omitempty"` + OperatorType string `json:"operatorType,omitempty"` +} + +// Dependency describes a chart upon which another chart depends. +// Dependencies can be used to express developer intent, or to capture the state +// of a chart. +type Dependency struct { + // Name is the name of the dependency. + // This must mach the name in the dependency's Chart.yaml. + Name string `json:"name"` + // Version is the version (range) of this chart. + // A lock file will always produce a single version, while a dependency + // may contain a semantic version range. + Version string `json:"version,omitempty"` + // The URL to the repository. + // Appending `index.yaml` to this string should result in a URL that can be + // used to fetch the repository index. + Repository string `json:"repository"` + // A yaml path that resolves to a boolean, used for enabling/disabling charts (e.g. subchart1.enabled ) + Condition string `json:"condition,omitempty"` + // Tags can be used to group charts for enabling/disabling together + Tags []string `json:"tags,omitempty"` + // Enabled bool determines if chart should be loaded + Enabled bool `json:"enabled,omitempty"` + // ImportValues holds the mapping of source values to parent key to be imported. Each item can be a + // string or pair of child/parent sublist items. + // ImportValues []interface{} `json:"import_values,omitempty"` + + // Alias usable alias to be used for the chart + Alias string `json:"alias,omitempty"` +} + +// +kubebuilder:object:root=true + +// HelmApplicationVersionList contains a list of HelmApplicationVersion +type HelmApplicationVersionList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []HelmApplicationVersion `json:"items"` +} + +func init() { + SchemeBuilder.Register(&HelmApplicationVersion{}, &HelmApplicationVersionList{}) +} + +func (in *HelmApplicationVersion) GetCreator() string { + return getValue(in.Annotations, constants.CreatorAnnotationKey) +} + +func (in *HelmApplicationVersion) GetHelmApplicationVersionId() string { + return in.Name +} + +func (in *HelmApplicationVersion) GetWorkspace() string { + return getValue(in.Labels, constants.WorkspaceLabelKey) +} + +func (in *HelmApplicationVersion) GetVersionName() string { + appV := in.GetChartAppVersion() + if appV != "" { + return fmt.Sprintf("%s [%s]", in.GetChartVersion(), appV) + } else { + return in.GetChartVersion() + } +} + +func (in *HelmApplicationVersion) GetHelmApplicationId() string { + return getValue(in.Labels, constants.ChartApplicationIdLabelKey) +} + +func (in *HelmApplicationVersion) GetSemver() string { + return strings.Split(in.GetVersionName(), " ")[0] +} + +func (in *HelmApplicationVersion) GetTrueName() string { + return in.Spec.Name +} + +func (in *HelmApplicationVersion) GetChartVersion() string { + return in.Spec.Version +} + +func (in *HelmApplicationVersion) GetChartAppVersion() string { + return in.Spec.AppVersion +} + +func (in *HelmApplicationVersion) GetHelmRepoId() string { + return getValue(in.Labels, constants.ChartRepoIdLabelKey) +} + +func (in *HelmApplicationVersion) State() string { + if in.Status.State == "" { + return StateDraft + } + + return in.Status.State +} diff --git a/pkg/apis/application/v1alpha1/helmcategory_types.go b/pkg/apis/application/v1alpha1/helmcategory_types.go new file mode 100644 index 0000000000000000000000000000000000000000..8a5e4c5e483c57021c0354e346cac80da197c85d --- /dev/null +++ b/pkg/apis/application/v1alpha1/helmcategory_types.go @@ -0,0 +1,79 @@ +/* +Copyright 2020 The KubeSphere 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 v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + ResourceKindHelmCategory = "HelmCategory" + ResourceSingularHelmCategory = "helmcategory" + ResourcePluralHelmCategory = "helmcategories" +) + +// HelmCategorySpec defines the desired state of HelmRepo +type HelmCategorySpec struct { + // name of the category + Name string `json:"name"` + // info from frontend + Description string `json:"description,omitempty"` + Locale string `json:"locale,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster,shortName=hctg +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="name",type=string,JSONPath=`.spec.name` +// +kubebuilder:printcolumn:name="total",type=string,JSONPath=`.status.total` +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" +// +genclient +// +genclient:nonNamespaced + +// HelmCategory is the Schema for the helmcategories API +type HelmCategory struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec HelmCategorySpec `json:"spec,omitempty"` + Status HelmCategoryStatus `json:"status,omitempty"` +} + +type HelmCategoryStatus struct { + // total helmapplications belong to this category + Total int `json:"total"` +} + +// +kubebuilder:object:root=true + +// HelmCategoryList contains a list of HelmCategory +type HelmCategoryList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []HelmCategory `json:"items"` +} + +func (in *HelmCategory) GetTrueName() string { + if in == nil { + return "" + } + return in.Spec.Name +} + +func init() { + SchemeBuilder.Register(&HelmCategory{}, &HelmCategoryList{}) +} diff --git a/pkg/apis/application/v1alpha1/helmrelease_types.go b/pkg/apis/application/v1alpha1/helmrelease_types.go new file mode 100644 index 0000000000000000000000000000000000000000..9bff9bdb645450bb8fd6ab78dcdd466a33c02d1b --- /dev/null +++ b/pkg/apis/application/v1alpha1/helmrelease_types.go @@ -0,0 +1,150 @@ +/* +Copyright 2020 The KubeSphere 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 v1alpha1 + +import ( + "fmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "kubesphere.io/kubesphere/pkg/constants" +) + +const ( + ResourceKindHelmRelease = "HelmRelease" + ResourceSingularHelmRelease = "helmrelease" + ResourcePluralHelmRelease = "helmreleases" +) + +// HelmReleaseSpec defines the desired state of HelmRelease +type HelmReleaseSpec struct { + // Name of the release + Name string `json:"name"` + // Message got from frontend + Description string `json:"description,omitempty"` + // helm release values.yaml + Values []byte `json:"values,omitempty"` + // The name of the chart which will be installed. + ChartName string `json:"chartName"` + // Specify the exact chart version to install. If this is not specified, the latest version is installed + ChartVersion string `json:"chartVersion"` + // appVersion from Chart.yaml + ChartAppVersion string `json:"chartAppVer,omitempty"` + // id of the repo + RepoId string `json:"repoId,omitempty"` + // id of the helmapplication + ApplicationId string `json:"appId,omitempty"` + // application version id + ApplicationVersionId string `json:"appVerId,omitempty"` + // expected release version, when this version is not equal status.version, the release need upgrade + // this filed should be modified when any filed of the spec modified. + Version int `json:"version"` +} + +type HelmReleaseDeployStatus struct { + // A human readable message indicating details about why the release is in this state. + Message string `json:"message,omitempty"` + // deploy state + State string `json:"state"` + // deploy time + Time metav1.Time `json:"deployTime"` +} + +// HelmReleaseStatus defines the observed state of HelmRelease +type HelmReleaseStatus struct { + // current state + State string `json:"state"` + // A human readable message indicating details about why the release is in this state. + Message string `json:"message,omitempty"` + // current release version + Version int `json:"version,omitempty"` + // deploy status list of history, which will store at most 10 state + DeployStatus []HelmReleaseDeployStatus `json:"deployStatus,omitempty"` + // last update time + LastUpdate metav1.Time `json:"lastUpdate,omitempty"` + // last successful deploy time + LastDeployed *metav1.Time `json:"lastDeployed,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster,shortName=hrls +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="Release Name",type=string,JSONPath=".spec.name" +// +kubebuilder:printcolumn:name="Workspace",type="string",JSONPath=".metadata.labels.kubesphere\\.io/workspace" +// +kubebuilder:printcolumn:name="Cluster",type="string",JSONPath=".metadata.labels.kubesphere\\.io/cluster" +// +kubebuilder:printcolumn:name="Namespace",type="string",JSONPath=".metadata.labels.kubesphere\\.io/namespace" +// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".status.state" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" +// +genclient +// +genclient:nonNamespaced + +// HelmRelease is the Schema for the helmreleases API +type HelmRelease struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec HelmReleaseSpec `json:"spec,omitempty"` + Status HelmReleaseStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// HelmReleaseList contains a list of HelmRelease +type HelmReleaseList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []HelmRelease `json:"items"` +} + +func init() { + SchemeBuilder.Register(&HelmRelease{}, &HelmReleaseList{}) +} + +func (in *HelmRelease) GetCreator() string { + return getValue(in.Annotations, constants.CreatorAnnotationKey) +} + +func (in *HelmRelease) GetTrueName() string { + return in.Spec.Name +} + +func (in *HelmRelease) GetChartVersionName() string { + appV := in.GetChartAppVersion() + if appV != "" { + return fmt.Sprintf("%s [%s]", in.GetChartVersion(), appV) + } else { + return in.GetChartVersion() + } +} + +func (in *HelmRelease) GetChartAppVersion() string { + return in.Spec.ChartAppVersion +} + +func (in *HelmRelease) GetChartVersion() string { + return in.Spec.ChartVersion +} + +func (in *HelmRelease) GetRlsCluster() string { + return getValue(in.Labels, constants.ClusterNameLabelKey) +} + +func (in *HelmRelease) GetWorkspace() string { + return getValue(in.Labels, constants.WorkspaceLabelKey) +} + +func (in *HelmRelease) GetRlsNamespace() string { + return getValue(in.Labels, constants.NamespaceLabelKey) +} diff --git a/pkg/apis/application/v1alpha1/helmrepo_types.go b/pkg/apis/application/v1alpha1/helmrepo_types.go new file mode 100644 index 0000000000000000000000000000000000000000..281da80eab7bc928b2bc119ba89dfd7e9cfe864c --- /dev/null +++ b/pkg/apis/application/v1alpha1/helmrepo_types.go @@ -0,0 +1,138 @@ +/* +Copyright 2020 The KubeSphere 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 v1alpha1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "kubesphere.io/kubesphere/pkg/constants" +) + +const ( + ResourceKindHelmRepo = "HelmRepo" + ResourceSingularHelmRepo = "helmrepo" + ResourcePluralHelmRepo = "helmrepos" +) + +type HelmRepoCredential struct { + // chart repository username + Username string `json:"username,omitempty"` + // chart repository password + Password string `json:"password,omitempty"` + // identify HTTPS client using this SSL certificate file + CertFile string `json:"certFile,omitempty"` + // identify HTTPS client using this SSL key file + KeyFile string `json:"keyFile,omitempty"` + // verify certificates of HTTPS-enabled servers using this CA bundle + CAFile string `json:"caFile,omitempty"` + // skip tls certificate checks for the repository, default is ture + InsecureSkipTLSVerify *bool `json:"insecureSkipTLSVerify,omitempty"` + + S3Config `json:",inline"` +} + +type S3Config struct { + AccessKeyID string `json:"accessKeyID,omitempty"` + SecretAccessKey string `json:"secretAccessKey,omitempty"` +} + +// HelmRepoSpec defines the desired state of HelmRepo +type HelmRepoSpec struct { + // name of the repo + Name string `json:"name"` + // helm repo url + Url string `json:"url"` + // helm repo credential + Credential HelmRepoCredential `json:"credential,omitempty"` + // chart repo description from frontend + Description string `json:"description,omitempty"` + // sync period in seconds, no sync when SyncPeriod=0, the minimum SyncPeriod is 180s + SyncPeriod int `json:"syncPeriod,omitempty"` + // expected repo version, when this version is not equal status.version, the repo need upgrade + // this filed should be modified when any filed of the spec modified. + Version int `json:"version,omitempty"` +} + +type HelmRepoSyncState struct { + // last sync state, valid state are: "failed", "success", and "" + State string `json:"state,omitempty"` + // A human readable message indicating details about why the repo is in this state. + Message string `json:"message,omitempty"` + SyncTime *metav1.Time `json:"syncTime"` +} + +// HelmRepoStatus defines the observed state of HelmRepo +type HelmRepoStatus struct { + // repo index + Data string `json:"data,omitempty"` + // status last update time + LastUpdateTime *metav1.Time `json:"lastUpdateTime,omitempty"` + // current state of the repo, successful, failed or syncing + State string `json:"state,omitempty"` + // sync state list of history, which will store at most 10 state + SyncState []HelmRepoSyncState `json:"syncState,omitempty"` + // if status.version!=spec.Version, we need sync the repo now + Version int `json:"version,omitempty"` +} + +// +kubebuilder:object:root=true +// +kubebuilder:resource:scope=Cluster,path=helmrepos,shortName=hrepo +// +kubebuilder:subresource:status +// +kubebuilder:printcolumn:name="name",type=string,JSONPath=`.spec.name` +// +kubebuilder:printcolumn:name="Workspace",type=string,JSONPath=`.metadata.labels.kubesphere\\.io/workspace` +// +kubebuilder:printcolumn:name="url",type=string,JSONPath=`.spec.url` +// +kubebuilder:printcolumn:name="State",type="string",JSONPath=".status.state" +// +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp" +// +genclient +// +genclient:nonNamespaced + +// HelmRepo is the Schema for the helmrepoes API +type HelmRepo struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata,omitempty"` + + Spec HelmRepoSpec `json:"spec,omitempty"` + Status HelmRepoStatus `json:"status,omitempty"` +} + +// +kubebuilder:object:root=true + +// HelmRepoList contains a list of HelmRepo +type HelmRepoList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata,omitempty"` + Items []HelmRepo `json:"items"` +} + +func init() { + SchemeBuilder.Register(&HelmRepo{}, &HelmRepoList{}) +} + +func (in *HelmRepo) GetTrueName() string { + return in.Spec.Name +} + +func (in *HelmRepo) GetHelmRepoId() string { + return in.Name +} + +func (in *HelmRepo) GetWorkspace() string { + return getValue(in.Labels, constants.WorkspaceLabelKey) +} + +func (in *HelmRepo) GetCreator() string { + return getValue(in.Annotations, constants.CreatorAnnotationKey) +} diff --git a/pkg/apis/application/v1alpha1/register.go b/pkg/apis/application/v1alpha1/register.go new file mode 100644 index 0000000000000000000000000000000000000000..7ecad99f42ad610cb91d19865ab5a5e8e2eed916 --- /dev/null +++ b/pkg/apis/application/v1alpha1/register.go @@ -0,0 +1,40 @@ +/* +Copyright 2020 The KubeSphere 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 v1alpha1 contains API Schema definitions for the application v1alpha1 API group +// +kubebuilder:object:generate=true +// +groupName=application.kubesphere.io +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/runtime/schema" + "sigs.k8s.io/controller-runtime/pkg/scheme" +) + +var ( + // SchemeGroupVersion is group version used to register these objects + SchemeGroupVersion = schema.GroupVersion{Group: "application.kubesphere.io", Version: "v1alpha1"} + + // SchemeBuilder is used to add go types to the GroupVersionKind scheme + SchemeBuilder = &scheme.Builder{GroupVersion: SchemeGroupVersion} + + // AddToScheme adds the types in this group-version to the given scheme. + AddToScheme = SchemeBuilder.AddToScheme +) + +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} diff --git a/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go new file mode 100644 index 0000000000000000000000000000000000000000..45d50e693961c040cb1b66aa00e134678d24a05c --- /dev/null +++ b/pkg/apis/application/v1alpha1/zz_generated.deepcopy.go @@ -0,0 +1,714 @@ +// +build !ignore_autogenerated + +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by controller-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Audit) DeepCopyInto(out *Audit) { + *out = *in + in.Time.DeepCopyInto(&out.Time) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Audit. +func (in *Audit) DeepCopy() *Audit { + if in == nil { + return nil + } + out := new(Audit) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Dependency) DeepCopyInto(out *Dependency) { + *out = *in + if in.Tags != nil { + in, out := &in.Tags, &out.Tags + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Dependency. +func (in *Dependency) DeepCopy() *Dependency { + if in == nil { + return nil + } + out := new(Dependency) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmApplication) DeepCopyInto(out *HelmApplication) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmApplication. +func (in *HelmApplication) DeepCopy() *HelmApplication { + if in == nil { + return nil + } + out := new(HelmApplication) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmApplication) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmApplicationList) DeepCopyInto(out *HelmApplicationList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]HelmApplication, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmApplicationList. +func (in *HelmApplicationList) DeepCopy() *HelmApplicationList { + if in == nil { + return nil + } + out := new(HelmApplicationList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmApplicationList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmApplicationSpec) DeepCopyInto(out *HelmApplicationSpec) { + *out = *in + if in.Attachments != nil { + in, out := &in.Attachments, &out.Attachments + *out = make([]string, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmApplicationSpec. +func (in *HelmApplicationSpec) DeepCopy() *HelmApplicationSpec { + if in == nil { + return nil + } + out := new(HelmApplicationSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmApplicationStatus) DeepCopyInto(out *HelmApplicationStatus) { + *out = *in + if in.UpdateTime != nil { + in, out := &in.UpdateTime, &out.UpdateTime + *out = (*in).DeepCopy() + } + if in.StatusTime != nil { + in, out := &in.StatusTime, &out.StatusTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmApplicationStatus. +func (in *HelmApplicationStatus) DeepCopy() *HelmApplicationStatus { + if in == nil { + return nil + } + out := new(HelmApplicationStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmApplicationVersion) DeepCopyInto(out *HelmApplicationVersion) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmApplicationVersion. +func (in *HelmApplicationVersion) DeepCopy() *HelmApplicationVersion { + if in == nil { + return nil + } + out := new(HelmApplicationVersion) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmApplicationVersion) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmApplicationVersionList) DeepCopyInto(out *HelmApplicationVersionList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]HelmApplicationVersion, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmApplicationVersionList. +func (in *HelmApplicationVersionList) DeepCopy() *HelmApplicationVersionList { + if in == nil { + return nil + } + out := new(HelmApplicationVersionList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmApplicationVersionList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmApplicationVersionSpec) DeepCopyInto(out *HelmApplicationVersionSpec) { + *out = *in + if in.Metadata != nil { + in, out := &in.Metadata, &out.Metadata + *out = new(Metadata) + (*in).DeepCopyInto(*out) + } + if in.URLs != nil { + in, out := &in.URLs, &out.URLs + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Data != nil { + in, out := &in.Data, &out.Data + *out = make([]byte, len(*in)) + copy(*out, *in) + } + if in.Created != nil { + in, out := &in.Created, &out.Created + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmApplicationVersionSpec. +func (in *HelmApplicationVersionSpec) DeepCopy() *HelmApplicationVersionSpec { + if in == nil { + return nil + } + out := new(HelmApplicationVersionSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmApplicationVersionStatus) DeepCopyInto(out *HelmApplicationVersionStatus) { + *out = *in + if in.Audit != nil { + in, out := &in.Audit, &out.Audit + *out = make([]Audit, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmApplicationVersionStatus. +func (in *HelmApplicationVersionStatus) DeepCopy() *HelmApplicationVersionStatus { + if in == nil { + return nil + } + out := new(HelmApplicationVersionStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmCategory) DeepCopyInto(out *HelmCategory) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + out.Status = in.Status +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmCategory. +func (in *HelmCategory) DeepCopy() *HelmCategory { + if in == nil { + return nil + } + out := new(HelmCategory) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmCategory) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmCategoryList) DeepCopyInto(out *HelmCategoryList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]HelmCategory, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmCategoryList. +func (in *HelmCategoryList) DeepCopy() *HelmCategoryList { + if in == nil { + return nil + } + out := new(HelmCategoryList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmCategoryList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmCategorySpec) DeepCopyInto(out *HelmCategorySpec) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmCategorySpec. +func (in *HelmCategorySpec) DeepCopy() *HelmCategorySpec { + if in == nil { + return nil + } + out := new(HelmCategorySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmCategoryStatus) DeepCopyInto(out *HelmCategoryStatus) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmCategoryStatus. +func (in *HelmCategoryStatus) DeepCopy() *HelmCategoryStatus { + if in == nil { + return nil + } + out := new(HelmCategoryStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmRelease) DeepCopyInto(out *HelmRelease) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmRelease. +func (in *HelmRelease) DeepCopy() *HelmRelease { + if in == nil { + return nil + } + out := new(HelmRelease) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmRelease) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmReleaseDeployStatus) DeepCopyInto(out *HelmReleaseDeployStatus) { + *out = *in + in.Time.DeepCopyInto(&out.Time) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseDeployStatus. +func (in *HelmReleaseDeployStatus) DeepCopy() *HelmReleaseDeployStatus { + if in == nil { + return nil + } + out := new(HelmReleaseDeployStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmReleaseList) DeepCopyInto(out *HelmReleaseList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]HelmRelease, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseList. +func (in *HelmReleaseList) DeepCopy() *HelmReleaseList { + if in == nil { + return nil + } + out := new(HelmReleaseList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmReleaseList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmReleaseSpec) DeepCopyInto(out *HelmReleaseSpec) { + *out = *in + if in.Values != nil { + in, out := &in.Values, &out.Values + *out = make([]byte, len(*in)) + copy(*out, *in) + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseSpec. +func (in *HelmReleaseSpec) DeepCopy() *HelmReleaseSpec { + if in == nil { + return nil + } + out := new(HelmReleaseSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmReleaseStatus) DeepCopyInto(out *HelmReleaseStatus) { + *out = *in + if in.DeployStatus != nil { + in, out := &in.DeployStatus, &out.DeployStatus + *out = make([]HelmReleaseDeployStatus, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + in.LastUpdate.DeepCopyInto(&out.LastUpdate) + if in.LastDeployed != nil { + in, out := &in.LastDeployed, &out.LastDeployed + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmReleaseStatus. +func (in *HelmReleaseStatus) DeepCopy() *HelmReleaseStatus { + if in == nil { + return nil + } + out := new(HelmReleaseStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmRepo) DeepCopyInto(out *HelmRepo) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmRepo. +func (in *HelmRepo) DeepCopy() *HelmRepo { + if in == nil { + return nil + } + out := new(HelmRepo) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmRepo) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmRepoCredential) DeepCopyInto(out *HelmRepoCredential) { + *out = *in + if in.InsecureSkipTLSVerify != nil { + in, out := &in.InsecureSkipTLSVerify, &out.InsecureSkipTLSVerify + *out = new(bool) + **out = **in + } + out.S3Config = in.S3Config +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmRepoCredential. +func (in *HelmRepoCredential) DeepCopy() *HelmRepoCredential { + if in == nil { + return nil + } + out := new(HelmRepoCredential) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmRepoList) DeepCopyInto(out *HelmRepoList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]HelmRepo, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmRepoList. +func (in *HelmRepoList) DeepCopy() *HelmRepoList { + if in == nil { + return nil + } + out := new(HelmRepoList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *HelmRepoList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmRepoSpec) DeepCopyInto(out *HelmRepoSpec) { + *out = *in + in.Credential.DeepCopyInto(&out.Credential) +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmRepoSpec. +func (in *HelmRepoSpec) DeepCopy() *HelmRepoSpec { + if in == nil { + return nil + } + out := new(HelmRepoSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmRepoStatus) DeepCopyInto(out *HelmRepoStatus) { + *out = *in + if in.LastUpdateTime != nil { + in, out := &in.LastUpdateTime, &out.LastUpdateTime + *out = (*in).DeepCopy() + } + if in.SyncState != nil { + in, out := &in.SyncState, &out.SyncState + *out = make([]HelmRepoSyncState, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmRepoStatus. +func (in *HelmRepoStatus) DeepCopy() *HelmRepoStatus { + if in == nil { + return nil + } + out := new(HelmRepoStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HelmRepoSyncState) DeepCopyInto(out *HelmRepoSyncState) { + *out = *in + if in.SyncTime != nil { + in, out := &in.SyncTime, &out.SyncTime + *out = (*in).DeepCopy() + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HelmRepoSyncState. +func (in *HelmRepoSyncState) DeepCopy() *HelmRepoSyncState { + if in == nil { + return nil + } + out := new(HelmRepoSyncState) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Maintainer) DeepCopyInto(out *Maintainer) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Maintainer. +func (in *Maintainer) DeepCopy() *Maintainer { + if in == nil { + return nil + } + out := new(Maintainer) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Metadata) DeepCopyInto(out *Metadata) { + *out = *in + if in.Sources != nil { + in, out := &in.Sources, &out.Sources + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Keywords != nil { + in, out := &in.Keywords, &out.Keywords + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.Maintainers != nil { + in, out := &in.Maintainers, &out.Maintainers + *out = make([]*Maintainer, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Maintainer) + **out = **in + } + } + } + if in.Annotations != nil { + in, out := &in.Annotations, &out.Annotations + *out = make(map[string]string, len(*in)) + for key, val := range *in { + (*out)[key] = val + } + } + if in.Dependencies != nil { + in, out := &in.Dependencies, &out.Dependencies + *out = make([]*Dependency, len(*in)) + for i := range *in { + if (*in)[i] != nil { + in, out := &(*in)[i], &(*out)[i] + *out = new(Dependency) + (*in).DeepCopyInto(*out) + } + } + } +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Metadata. +func (in *Metadata) DeepCopy() *Metadata { + if in == nil { + return nil + } + out := new(Metadata) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *S3Config) DeepCopyInto(out *S3Config) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S3Config. +func (in *S3Config) DeepCopy() *S3Config { + if in == nil { + return nil + } + out := new(S3Config) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go index 1d5b610e98d7f3247c66c4effe3936fa589fe0ea..cf99c414cc840cf05985219d5ee06c1f9174f69a 100644 --- a/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/cluster/v1alpha1/zz_generated.deepcopy.go @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by deepcopy-gen. DO NOT EDIT. +// Code generated by controller-gen. DO NOT EDIT. package v1alpha1 @@ -31,7 +31,6 @@ func (in *Cluster) DeepCopyInto(out *Cluster) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster. @@ -57,7 +56,6 @@ func (in *ClusterCondition) DeepCopyInto(out *ClusterCondition) { *out = *in in.LastUpdateTime.DeepCopyInto(&out.LastUpdateTime) in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterCondition. @@ -82,7 +80,6 @@ func (in *ClusterList) DeepCopyInto(out *ClusterList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterList. @@ -107,7 +104,6 @@ func (in *ClusterList) DeepCopyObject() runtime.Object { func (in *ClusterSpec) DeepCopyInto(out *ClusterSpec) { *out = *in in.Connection.DeepCopyInto(&out.Connection) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSpec. @@ -147,7 +143,6 @@ func (in *ClusterStatus) DeepCopyInto(out *ClusterStatus) { (*out)[key] = val } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterStatus. @@ -168,7 +163,6 @@ func (in *Connection) DeepCopyInto(out *Connection) { *out = make([]byte, len(*in)) copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Connection. diff --git a/pkg/apis/devops/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/devops/v1alpha1/zz_generated.deepcopy.go index 1def6ff44ff00013d85a87cf53ae10b25245e63c..00f90c63ff2c37ecb39b451d04e379738da20a70 100644 --- a/pkg/apis/devops/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/devops/v1alpha1/zz_generated.deepcopy.go @@ -16,12 +16,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by deepcopy-gen. DO NOT EDIT. +// Code generated by controller-gen. DO NOT EDIT. package v1alpha1 import ( - v1 "k8s.io/api/core/v1" + "k8s.io/api/core/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -33,7 +33,6 @@ func (in *AuthConfig) DeepCopyInto(out *AuthConfig) { *out = new(v1.LocalObjectReference) **out = **in } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AuthConfig. @@ -49,7 +48,6 @@ func (in *AuthConfig) DeepCopy() *AuthConfig { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *CGroupLimits) DeepCopyInto(out *CGroupLimits) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CGroupLimits. @@ -77,7 +75,6 @@ func (in *ContainerConfig) DeepCopyInto(out *ContainerConfig) { *out = make([]string, len(*in)) copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerConfig. @@ -103,7 +100,6 @@ func (in *ContainerInfo) DeepCopyInto(out *ContainerInfo) { *out = make([]string, len(*in)) copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ContainerInfo. @@ -119,7 +115,6 @@ func (in *ContainerInfo) DeepCopy() *ContainerInfo { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DockerConfig) DeepCopyInto(out *DockerConfig) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DockerConfig. @@ -135,7 +130,6 @@ func (in *DockerConfig) DeepCopy() *DockerConfig { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *DockerConfigEntry) DeepCopyInto(out *DockerConfigEntry) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DockerConfigEntry. @@ -158,7 +152,6 @@ func (in *DockerConfigJson) DeepCopyInto(out *DockerConfigJson) { (*out)[key] = val } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DockerConfigJson. @@ -179,7 +172,6 @@ func (in DockerConfigMap) DeepCopyInto(out *DockerConfigMap) { for key, val := range *in { (*out)[key] = val } - return } } @@ -196,7 +188,6 @@ func (in DockerConfigMap) DeepCopy() DockerConfigMap { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *EnvironmentSpec) DeepCopyInto(out *EnvironmentSpec) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EnvironmentSpec. @@ -217,7 +208,6 @@ func (in *Parameter) DeepCopyInto(out *Parameter) { *out = make([]string, len(*in)) copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Parameter. @@ -233,7 +223,6 @@ func (in *Parameter) DeepCopy() *Parameter { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ProxyConfig) DeepCopyInto(out *ProxyConfig) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyConfig. @@ -259,7 +248,6 @@ func (in *S2iAutoScale) DeepCopyInto(out *S2iAutoScale) { *out = make([]string, len(*in)) copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iAutoScale. @@ -279,7 +267,6 @@ func (in *S2iBinary) DeepCopyInto(out *S2iBinary) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBinary. @@ -312,7 +299,6 @@ func (in *S2iBinaryList) DeepCopyInto(out *S2iBinaryList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBinaryList. @@ -340,7 +326,6 @@ func (in *S2iBinarySpec) DeepCopyInto(out *S2iBinarySpec) { in, out := &in.UploadTimeStamp, &out.UploadTimeStamp *out = (*in).DeepCopy() } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBinarySpec. @@ -356,7 +341,6 @@ func (in *S2iBinarySpec) DeepCopy() *S2iBinarySpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *S2iBinaryStatus) DeepCopyInto(out *S2iBinaryStatus) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBinaryStatus. @@ -377,7 +361,6 @@ func (in *S2iBuildResult) DeepCopyInto(out *S2iBuildResult) { *out = make([]string, len(*in)) copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuildResult. @@ -393,7 +376,6 @@ func (in *S2iBuildResult) DeepCopy() *S2iBuildResult { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *S2iBuildSource) DeepCopyInto(out *S2iBuildSource) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuildSource. @@ -413,7 +395,6 @@ func (in *S2iBuilder) DeepCopyInto(out *S2iBuilder) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilder. @@ -446,7 +427,6 @@ func (in *S2iBuilderList) DeepCopyInto(out *S2iBuilderList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderList. @@ -480,7 +460,6 @@ func (in *S2iBuilderSpec) DeepCopyInto(out *S2iBuilderSpec) { *out = new(UserDefineTemplate) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderSpec. @@ -505,7 +484,6 @@ func (in *S2iBuilderStatus) DeepCopyInto(out *S2iBuilderStatus) { in, out := &in.LastRunStartTime, &out.LastRunStartTime *out = (*in).DeepCopy() } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderStatus. @@ -525,7 +503,6 @@ func (in *S2iBuilderTemplate) DeepCopyInto(out *S2iBuilderTemplate) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderTemplate. @@ -558,7 +535,6 @@ func (in *S2iBuilderTemplateList) DeepCopyInto(out *S2iBuilderTemplateList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderTemplateList. @@ -596,7 +572,6 @@ func (in *S2iBuilderTemplateSpec) DeepCopyInto(out *S2iBuilderTemplateSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderTemplateSpec. @@ -612,7 +587,6 @@ func (in *S2iBuilderTemplateSpec) DeepCopy() *S2iBuilderTemplateSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *S2iBuilderTemplateStatus) DeepCopyInto(out *S2iBuilderTemplateStatus) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iBuilderTemplateStatus. @@ -715,7 +689,6 @@ func (in *S2iConfig) DeepCopyInto(out *S2iConfig) { *out = make([]string, len(*in)) copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iConfig. @@ -735,7 +708,6 @@ func (in *S2iRun) DeepCopyInto(out *S2iRun) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) out.Spec = in.Spec in.Status.DeepCopyInto(&out.Status) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iRun. @@ -768,7 +740,6 @@ func (in *S2iRunList) DeepCopyInto(out *S2iRunList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iRunList. @@ -792,7 +763,6 @@ func (in *S2iRunList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *S2iRunSpec) DeepCopyInto(out *S2iRunSpec) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iRunSpec. @@ -826,7 +796,6 @@ func (in *S2iRunStatus) DeepCopyInto(out *S2iRunStatus) { *out = new(S2iBuildSource) **out = **in } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new S2iRunStatus. @@ -849,7 +818,6 @@ func (in *UserDefineTemplate) DeepCopyInto(out *UserDefineTemplate) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserDefineTemplate. @@ -865,7 +833,6 @@ func (in *UserDefineTemplate) DeepCopy() *UserDefineTemplate { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VolumeSpec) DeepCopyInto(out *VolumeSpec) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSpec. diff --git a/pkg/apis/iam/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/iam/v1alpha2/zz_generated.deepcopy.go index 53810ab256a847410b70b356dbf1100f68f6445a..86305a89832b054549feb470fa79f872368b4124 100644 --- a/pkg/apis/iam/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/iam/v1alpha2/zz_generated.deepcopy.go @@ -16,19 +16,18 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by deepcopy-gen. DO NOT EDIT. +// Code generated by controller-gen. DO NOT EDIT. package v1alpha2 import ( - v1 "k8s.io/api/rbac/v1" - runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/api/rbac/v1" + "k8s.io/apimachinery/pkg/runtime" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *Cluster) DeepCopyInto(out *Cluster) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Cluster. @@ -51,7 +50,6 @@ func (in *ClusterSelector) DeepCopyInto(out *ClusterSelector) { (*out)[key] = val } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSelector. @@ -70,7 +68,6 @@ func (in *FederatedRole) DeepCopyInto(out *FederatedRole) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedRole. @@ -89,7 +86,6 @@ func (in *FederatedRoleBinding) DeepCopyInto(out *FederatedRoleBinding) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedRoleBinding. @@ -107,7 +103,6 @@ func (in *FederatedRoleBindingSpec) DeepCopyInto(out *FederatedRoleBindingSpec) *out = *in in.Template.DeepCopyInto(&out.Template) in.Placement.DeepCopyInto(&out.Placement) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedRoleBindingSpec. @@ -125,7 +120,6 @@ func (in *FederatedRoleSpec) DeepCopyInto(out *FederatedRoleSpec) { *out = *in in.Template.DeepCopyInto(&out.Template) in.Placement.DeepCopyInto(&out.Placement) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedRoleSpec. @@ -144,7 +138,6 @@ func (in *FederatedUser) DeepCopyInto(out *FederatedUser) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedUser. @@ -162,7 +155,6 @@ func (in *FederatedUserSpec) DeepCopyInto(out *FederatedUserSpec) { *out = *in in.Template.DeepCopyInto(&out.Template) in.Placement.DeepCopyInto(&out.Placement) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedUserSpec. @@ -187,7 +179,6 @@ func (in *GlobalRole) DeepCopyInto(out *GlobalRole) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlobalRole. @@ -219,7 +210,6 @@ func (in *GlobalRoleBinding) DeepCopyInto(out *GlobalRoleBinding) { copy(*out, *in) } out.RoleRef = in.RoleRef - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlobalRoleBinding. @@ -252,7 +242,6 @@ func (in *GlobalRoleBindingList) DeepCopyInto(out *GlobalRoleBindingList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlobalRoleBindingList. @@ -285,7 +274,6 @@ func (in *GlobalRoleList) DeepCopyInto(out *GlobalRoleList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlobalRoleList. @@ -313,7 +301,6 @@ func (in *Group) DeepCopyInto(out *Group) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) out.Spec = in.Spec out.Status = in.Status - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Group. @@ -345,7 +332,6 @@ func (in *GroupBinding) DeepCopyInto(out *GroupBinding) { *out = make([]string, len(*in)) copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupBinding. @@ -378,7 +364,6 @@ func (in *GroupBindingList) DeepCopyInto(out *GroupBindingList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupBindingList. @@ -411,7 +396,6 @@ func (in *GroupList) DeepCopyInto(out *GroupList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupList. @@ -435,7 +419,6 @@ func (in *GroupList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GroupRef) DeepCopyInto(out *GroupRef) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupRef. @@ -451,7 +434,6 @@ func (in *GroupRef) DeepCopy() *GroupRef { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GroupSpec) DeepCopyInto(out *GroupSpec) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupSpec. @@ -467,7 +449,6 @@ func (in *GroupSpec) DeepCopy() *GroupSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GroupStatus) DeepCopyInto(out *GroupStatus) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupStatus. @@ -486,7 +467,6 @@ func (in *LoginRecord) DeepCopyInto(out *LoginRecord) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) out.Spec = in.Spec - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoginRecord. @@ -519,7 +499,6 @@ func (in *LoginRecordList) DeepCopyInto(out *LoginRecordList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoginRecordList. @@ -543,7 +522,6 @@ func (in *LoginRecordList) DeepCopyObject() runtime.Object { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *LoginRecordSpec) DeepCopyInto(out *LoginRecordSpec) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoginRecordSpec. @@ -565,7 +543,6 @@ func (in *Placement) DeepCopyInto(out *Placement) { copy(*out, *in) } in.ClusterSelector.DeepCopyInto(&out.ClusterSelector) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Placement. @@ -584,7 +561,6 @@ func (in *RoleBase) DeepCopyInto(out *RoleBase) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Role.DeepCopyInto(&out.Role) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleBase. @@ -617,7 +593,6 @@ func (in *RoleBaseList) DeepCopyInto(out *RoleBaseList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleBaseList. @@ -648,7 +623,6 @@ func (in *RoleBindingTemplate) DeepCopyInto(out *RoleBindingTemplate) { copy(*out, *in) } out.RoleRef = in.RoleRef - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleBindingTemplate. @@ -672,7 +646,6 @@ func (in *RoleTemplate) DeepCopyInto(out *RoleTemplate) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RoleTemplate. @@ -692,7 +665,6 @@ func (in *User) DeepCopyInto(out *User) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new User. @@ -725,7 +697,6 @@ func (in *UserList) DeepCopyInto(out *UserList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserList. @@ -754,7 +725,6 @@ func (in *UserSpec) DeepCopyInto(out *UserSpec) { *out = make([]string, len(*in)) copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserSpec. @@ -783,7 +753,6 @@ func (in *UserStatus) DeepCopyInto(out *UserStatus) { in, out := &in.LastLoginTime, &out.LastLoginTime *out = (*in).DeepCopy() } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserStatus. @@ -802,7 +771,6 @@ func (in *UserTemplate) DeepCopyInto(out *UserTemplate) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserTemplate. @@ -827,7 +795,6 @@ func (in *WorkspaceRole) DeepCopyInto(out *WorkspaceRole) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceRole. @@ -859,7 +826,6 @@ func (in *WorkspaceRoleBinding) DeepCopyInto(out *WorkspaceRoleBinding) { copy(*out, *in) } out.RoleRef = in.RoleRef - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceRoleBinding. @@ -892,7 +858,6 @@ func (in *WorkspaceRoleBindingList) DeepCopyInto(out *WorkspaceRoleBindingList) (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceRoleBindingList. @@ -925,7 +890,6 @@ func (in *WorkspaceRoleList) DeepCopyInto(out *WorkspaceRoleList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceRoleList. diff --git a/pkg/apis/network/calicov3/zz_generated.deepcopy.go b/pkg/apis/network/calicov3/zz_generated.deepcopy.go index ab3e51879d8246febcd7f546dfb5950d4d57feb2..a3f98985be0c6ac3c3517031f25f9595e2414e8d 100644 --- a/pkg/apis/network/calicov3/zz_generated.deepcopy.go +++ b/pkg/apis/network/calicov3/zz_generated.deepcopy.go @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by deepcopy-gen. DO NOT EDIT. +// Code generated by controller-gen. DO NOT EDIT. package calicov3 @@ -30,7 +30,6 @@ func (in *BlockAffinity) DeepCopyInto(out *BlockAffinity) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) out.Spec = in.Spec - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BlockAffinity. @@ -63,7 +62,6 @@ func (in *BlockAffinityList) DeepCopyInto(out *BlockAffinityList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new BlockAffinityList. @@ -90,7 +88,6 @@ func (in *IPAMBlock) DeepCopyInto(out *IPAMBlock) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAMBlock. @@ -123,7 +120,6 @@ func (in *IPAMBlockList) DeepCopyInto(out *IPAMBlockList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPAMBlockList. @@ -150,7 +146,6 @@ func (in *IPPool) DeepCopyInto(out *IPPool) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPool. @@ -183,7 +178,6 @@ func (in *IPPoolList) DeepCopyInto(out *IPPoolList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IPPoolList. diff --git a/pkg/apis/servicemesh/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/servicemesh/v1alpha2/zz_generated.deepcopy.go index f58e8d24d0aaf0a739ed2a86cad6158a6c53e00c..c9cdd094f6c4e0e02683cd0cb15c779f03bae96b 100644 --- a/pkg/apis/servicemesh/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/servicemesh/v1alpha2/zz_generated.deepcopy.go @@ -16,12 +16,12 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by deepcopy-gen. DO NOT EDIT. +// Code generated by controller-gen. DO NOT EDIT. package v1alpha2 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" runtime "k8s.io/apimachinery/pkg/runtime" ) @@ -30,7 +30,6 @@ func (in *DestinationRuleSpecTemplate) DeepCopyInto(out *DestinationRuleSpecTemp *out = *in in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DestinationRuleSpecTemplate. @@ -50,7 +49,6 @@ func (in *ServicePolicy) DeepCopyInto(out *ServicePolicy) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePolicy. @@ -76,7 +74,6 @@ func (in *ServicePolicyCondition) DeepCopyInto(out *ServicePolicyCondition) { *out = *in in.LastProbeTime.DeepCopyInto(&out.LastProbeTime) in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePolicyCondition. @@ -101,7 +98,6 @@ func (in *ServicePolicyList) DeepCopyInto(out *ServicePolicyList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePolicyList. @@ -131,7 +127,6 @@ func (in *ServicePolicySpec) DeepCopyInto(out *ServicePolicySpec) { (*in).DeepCopyInto(*out) } in.Template.DeepCopyInto(&out.Template) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePolicySpec. @@ -162,7 +157,6 @@ func (in *ServicePolicyStatus) DeepCopyInto(out *ServicePolicyStatus) { in, out := &in.CompletionTime, &out.CompletionTime *out = (*in).DeepCopy() } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServicePolicyStatus. @@ -182,7 +176,6 @@ func (in *Strategy) DeepCopyInto(out *Strategy) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) in.Status.DeepCopyInto(&out.Status) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Strategy. @@ -208,7 +201,6 @@ func (in *StrategyCondition) DeepCopyInto(out *StrategyCondition) { *out = *in in.LastProbeTime.DeepCopyInto(&out.LastProbeTime) in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategyCondition. @@ -233,7 +225,6 @@ func (in *StrategyList) DeepCopyInto(out *StrategyList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategyList. @@ -263,7 +254,6 @@ func (in *StrategySpec) DeepCopyInto(out *StrategySpec) { (*in).DeepCopyInto(*out) } in.Template.DeepCopyInto(&out.Template) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategySpec. @@ -294,7 +284,6 @@ func (in *StrategyStatus) DeepCopyInto(out *StrategyStatus) { in, out := &in.CompletionTime, &out.CompletionTime *out = (*in).DeepCopy() } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StrategyStatus. @@ -312,7 +301,6 @@ func (in *VirtualServiceTemplateSpec) DeepCopyInto(out *VirtualServiceTemplateSp *out = *in in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VirtualServiceTemplateSpec. diff --git a/pkg/apis/storage/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/storage/v1alpha1/zz_generated.deepcopy.go index 68b70b7e2b86837fac2c1d1c51923985b3f1f533..457457e1cbe45caa0577c89f6179f80c472d4aa5 100644 --- a/pkg/apis/storage/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/storage/v1alpha1/zz_generated.deepcopy.go @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by deepcopy-gen. DO NOT EDIT. +// Code generated by controller-gen. DO NOT EDIT. package v1alpha1 @@ -29,7 +29,6 @@ func (in *CapabilityFeatures) DeepCopyInto(out *CapabilityFeatures) { *out = *in out.Volume = in.Volume out.Snapshot = in.Snapshot - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CapabilityFeatures. @@ -45,7 +44,6 @@ func (in *CapabilityFeatures) DeepCopy() *CapabilityFeatures { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PluginInfo) DeepCopyInto(out *PluginInfo) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PluginInfo. @@ -64,7 +62,6 @@ func (in *ProvisionerCapability) DeepCopyInto(out *ProvisionerCapability) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) out.Spec = in.Spec - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisionerCapability. @@ -97,7 +94,6 @@ func (in *ProvisionerCapabilityList) DeepCopyInto(out *ProvisionerCapabilityList (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisionerCapabilityList. @@ -123,7 +119,6 @@ func (in *ProvisionerCapabilitySpec) DeepCopyInto(out *ProvisionerCapabilitySpec *out = *in out.PluginInfo = in.PluginInfo out.Features = in.Features - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProvisionerCapabilitySpec. @@ -139,7 +134,6 @@ func (in *ProvisionerCapabilitySpec) DeepCopy() *ProvisionerCapabilitySpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *SnapshotFeature) DeepCopyInto(out *SnapshotFeature) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SnapshotFeature. @@ -158,7 +152,6 @@ func (in *StorageClassCapability) DeepCopyInto(out *StorageClassCapability) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) out.Spec = in.Spec - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageClassCapability. @@ -191,7 +184,6 @@ func (in *StorageClassCapabilityList) DeepCopyInto(out *StorageClassCapabilityLi (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageClassCapabilityList. @@ -216,7 +208,6 @@ func (in *StorageClassCapabilityList) DeepCopyObject() runtime.Object { func (in *StorageClassCapabilitySpec) DeepCopyInto(out *StorageClassCapabilitySpec) { *out = *in out.Features = in.Features - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StorageClassCapabilitySpec. @@ -232,7 +223,6 @@ func (in *StorageClassCapabilitySpec) DeepCopy() *StorageClassCapabilitySpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *VolumeFeature) DeepCopyInto(out *VolumeFeature) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeFeature. diff --git a/pkg/apis/tenant/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/tenant/v1alpha1/zz_generated.deepcopy.go index 06c23ab44657233101c03aea01c473e544fd87d1..393122d0b55336917267a41b897529d60bc01a5d 100644 --- a/pkg/apis/tenant/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/tenant/v1alpha1/zz_generated.deepcopy.go @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by deepcopy-gen. DO NOT EDIT. +// Code generated by controller-gen. DO NOT EDIT. package v1alpha1 @@ -31,7 +31,6 @@ func (in *Workspace) DeepCopyInto(out *Workspace) { in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) out.Status = in.Status - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Workspace. @@ -64,7 +63,6 @@ func (in *WorkspaceList) DeepCopyInto(out *WorkspaceList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceList. @@ -93,7 +91,6 @@ func (in *WorkspaceSpec) DeepCopyInto(out *WorkspaceSpec) { *out = new(bool) **out = **in } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceSpec. @@ -109,7 +106,6 @@ func (in *WorkspaceSpec) DeepCopy() *WorkspaceSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkspaceStatus) DeepCopyInto(out *WorkspaceStatus) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceStatus. diff --git a/pkg/apis/tenant/v1alpha2/zz_generated.deepcopy.go b/pkg/apis/tenant/v1alpha2/zz_generated.deepcopy.go index 6465142864187ee9e0bc5479ff2ef8e944f54352..9fc14af6573fcf77e987f5186e82145d4598a720 100644 --- a/pkg/apis/tenant/v1alpha2/zz_generated.deepcopy.go +++ b/pkg/apis/tenant/v1alpha2/zz_generated.deepcopy.go @@ -16,7 +16,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by deepcopy-gen. DO NOT EDIT. +// Code generated by controller-gen. DO NOT EDIT. package v1alpha2 @@ -30,7 +30,6 @@ func (in *WorkspaceTemplate) DeepCopyInto(out *WorkspaceTemplate) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceTemplate. @@ -63,7 +62,6 @@ func (in *WorkspaceTemplateList) DeepCopyInto(out *WorkspaceTemplateList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceTemplateList. diff --git a/pkg/apis/types/v1beta1/register.go b/pkg/apis/types/v1beta1/register.go index 0706a8b2b8c0bc3405d1216db82ba147390660c0..b11654efcfcfd60ac5c12995ca657d821cb1c616 100644 --- a/pkg/apis/types/v1beta1/register.go +++ b/pkg/apis/types/v1beta1/register.go @@ -81,5 +81,6 @@ func init() { &FederatedWorkspaceRole{}, &FederatedWorkspaceRoleList{}, &FederatedWorkspaceRoleBinding{}, - &FederatedWorkspaceRoleBindingList{}) + &FederatedWorkspaceRoleBindingList{}, + ) } diff --git a/pkg/apis/types/v1beta1/zz_generated.deepcopy.go b/pkg/apis/types/v1beta1/zz_generated.deepcopy.go index a6dc37ab56c63f1455aeb97a607e2c4c750c77b4..5bffec1cd4e6166fa431b999bd83e2170d51d72c 100644 --- a/pkg/apis/types/v1beta1/zz_generated.deepcopy.go +++ b/pkg/apis/types/v1beta1/zz_generated.deepcopy.go @@ -16,21 +16,20 @@ See the License for the specific language governing permissions and limitations under the License. */ -// Code generated by deepcopy-gen. DO NOT EDIT. +// Code generated by controller-gen. DO NOT EDIT. package v1beta1 import ( - v1 "k8s.io/api/rbac/v1" + "k8s.io/api/rbac/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - runtime "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime" ) // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *ApplicationTemplate) DeepCopyInto(out *ApplicationTemplate) { *out = *in in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ApplicationTemplate. @@ -47,7 +46,6 @@ func (in *ApplicationTemplate) DeepCopy() *ApplicationTemplate { func (in *ClusterOverride) DeepCopyInto(out *ClusterOverride) { *out = *in in.Value.DeepCopyInto(&out.Value) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterOverride. @@ -69,7 +67,6 @@ func (in *ClusterRoleBindingTemplate) DeepCopyInto(out *ClusterRoleBindingTempla copy(*out, *in) } out.RoleRef = in.RoleRef - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRoleBindingTemplate. @@ -97,7 +94,6 @@ func (in *ClusterRoleTemplate) DeepCopyInto(out *ClusterRoleTemplate) { *out = new(v1.AggregationRule) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterRoleTemplate. @@ -135,7 +131,6 @@ func (in *ConfigMapTemplate) DeepCopyInto(out *ConfigMapTemplate) { (*out)[key] = outVal } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConfigMapTemplate. @@ -152,7 +147,6 @@ func (in *ConfigMapTemplate) DeepCopy() *ConfigMapTemplate { func (in *DeploymentTemplate) DeepCopyInto(out *DeploymentTemplate) { *out = *in in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeploymentTemplate. @@ -176,7 +170,6 @@ func (in *FederatedApplication) DeepCopyInto(out *FederatedApplication) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedApplication. @@ -209,7 +202,6 @@ func (in *FederatedApplicationList) DeepCopyInto(out *FederatedApplicationList) (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedApplicationList. @@ -242,7 +234,6 @@ func (in *FederatedApplicationSpec) DeepCopyInto(out *FederatedApplicationSpec) (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedApplicationSpec. @@ -266,7 +257,6 @@ func (in *FederatedClusterRole) DeepCopyInto(out *FederatedClusterRole) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedClusterRole. @@ -298,7 +288,6 @@ func (in *FederatedClusterRoleBinding) DeepCopyInto(out *FederatedClusterRoleBin *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedClusterRoleBinding. @@ -331,7 +320,6 @@ func (in *FederatedClusterRoleBindingList) DeepCopyInto(out *FederatedClusterRol (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedClusterRoleBindingList. @@ -364,7 +352,6 @@ func (in *FederatedClusterRoleBindingSpec) DeepCopyInto(out *FederatedClusterRol (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedClusterRoleBindingSpec. @@ -389,7 +376,6 @@ func (in *FederatedClusterRoleList) DeepCopyInto(out *FederatedClusterRoleList) (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedClusterRoleList. @@ -422,7 +408,6 @@ func (in *FederatedClusterRoleSpec) DeepCopyInto(out *FederatedClusterRoleSpec) (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedClusterRoleSpec. @@ -446,7 +431,6 @@ func (in *FederatedConfigMap) DeepCopyInto(out *FederatedConfigMap) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedConfigMap. @@ -479,7 +463,6 @@ func (in *FederatedConfigMapList) DeepCopyInto(out *FederatedConfigMapList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedConfigMapList. @@ -512,7 +495,6 @@ func (in *FederatedConfigMapSpec) DeepCopyInto(out *FederatedConfigMapSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedConfigMapSpec. @@ -536,7 +518,6 @@ func (in *FederatedDeployment) DeepCopyInto(out *FederatedDeployment) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedDeployment. @@ -569,7 +550,6 @@ func (in *FederatedDeploymentList) DeepCopyInto(out *FederatedDeploymentList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedDeploymentList. @@ -602,7 +582,6 @@ func (in *FederatedDeploymentSpec) DeepCopyInto(out *FederatedDeploymentSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedDeploymentSpec. @@ -626,7 +605,6 @@ func (in *FederatedGroup) DeepCopyInto(out *FederatedGroup) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedGroup. @@ -658,7 +636,6 @@ func (in *FederatedGroupBinding) DeepCopyInto(out *FederatedGroupBinding) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedGroupBinding. @@ -691,7 +668,6 @@ func (in *FederatedGroupBindingList) DeepCopyInto(out *FederatedGroupBindingList (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedGroupBindingList. @@ -724,7 +700,6 @@ func (in *FederatedGroupBindingSpec) DeepCopyInto(out *FederatedGroupBindingSpec (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedGroupBindingSpec. @@ -749,7 +724,6 @@ func (in *FederatedGroupList) DeepCopyInto(out *FederatedGroupList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedGroupList. @@ -782,7 +756,6 @@ func (in *FederatedGroupSpec) DeepCopyInto(out *FederatedGroupSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedGroupSpec. @@ -806,7 +779,6 @@ func (in *FederatedIngress) DeepCopyInto(out *FederatedIngress) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedIngress. @@ -839,7 +811,6 @@ func (in *FederatedIngressList) DeepCopyInto(out *FederatedIngressList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedIngressList. @@ -872,7 +843,6 @@ func (in *FederatedIngressSpec) DeepCopyInto(out *FederatedIngressSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedIngressSpec. @@ -896,7 +866,6 @@ func (in *FederatedJob) DeepCopyInto(out *FederatedJob) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedJob. @@ -929,7 +898,6 @@ func (in *FederatedJobList) DeepCopyInto(out *FederatedJobList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedJobList. @@ -962,7 +930,6 @@ func (in *FederatedJobSpec) DeepCopyInto(out *FederatedJobSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedJobSpec. @@ -986,7 +953,6 @@ func (in *FederatedLimitRange) DeepCopyInto(out *FederatedLimitRange) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedLimitRange. @@ -1019,7 +985,6 @@ func (in *FederatedLimitRangeList) DeepCopyInto(out *FederatedLimitRangeList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedLimitRangeList. @@ -1052,7 +1017,6 @@ func (in *FederatedLimitRangeSpec) DeepCopyInto(out *FederatedLimitRangeSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedLimitRangeSpec. @@ -1076,7 +1040,6 @@ func (in *FederatedNamespace) DeepCopyInto(out *FederatedNamespace) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNamespace. @@ -1109,7 +1072,6 @@ func (in *FederatedNamespaceList) DeepCopyInto(out *FederatedNamespaceList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNamespaceList. @@ -1142,7 +1104,6 @@ func (in *FederatedNamespaceSpec) DeepCopyInto(out *FederatedNamespaceSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedNamespaceSpec. @@ -1166,7 +1127,6 @@ func (in *FederatedPersistentVolumeClaim) DeepCopyInto(out *FederatedPersistentV *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedPersistentVolumeClaim. @@ -1199,7 +1159,6 @@ func (in *FederatedPersistentVolumeClaimList) DeepCopyInto(out *FederatedPersist (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedPersistentVolumeClaimList. @@ -1232,7 +1191,6 @@ func (in *FederatedPersistentVolumeClaimSpec) DeepCopyInto(out *FederatedPersist (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedPersistentVolumeClaimSpec. @@ -1256,7 +1214,6 @@ func (in *FederatedResourceQuota) DeepCopyInto(out *FederatedResourceQuota) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedResourceQuota. @@ -1289,7 +1246,6 @@ func (in *FederatedResourceQuotaList) DeepCopyInto(out *FederatedResourceQuotaLi (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedResourceQuotaList. @@ -1322,7 +1278,6 @@ func (in *FederatedResourceQuotaSpec) DeepCopyInto(out *FederatedResourceQuotaSp (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedResourceQuotaSpec. @@ -1346,7 +1301,6 @@ func (in *FederatedSecret) DeepCopyInto(out *FederatedSecret) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedSecret. @@ -1379,7 +1333,6 @@ func (in *FederatedSecretList) DeepCopyInto(out *FederatedSecretList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedSecretList. @@ -1412,7 +1365,6 @@ func (in *FederatedSecretSpec) DeepCopyInto(out *FederatedSecretSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedSecretSpec. @@ -1436,7 +1388,6 @@ func (in *FederatedService) DeepCopyInto(out *FederatedService) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedService. @@ -1469,7 +1420,6 @@ func (in *FederatedServiceList) DeepCopyInto(out *FederatedServiceList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedServiceList. @@ -1502,7 +1452,6 @@ func (in *FederatedServiceSpec) DeepCopyInto(out *FederatedServiceSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedServiceSpec. @@ -1526,7 +1475,6 @@ func (in *FederatedStatefulSet) DeepCopyInto(out *FederatedStatefulSet) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedStatefulSet. @@ -1559,7 +1507,6 @@ func (in *FederatedStatefulSetList) DeepCopyInto(out *FederatedStatefulSetList) (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedStatefulSetList. @@ -1592,7 +1539,6 @@ func (in *FederatedStatefulSetSpec) DeepCopyInto(out *FederatedStatefulSetSpec) (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedStatefulSetSpec. @@ -1616,7 +1562,6 @@ func (in *FederatedUser) DeepCopyInto(out *FederatedUser) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedUser. @@ -1649,7 +1594,6 @@ func (in *FederatedUserList) DeepCopyInto(out *FederatedUserList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedUserList. @@ -1682,7 +1626,6 @@ func (in *FederatedUserSpec) DeepCopyInto(out *FederatedUserSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedUserSpec. @@ -1706,7 +1649,6 @@ func (in *FederatedWorkspace) DeepCopyInto(out *FederatedWorkspace) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedWorkspace. @@ -1739,7 +1681,6 @@ func (in *FederatedWorkspaceList) DeepCopyInto(out *FederatedWorkspaceList) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedWorkspaceList. @@ -1771,7 +1712,6 @@ func (in *FederatedWorkspaceRole) DeepCopyInto(out *FederatedWorkspaceRole) { *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedWorkspaceRole. @@ -1803,7 +1743,6 @@ func (in *FederatedWorkspaceRoleBinding) DeepCopyInto(out *FederatedWorkspaceRol *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedWorkspaceRoleBinding. @@ -1836,7 +1775,6 @@ func (in *FederatedWorkspaceRoleBindingList) DeepCopyInto(out *FederatedWorkspac (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedWorkspaceRoleBindingList. @@ -1869,7 +1807,6 @@ func (in *FederatedWorkspaceRoleBindingSpec) DeepCopyInto(out *FederatedWorkspac (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedWorkspaceRoleBindingSpec. @@ -1882,29 +1819,6 @@ func (in *FederatedWorkspaceRoleBindingSpec) DeepCopy() *FederatedWorkspaceRoleB return out } -// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. -func (in *WorkspaceRoleBindingTemplate) DeepCopyInto(out *WorkspaceRoleBindingTemplate) { - *out = *in - in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) - if in.Subjects != nil { - in, out := &in.Subjects, &out.Subjects - *out = make([]v1.Subject, len(*in)) - copy(*out, *in) - } - out.RoleRef = in.RoleRef - return -} - -// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceRoleBindingTemplate. -func (in *WorkspaceRoleBindingTemplate) DeepCopy() *WorkspaceRoleBindingTemplate { - if in == nil { - return nil - } - out := new(WorkspaceRoleBindingTemplate) - in.DeepCopyInto(out) - return out -} - // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *FederatedWorkspaceRoleList) DeepCopyInto(out *FederatedWorkspaceRoleList) { *out = *in @@ -1917,7 +1831,6 @@ func (in *FederatedWorkspaceRoleList) DeepCopyInto(out *FederatedWorkspaceRoleLi (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedWorkspaceRoleList. @@ -1950,7 +1863,6 @@ func (in *FederatedWorkspaceRoleSpec) DeepCopyInto(out *FederatedWorkspaceRoleSp (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedWorkspaceRoleSpec. @@ -1975,7 +1887,6 @@ func (in *FederatedWorkspaceSpec) DeepCopyInto(out *FederatedWorkspaceSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FederatedWorkspaceSpec. @@ -1991,7 +1902,6 @@ func (in *FederatedWorkspaceSpec) DeepCopy() *FederatedWorkspaceSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GenericClusterReference) DeepCopyInto(out *GenericClusterReference) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericClusterReference. @@ -2007,7 +1917,6 @@ func (in *GenericClusterReference) DeepCopy() *GenericClusterReference { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GenericClusterStatus) DeepCopyInto(out *GenericClusterStatus) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericClusterStatus. @@ -2023,7 +1932,6 @@ func (in *GenericClusterStatus) DeepCopy() *GenericClusterStatus { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *GenericCondition) DeepCopyInto(out *GenericCondition) { *out = *in - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericCondition. @@ -2046,7 +1954,6 @@ func (in *GenericFederatedResource) DeepCopyInto(out *GenericFederatedResource) *out = new(GenericFederatedStatus) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericFederatedResource. @@ -2078,7 +1985,6 @@ func (in *GenericFederatedStatus) DeepCopyInto(out *GenericFederatedStatus) { *out = make([]GenericClusterStatus, len(*in)) copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericFederatedStatus. @@ -2101,7 +2007,6 @@ func (in *GenericOverride) DeepCopyInto(out *GenericOverride) { *out = new(GenericOverrideSpec) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericOverride. @@ -2124,7 +2029,6 @@ func (in *GenericOverrideItem) DeepCopyInto(out *GenericOverrideItem) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericOverrideItem. @@ -2147,7 +2051,6 @@ func (in *GenericOverrideSpec) DeepCopyInto(out *GenericOverrideSpec) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericOverrideSpec. @@ -2166,7 +2069,6 @@ func (in *GenericPlacement) DeepCopyInto(out *GenericPlacement) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericPlacement. @@ -2192,7 +2094,6 @@ func (in *GenericPlacementFields) DeepCopyInto(out *GenericPlacementFields) { *out = new(metav1.LabelSelector) (*in).DeepCopyInto(*out) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericPlacementFields. @@ -2209,7 +2110,6 @@ func (in *GenericPlacementFields) DeepCopy() *GenericPlacementFields { func (in *GenericPlacementSpec) DeepCopyInto(out *GenericPlacementSpec) { *out = *in in.Placement.DeepCopyInto(&out.Placement) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GenericPlacementSpec. @@ -2232,7 +2132,6 @@ func (in *GroupBindingTemplate) DeepCopyInto(out *GroupBindingTemplate) { *out = make([]string, len(*in)) copy(*out, *in) } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupBindingTemplate. @@ -2250,7 +2149,6 @@ func (in *GroupTemplate) DeepCopyInto(out *GroupTemplate) { *out = *in in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) out.Spec = in.Spec - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GroupTemplate. @@ -2267,7 +2165,6 @@ func (in *GroupTemplate) DeepCopy() *GroupTemplate { func (in *IngressTemplate) DeepCopyInto(out *IngressTemplate) { *out = *in in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new IngressTemplate. @@ -2284,7 +2181,6 @@ func (in *IngressTemplate) DeepCopy() *IngressTemplate { func (in *JobTemplate) DeepCopyInto(out *JobTemplate) { *out = *in in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new JobTemplate. @@ -2301,7 +2197,6 @@ func (in *JobTemplate) DeepCopy() *JobTemplate { func (in *LimitRangeTemplate) DeepCopyInto(out *LimitRangeTemplate) { *out = *in in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LimitRangeTemplate. @@ -2318,7 +2213,6 @@ func (in *LimitRangeTemplate) DeepCopy() *LimitRangeTemplate { func (in *NamespaceTemplate) DeepCopyInto(out *NamespaceTemplate) { *out = *in in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NamespaceTemplate. @@ -2337,7 +2231,6 @@ func (in *PersistentVolumeClaimTemplate) DeepCopyInto(out *PersistentVolumeClaim out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PersistentVolumeClaimTemplate. @@ -2354,7 +2247,6 @@ func (in *PersistentVolumeClaimTemplate) DeepCopy() *PersistentVolumeClaimTempla func (in *ResourceQuotaTemplate) DeepCopyInto(out *ResourceQuotaTemplate) { *out = *in in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceQuotaTemplate. @@ -2392,7 +2284,6 @@ func (in *SecretTemplate) DeepCopyInto(out *SecretTemplate) { (*out)[key] = val } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretTemplate. @@ -2411,7 +2302,6 @@ func (in *ServiceTemplate) DeepCopyInto(out *ServiceTemplate) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ServiceTemplate. @@ -2430,7 +2320,6 @@ func (in *StatefulSetTemplate) DeepCopyInto(out *StatefulSetTemplate) { out.TypeMeta = in.TypeMeta in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new StatefulSetTemplate. @@ -2447,7 +2336,6 @@ func (in *StatefulSetTemplate) DeepCopy() *StatefulSetTemplate { func (in *UserTemplate) DeepCopyInto(out *UserTemplate) { *out = *in in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new UserTemplate. @@ -2460,6 +2348,28 @@ func (in *UserTemplate) DeepCopy() *UserTemplate { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *WorkspaceRoleBindingTemplate) DeepCopyInto(out *WorkspaceRoleBindingTemplate) { + *out = *in + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + if in.Subjects != nil { + in, out := &in.Subjects, &out.Subjects + *out = make([]v1.Subject, len(*in)) + copy(*out, *in) + } + out.RoleRef = in.RoleRef +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceRoleBindingTemplate. +func (in *WorkspaceRoleBindingTemplate) DeepCopy() *WorkspaceRoleBindingTemplate { + if in == nil { + return nil + } + out := new(WorkspaceRoleBindingTemplate) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *WorkspaceRoleTemplate) DeepCopyInto(out *WorkspaceRoleTemplate) { *out = *in @@ -2471,7 +2381,6 @@ func (in *WorkspaceRoleTemplate) DeepCopyInto(out *WorkspaceRoleTemplate) { (*in)[i].DeepCopyInto(&(*out)[i]) } } - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceRoleTemplate. @@ -2489,7 +2398,6 @@ func (in *WorkspaceTemplate) DeepCopyInto(out *WorkspaceTemplate) { *out = *in in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) in.Spec.DeepCopyInto(&out.Spec) - return } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkspaceTemplate. diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index fbbc12d8f3223c273c7f228195e500dbbd4cbe6c..11afa24c2dab85736f0058135b95bca2cb43a1cf 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -24,6 +24,8 @@ import ( rt "runtime" "time" + openpitrixv2alpha1 "kubesphere.io/kubesphere/pkg/kapis/openpitrix/v2alpha1" + "strconv" "github.com/emicklei/go-restful" @@ -88,7 +90,6 @@ import ( "kubesphere.io/kubesphere/pkg/simple/client/k8s" "kubesphere.io/kubesphere/pkg/simple/client/logging" "kubesphere.io/kubesphere/pkg/simple/client/monitoring" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" "kubesphere.io/kubesphere/pkg/simple/client/s3" "kubesphere.io/kubesphere/pkg/simple/client/sonarqube" "kubesphere.io/kubesphere/pkg/utils/metrics" @@ -135,9 +136,6 @@ type APIServer struct { MetricsClient monitoring.Interface - // - OpenpitrixClient openpitrix.Client - // LoggingClient logging.Client @@ -215,14 +213,15 @@ func (s *APIServer) installKubeSphereAPIs() { urlruntime.Must(configv1alpha2.AddToContainer(s.container, s.Config)) urlruntime.Must(resourcev1alpha3.AddToContainer(s.container, s.InformerFactory, s.RuntimeCache)) - urlruntime.Must(monitoringv1alpha3.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.MonitoringClient, s.MetricsClient, s.InformerFactory, s.OpenpitrixClient)) - urlruntime.Must(meteringv1alpha1.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.MonitoringClient, s.InformerFactory, s.OpenpitrixClient, s.RuntimeCache)) - urlruntime.Must(openpitrixv1.AddToContainer(s.container, s.InformerFactory, s.OpenpitrixClient)) + urlruntime.Must(monitoringv1alpha3.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.MonitoringClient, s.MetricsClient, s.InformerFactory)) + urlruntime.Must(meteringv1alpha1.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.MonitoringClient, s.InformerFactory, s.RuntimeCache)) + urlruntime.Must(openpitrixv1.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.KubeSphere(), s.Config.OpenPitrixOptions)) + urlruntime.Must(openpitrixv2alpha1.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.KubeSphere(), s.Config.OpenPitrixOptions)) urlruntime.Must(operationsv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes())) urlruntime.Must(resourcesv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.InformerFactory, s.KubernetesClient.Master())) urlruntime.Must(tenantv1alpha2.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.Kubernetes(), - s.KubernetesClient.KubeSphere(), s.EventsClient, s.LoggingClient, s.AuditingClient, amOperator, rbacAuthorizer, s.MonitoringClient, s.OpenpitrixClient, s.RuntimeCache)) + s.KubernetesClient.KubeSphere(), s.EventsClient, s.LoggingClient, s.AuditingClient, amOperator, rbacAuthorizer, s.MonitoringClient, s.RuntimeCache)) urlruntime.Must(terminalv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.KubernetesClient.Config())) urlruntime.Must(clusterkapisv1alpha1.AddToContainer(s.container, s.InformerFactory.KubernetesSharedInformerFactory(), @@ -338,8 +337,7 @@ func (s *APIServer) buildHandlerChain(stopCh <-chan struct{}) { handler = filters.WithAuthorization(handler, authorizers) if s.Config.MultiClusterOptions.Enable { - clusterDispatcher := dispatch.NewClusterDispatch(s.InformerFactory.KubeSphereSharedInformerFactory().Cluster().V1alpha1().Clusters(), - s.InformerFactory.KubeSphereSharedInformerFactory().Cluster().V1alpha1().Clusters().Lister()) + clusterDispatcher := dispatch.NewClusterDispatch(s.InformerFactory.KubeSphereSharedInformerFactory().Cluster().V1alpha1().Clusters()) handler = filters.WithMultipleClusterDispatcher(handler, clusterDispatcher) } diff --git a/pkg/apiserver/config/config.go b/pkg/apiserver/config/config.go index 41a7b99c9e59f5eeac21a339a34e947ca8d069e8..16ebc9749d8132dfd8f505e9a4121965d13fb254 100644 --- a/pkg/apiserver/config/config.go +++ b/pkg/apiserver/config/config.go @@ -196,6 +196,14 @@ func (conf *Config) ToMap() map[string]bool { continue } + if name == "openpitrix" { + if conf.OpenPitrixOptions.IsEmpty() { + result["openpitrix.appstore"] = false + } else { + result["openpitrix.appstore"] = true + } + } + if c.Field(i).IsNil() { result[name] = false } else { diff --git a/pkg/apiserver/config/config_test.go b/pkg/apiserver/config/config_test.go index fc572f47bc5ff7799c634e91e191f21168535716..f12fba689e50f5e0afa565193593ad49b351949c 100644 --- a/pkg/apiserver/config/config_test.go +++ b/pkg/apiserver/config/config_test.go @@ -94,12 +94,16 @@ func newTestConfig() (*Config, error) { Bucket: "ssss", }, OpenPitrixOptions: &openpitrix.Options{ - RuntimeManagerEndpoint: "openpitrix-hyperpitrix.openpitrix-system.svc:9103", - ClusterManagerEndpoint: "openpitrix-hyperpitrix.openpitrix-system.svc:9104", - RepoManagerEndpoint: "openpitrix-hyperpitrix.openpitrix-system.svc:9101", - AppManagerEndpoint: "openpitrix-hyperpitrix.openpitrix-system.svc:9102", - CategoryManagerEndpoint: "openpitrix-hyperpitrix.openpitrix-system.svc:9113", - AttachmentManagerEndpoint: "openpitrix-hyperpitrix.openpitrix-system.svc:9122", + S3Options: &s3.Options{ + Endpoint: "http://minio.openpitrix-system.svc", + Region: "", + DisableSSL: false, + ForcePathStyle: false, + AccessKeyID: "ABCDEFGHIJKLMN", + SecretAccessKey: "OPQRSTUVWXYZ", + SessionToken: "abcdefghijklmn", + Bucket: "app", + }, }, NetworkOptions: &network.Options{ EnableNetworkPolicy: true, diff --git a/pkg/apiserver/dispatch/dispatch.go b/pkg/apiserver/dispatch/dispatch.go index 1d8465b1a38eac32b77cf4e95a9e6b1a6ee5274d..7241113e4ef366118d5951477de5d3041bff535c 100644 --- a/pkg/apiserver/dispatch/dispatch.go +++ b/pkg/apiserver/dispatch/dispatch.go @@ -18,25 +18,18 @@ package dispatch import ( "fmt" - "net/http" - "net/url" - "strings" - "sync" - - corev1 "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/api/errors" "k8s.io/apimachinery/pkg/util/httpstream" "k8s.io/apimachinery/pkg/util/proxy" "k8s.io/apiserver/pkg/endpoints/handlers/responsewriters" - "k8s.io/client-go/rest" - "k8s.io/client-go/tools/cache" - "k8s.io/client-go/tools/clientcmd" "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/utils/clusterclient" + "net/http" + "strings" clusterv1alpha1 "kubesphere.io/kubesphere/pkg/apis/cluster/v1alpha1" "kubesphere.io/kubesphere/pkg/apiserver/request" clusterinformer "kubesphere.io/kubesphere/pkg/client/informers/externalversions/cluster/v1alpha1" - clusterlister "kubesphere.io/kubesphere/pkg/client/listers/cluster/v1alpha1" ) const proxyURLFormat = "/api/v1/namespaces/kubesphere-system/services/:ks-apiserver:/proxy%s" @@ -48,48 +41,12 @@ type Dispatcher interface { Dispatch(w http.ResponseWriter, req *http.Request, handler http.Handler) } -type innerCluster struct { - kubernetesURL *url.URL - kubesphereURL *url.URL - transport http.RoundTripper -} - type clusterDispatch struct { - clusterLister clusterlister.ClusterLister - - // dispatcher will build a in memory cluster cache to speed things up - innerClusters map[string]*innerCluster - - clusterInformerSynced cache.InformerSynced - - mutex sync.RWMutex + clusterclient.ClusterClients } -func NewClusterDispatch(clusterInformer clusterinformer.ClusterInformer, clusterLister clusterlister.ClusterLister) Dispatcher { - clusterDispatcher := &clusterDispatch{ - clusterLister: clusterLister, - innerClusters: make(map[string]*innerCluster), - mutex: sync.RWMutex{}, - } - - clusterDispatcher.clusterInformerSynced = clusterInformer.Informer().HasSynced - clusterInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ - AddFunc: clusterDispatcher.updateInnerClusters, - UpdateFunc: func(oldObj, newObj interface{}) { - clusterDispatcher.updateInnerClusters(newObj) - }, - DeleteFunc: func(obj interface{}) { - cluster := obj.(*clusterv1alpha1.Cluster) - clusterDispatcher.mutex.Lock() - if _, ok := clusterDispatcher.innerClusters[cluster.Name]; ok { - delete(clusterDispatcher.innerClusters, cluster.Name) - } - clusterDispatcher.mutex.Unlock() - - }, - }) - - return clusterDispatcher +func NewClusterDispatch(clusterInformer clusterinformer.ClusterInformer) Dispatcher { + return &clusterDispatch{clusterclient.NewClusterClient(clusterInformer)} } // Dispatch dispatch requests to designated cluster @@ -102,7 +59,7 @@ func (c *clusterDispatch) Dispatch(w http.ResponseWriter, req *http.Request, han return } - cluster, err := c.clusterLister.Get(info.Cluster) + cluster, err := c.Get(info.Cluster) if err != nil { if errors.IsNotFound(err) { http.Error(w, fmt.Sprintf("cluster %s not found", info.Cluster), http.StatusNotFound) @@ -113,18 +70,18 @@ func (c *clusterDispatch) Dispatch(w http.ResponseWriter, req *http.Request, han } // request cluster is host cluster, no need go through agent - if isClusterHostCluster(cluster) { + if c.IsHostCluster(cluster) { req.URL.Path = strings.Replace(req.URL.Path, fmt.Sprintf("/clusters/%s", info.Cluster), "", 1) handler.ServeHTTP(w, req) return } - if !isClusterReady(cluster) { + if !c.IsClusterReady(cluster) { http.Error(w, fmt.Sprintf("cluster %s is not ready", cluster.Name), http.StatusInternalServerError) return } - innCluster := c.getInnerCluster(cluster.Name) + innCluster := c.GetInnerCluster(cluster.Name) if innCluster == nil { http.Error(w, fmt.Sprintf("cluster %s is not ready", cluster.Name), http.StatusInternalServerError) return @@ -141,10 +98,10 @@ func (c *clusterDispatch) Dispatch(w http.ResponseWriter, req *http.Request, han if cluster.Spec.Connection.Type == clusterv1alpha1.ConnectionTypeDirect && len(cluster.Spec.Connection.KubeSphereAPIEndpoint) == 0 { - u.Scheme = innCluster.kubernetesURL.Scheme - u.Host = innCluster.kubernetesURL.Host + u.Scheme = innCluster.KubernetesURL.Scheme + u.Host = innCluster.KubernetesURL.Host u.Path = fmt.Sprintf(proxyURLFormat, u.Path) - transport = innCluster.transport + transport = innCluster.Transport // The reason we need this is kube-apiserver doesn't behave like a standard proxy, it will strip // authorization header of proxy requests. Use custom header to avoid stripping by kube-apiserver. @@ -178,8 +135,8 @@ func (c *clusterDispatch) Dispatch(w http.ResponseWriter, req *http.Request, han } else { // everything else goes to ks-apiserver, since our ks-apiserver has the ability to proxy kube-apiserver requests - u.Host = innCluster.kubesphereURL.Host - u.Scheme = innCluster.kubesphereURL.Scheme + u.Host = innCluster.KubesphereURL.Host + u.Scheme = innCluster.KubesphereURL.Scheme } httpProxy := proxy.NewUpgradeAwareHandler(&u, transport, false, false, c) @@ -190,73 +147,3 @@ func (c *clusterDispatch) Dispatch(w http.ResponseWriter, req *http.Request, han func (c *clusterDispatch) Error(w http.ResponseWriter, req *http.Request, err error) { responsewriters.InternalError(w, req, err) } - -func (c *clusterDispatch) getInnerCluster(name string) *innerCluster { - c.mutex.RLock() - defer c.mutex.RUnlock() - if cluster, ok := c.innerClusters[name]; ok { - return cluster - } - return nil -} - -func (c *clusterDispatch) updateInnerClusters(obj interface{}) { - cluster := obj.(*clusterv1alpha1.Cluster) - - kubernetesEndpoint, err := url.Parse(cluster.Spec.Connection.KubernetesAPIEndpoint) - if err != nil { - klog.Errorf("Parse kubernetes apiserver endpoint %s failed, %v", cluster.Spec.Connection.KubernetesAPIEndpoint, err) - return - } - - kubesphereEndpoint, err := url.Parse(cluster.Spec.Connection.KubeSphereAPIEndpoint) - if err != nil { - klog.Errorf("Parse kubesphere apiserver endpoint %s failed, %v", cluster.Spec.Connection.KubeSphereAPIEndpoint, err) - return - } - - // prepare for - clientConfig, err := clientcmd.NewClientConfigFromBytes(cluster.Spec.Connection.KubeConfig) - if err != nil { - klog.Errorf("Unable to create client config from kubeconfig bytes, %#v", err) - return - } - - clusterConfig, err := clientConfig.ClientConfig() - if err != nil { - klog.Errorf("Failed to get client config, %#v", err) - return - } - - transport, err := rest.TransportFor(clusterConfig) - if err != nil { - klog.Errorf("Create transport failed, %v", err) - return - } - - c.mutex.Lock() - c.innerClusters[cluster.Name] = &innerCluster{ - kubernetesURL: kubernetesEndpoint, - kubesphereURL: kubesphereEndpoint, - transport: transport, - } - c.mutex.Unlock() -} - -func isClusterReady(cluster *clusterv1alpha1.Cluster) bool { - for _, condition := range cluster.Status.Conditions { - if condition.Type == clusterv1alpha1.ClusterReady && condition.Status == corev1.ConditionTrue { - return true - } - } - - return false -} - -func isClusterHostCluster(cluster *clusterv1alpha1.Cluster) bool { - if _, ok := cluster.Labels[clusterv1alpha1.HostCluster]; ok { - return true - } - - return false -} diff --git a/pkg/apiserver/runtime/runtime.go b/pkg/apiserver/runtime/runtime.go index 453241ecadbba93c566bb4b8c07d7618f3c0a6a2..bb98f772bf05a23ae4927b328b800fa55f732c1a 100644 --- a/pkg/apiserver/runtime/runtime.go +++ b/pkg/apiserver/runtime/runtime.go @@ -32,6 +32,7 @@ type ContainerBuilder []func(c *restful.Container) error const MimeMergePatchJson = "application/merge-patch+json" const MimeJsonPatchJson = "application/json-patch+json" +const MimeMultipartFormData = "multipart/form-data" func init() { restful.RegisterEntityAccessor(MimeMergePatchJson, restful.NewEntityAccessorJSON(restful.MIME_JSON)) diff --git a/pkg/client/clientset/versioned/clientset.go b/pkg/client/clientset/versioned/clientset.go index 6537fe1dfa4f251b20e48b7c7c5037817012489e..48f01b5c6fef19b33e3626ecd90213284ada82ba 100644 --- a/pkg/client/clientset/versioned/clientset.go +++ b/pkg/client/clientset/versioned/clientset.go @@ -24,6 +24,7 @@ import ( discovery "k8s.io/client-go/discovery" rest "k8s.io/client-go/rest" flowcontrol "k8s.io/client-go/util/flowcontrol" + applicationv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/application/v1alpha1" auditingv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/auditing/v1alpha1" clusterv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/cluster/v1alpha1" devopsv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/devops/v1alpha1" @@ -40,6 +41,7 @@ import ( type Interface interface { Discovery() discovery.DiscoveryInterface + ApplicationV1alpha1() applicationv1alpha1.ApplicationV1alpha1Interface AuditingV1alpha1() auditingv1alpha1.AuditingV1alpha1Interface ClusterV1alpha1() clusterv1alpha1.ClusterV1alpha1Interface DevopsV1alpha1() devopsv1alpha1.DevopsV1alpha1Interface @@ -58,6 +60,7 @@ type Interface interface { // version included in a Clientset. type Clientset struct { *discovery.DiscoveryClient + applicationV1alpha1 *applicationv1alpha1.ApplicationV1alpha1Client auditingV1alpha1 *auditingv1alpha1.AuditingV1alpha1Client clusterV1alpha1 *clusterv1alpha1.ClusterV1alpha1Client devopsV1alpha1 *devopsv1alpha1.DevopsV1alpha1Client @@ -72,6 +75,11 @@ type Clientset struct { typesV1beta1 *typesv1beta1.TypesV1beta1Client } +// ApplicationV1alpha1 retrieves the ApplicationV1alpha1Client +func (c *Clientset) ApplicationV1alpha1() applicationv1alpha1.ApplicationV1alpha1Interface { + return c.applicationV1alpha1 +} + // AuditingV1alpha1 retrieves the AuditingV1alpha1Client func (c *Clientset) AuditingV1alpha1() auditingv1alpha1.AuditingV1alpha1Interface { return c.auditingV1alpha1 @@ -153,6 +161,10 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { } var cs Clientset var err error + cs.applicationV1alpha1, err = applicationv1alpha1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } cs.auditingV1alpha1, err = auditingv1alpha1.NewForConfig(&configShallowCopy) if err != nil { return nil, err @@ -213,6 +225,7 @@ func NewForConfig(c *rest.Config) (*Clientset, error) { // panics if there is an error in the config. func NewForConfigOrDie(c *rest.Config) *Clientset { var cs Clientset + cs.applicationV1alpha1 = applicationv1alpha1.NewForConfigOrDie(c) cs.auditingV1alpha1 = auditingv1alpha1.NewForConfigOrDie(c) cs.clusterV1alpha1 = clusterv1alpha1.NewForConfigOrDie(c) cs.devopsV1alpha1 = devopsv1alpha1.NewForConfigOrDie(c) @@ -233,6 +246,7 @@ func NewForConfigOrDie(c *rest.Config) *Clientset { // New creates a new Clientset for the given RESTClient. func New(c rest.Interface) *Clientset { var cs Clientset + cs.applicationV1alpha1 = applicationv1alpha1.New(c) cs.auditingV1alpha1 = auditingv1alpha1.New(c) cs.clusterV1alpha1 = clusterv1alpha1.New(c) cs.devopsV1alpha1 = devopsv1alpha1.New(c) diff --git a/pkg/client/clientset/versioned/fake/clientset_generated.go b/pkg/client/clientset/versioned/fake/clientset_generated.go index b13a4bd001c3368314fd949eaadade6b97ce3e27..1bb7bd111aa2ad0bf4a51e726381534e49206189 100644 --- a/pkg/client/clientset/versioned/fake/clientset_generated.go +++ b/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -25,6 +25,8 @@ import ( fakediscovery "k8s.io/client-go/discovery/fake" "k8s.io/client-go/testing" clientset "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + applicationv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/application/v1alpha1" + fakeapplicationv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/application/v1alpha1/fake" auditingv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/auditing/v1alpha1" fakeauditingv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/auditing/v1alpha1/fake" clusterv1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/cluster/v1alpha1" @@ -98,6 +100,11 @@ func (c *Clientset) Tracker() testing.ObjectTracker { var _ clientset.Interface = &Clientset{} +// ApplicationV1alpha1 retrieves the ApplicationV1alpha1Client +func (c *Clientset) ApplicationV1alpha1() applicationv1alpha1.ApplicationV1alpha1Interface { + return &fakeapplicationv1alpha1.FakeApplicationV1alpha1{Fake: &c.Fake} +} + // AuditingV1alpha1 retrieves the AuditingV1alpha1Client func (c *Clientset) AuditingV1alpha1() auditingv1alpha1.AuditingV1alpha1Interface { return &fakeauditingv1alpha1.FakeAuditingV1alpha1{Fake: &c.Fake} diff --git a/pkg/client/clientset/versioned/fake/register.go b/pkg/client/clientset/versioned/fake/register.go index eb9569f56d5be4237bd12e434958c8e9ad13a708..3a529a6c8a2edaceed00d7c0285f00b06852c0b6 100644 --- a/pkg/client/clientset/versioned/fake/register.go +++ b/pkg/client/clientset/versioned/fake/register.go @@ -24,6 +24,7 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + applicationv1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" auditingv1alpha1 "kubesphere.io/kubesphere/pkg/apis/auditing/v1alpha1" clusterv1alpha1 "kubesphere.io/kubesphere/pkg/apis/cluster/v1alpha1" devopsv1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1" @@ -42,6 +43,7 @@ var scheme = runtime.NewScheme() var codecs = serializer.NewCodecFactory(scheme) var parameterCodec = runtime.NewParameterCodec(scheme) var localSchemeBuilder = runtime.SchemeBuilder{ + applicationv1alpha1.AddToScheme, auditingv1alpha1.AddToScheme, clusterv1alpha1.AddToScheme, devopsv1alpha1.AddToScheme, diff --git a/pkg/client/clientset/versioned/scheme/register.go b/pkg/client/clientset/versioned/scheme/register.go index 28002f8f309c0c1eebf08b9879c0b7441f90ed6d..b366e23331ea9f6a1b6d32620bc60985aa3e8b75 100644 --- a/pkg/client/clientset/versioned/scheme/register.go +++ b/pkg/client/clientset/versioned/scheme/register.go @@ -24,6 +24,7 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" serializer "k8s.io/apimachinery/pkg/runtime/serializer" utilruntime "k8s.io/apimachinery/pkg/util/runtime" + applicationv1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" auditingv1alpha1 "kubesphere.io/kubesphere/pkg/apis/auditing/v1alpha1" clusterv1alpha1 "kubesphere.io/kubesphere/pkg/apis/cluster/v1alpha1" devopsv1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1" @@ -42,6 +43,7 @@ var Scheme = runtime.NewScheme() var Codecs = serializer.NewCodecFactory(Scheme) var ParameterCodec = runtime.NewParameterCodec(Scheme) var localSchemeBuilder = runtime.SchemeBuilder{ + applicationv1alpha1.AddToScheme, auditingv1alpha1.AddToScheme, clusterv1alpha1.AddToScheme, devopsv1alpha1.AddToScheme, diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/application_client.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/application_client.go new file mode 100644 index 0000000000000000000000000000000000000000..843b37cff09cc4fa901ece11207f01d831fa26aa --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/application_client.go @@ -0,0 +1,109 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + rest "k8s.io/client-go/rest" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +type ApplicationV1alpha1Interface interface { + RESTClient() rest.Interface + HelmApplicationsGetter + HelmApplicationVersionsGetter + HelmCategoriesGetter + HelmReleasesGetter + HelmReposGetter +} + +// ApplicationV1alpha1Client is used to interact with features provided by the application.kubesphere.io group. +type ApplicationV1alpha1Client struct { + restClient rest.Interface +} + +func (c *ApplicationV1alpha1Client) HelmApplications() HelmApplicationInterface { + return newHelmApplications(c) +} + +func (c *ApplicationV1alpha1Client) HelmApplicationVersions() HelmApplicationVersionInterface { + return newHelmApplicationVersions(c) +} + +func (c *ApplicationV1alpha1Client) HelmCategories() HelmCategoryInterface { + return newHelmCategories(c) +} + +func (c *ApplicationV1alpha1Client) HelmReleases() HelmReleaseInterface { + return newHelmReleases(c) +} + +func (c *ApplicationV1alpha1Client) HelmRepos() HelmRepoInterface { + return newHelmRepos(c) +} + +// NewForConfig creates a new ApplicationV1alpha1Client for the given config. +func NewForConfig(c *rest.Config) (*ApplicationV1alpha1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &ApplicationV1alpha1Client{client}, nil +} + +// NewForConfigOrDie creates a new ApplicationV1alpha1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *ApplicationV1alpha1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new ApplicationV1alpha1Client for the given RESTClient. +func New(c rest.Interface) *ApplicationV1alpha1Client { + return &ApplicationV1alpha1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1alpha1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = scheme.Codecs.WithoutConversion() + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *ApplicationV1alpha1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/doc.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/doc.go new file mode 100644 index 0000000000000000000000000000000000000000..769278743f5e4430793280a619ed2b446d971c9e --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1alpha1 diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/doc.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/doc.go new file mode 100644 index 0000000000000000000000000000000000000000..7e36dbca87adb21bcb79573d414617f117fb550e --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/doc.go @@ -0,0 +1,20 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_application_client.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_application_client.go new file mode 100644 index 0000000000000000000000000000000000000000..ffbbdd7cad4f2bd8f9d6982d89f14115d4e38e36 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_application_client.go @@ -0,0 +1,56 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" + v1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/application/v1alpha1" +) + +type FakeApplicationV1alpha1 struct { + *testing.Fake +} + +func (c *FakeApplicationV1alpha1) HelmApplications() v1alpha1.HelmApplicationInterface { + return &FakeHelmApplications{c} +} + +func (c *FakeApplicationV1alpha1) HelmApplicationVersions() v1alpha1.HelmApplicationVersionInterface { + return &FakeHelmApplicationVersions{c} +} + +func (c *FakeApplicationV1alpha1) HelmCategories() v1alpha1.HelmCategoryInterface { + return &FakeHelmCategories{c} +} + +func (c *FakeApplicationV1alpha1) HelmReleases() v1alpha1.HelmReleaseInterface { + return &FakeHelmReleases{c} +} + +func (c *FakeApplicationV1alpha1) HelmRepos() v1alpha1.HelmRepoInterface { + return &FakeHelmRepos{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeApplicationV1alpha1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmapplication.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmapplication.go new file mode 100644 index 0000000000000000000000000000000000000000..ee41b5c05f2b9febf2939ca8c7a476e347ce72bb --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmapplication.go @@ -0,0 +1,133 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" +) + +// FakeHelmApplications implements HelmApplicationInterface +type FakeHelmApplications struct { + Fake *FakeApplicationV1alpha1 +} + +var helmapplicationsResource = schema.GroupVersionResource{Group: "application.kubesphere.io", Version: "v1alpha1", Resource: "helmapplications"} + +var helmapplicationsKind = schema.GroupVersionKind{Group: "application.kubesphere.io", Version: "v1alpha1", Kind: "HelmApplication"} + +// Get takes name of the helmApplication, and returns the corresponding helmApplication object, and an error if there is any. +func (c *FakeHelmApplications) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.HelmApplication, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(helmapplicationsResource, name), &v1alpha1.HelmApplication{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmApplication), err +} + +// List takes label and field selectors, and returns the list of HelmApplications that match those selectors. +func (c *FakeHelmApplications) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.HelmApplicationList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(helmapplicationsResource, helmapplicationsKind, opts), &v1alpha1.HelmApplicationList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.HelmApplicationList{ListMeta: obj.(*v1alpha1.HelmApplicationList).ListMeta} + for _, item := range obj.(*v1alpha1.HelmApplicationList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested helmApplications. +func (c *FakeHelmApplications) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(helmapplicationsResource, opts)) +} + +// Create takes the representation of a helmApplication and creates it. Returns the server's representation of the helmApplication, and an error, if there is any. +func (c *FakeHelmApplications) Create(ctx context.Context, helmApplication *v1alpha1.HelmApplication, opts v1.CreateOptions) (result *v1alpha1.HelmApplication, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(helmapplicationsResource, helmApplication), &v1alpha1.HelmApplication{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmApplication), err +} + +// Update takes the representation of a helmApplication and updates it. Returns the server's representation of the helmApplication, and an error, if there is any. +func (c *FakeHelmApplications) Update(ctx context.Context, helmApplication *v1alpha1.HelmApplication, opts v1.UpdateOptions) (result *v1alpha1.HelmApplication, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(helmapplicationsResource, helmApplication), &v1alpha1.HelmApplication{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmApplication), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeHelmApplications) UpdateStatus(ctx context.Context, helmApplication *v1alpha1.HelmApplication, opts v1.UpdateOptions) (*v1alpha1.HelmApplication, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(helmapplicationsResource, "status", helmApplication), &v1alpha1.HelmApplication{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmApplication), err +} + +// Delete takes name of the helmApplication and deletes it. Returns an error if one occurs. +func (c *FakeHelmApplications) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(helmapplicationsResource, name), &v1alpha1.HelmApplication{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeHelmApplications) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(helmapplicationsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.HelmApplicationList{}) + return err +} + +// Patch applies the patch and returns the patched helmApplication. +func (c *FakeHelmApplications) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmApplication, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(helmapplicationsResource, name, pt, data, subresources...), &v1alpha1.HelmApplication{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmApplication), err +} diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmapplicationversion.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmapplicationversion.go new file mode 100644 index 0000000000000000000000000000000000000000..b99f6f728ce71f650aeeb318caed0185dc0a40c2 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmapplicationversion.go @@ -0,0 +1,133 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" +) + +// FakeHelmApplicationVersions implements HelmApplicationVersionInterface +type FakeHelmApplicationVersions struct { + Fake *FakeApplicationV1alpha1 +} + +var helmapplicationversionsResource = schema.GroupVersionResource{Group: "application.kubesphere.io", Version: "v1alpha1", Resource: "helmapplicationversions"} + +var helmapplicationversionsKind = schema.GroupVersionKind{Group: "application.kubesphere.io", Version: "v1alpha1", Kind: "HelmApplicationVersion"} + +// Get takes name of the helmApplicationVersion, and returns the corresponding helmApplicationVersion object, and an error if there is any. +func (c *FakeHelmApplicationVersions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.HelmApplicationVersion, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(helmapplicationversionsResource, name), &v1alpha1.HelmApplicationVersion{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmApplicationVersion), err +} + +// List takes label and field selectors, and returns the list of HelmApplicationVersions that match those selectors. +func (c *FakeHelmApplicationVersions) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.HelmApplicationVersionList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(helmapplicationversionsResource, helmapplicationversionsKind, opts), &v1alpha1.HelmApplicationVersionList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.HelmApplicationVersionList{ListMeta: obj.(*v1alpha1.HelmApplicationVersionList).ListMeta} + for _, item := range obj.(*v1alpha1.HelmApplicationVersionList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested helmApplicationVersions. +func (c *FakeHelmApplicationVersions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(helmapplicationversionsResource, opts)) +} + +// Create takes the representation of a helmApplicationVersion and creates it. Returns the server's representation of the helmApplicationVersion, and an error, if there is any. +func (c *FakeHelmApplicationVersions) Create(ctx context.Context, helmApplicationVersion *v1alpha1.HelmApplicationVersion, opts v1.CreateOptions) (result *v1alpha1.HelmApplicationVersion, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(helmapplicationversionsResource, helmApplicationVersion), &v1alpha1.HelmApplicationVersion{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmApplicationVersion), err +} + +// Update takes the representation of a helmApplicationVersion and updates it. Returns the server's representation of the helmApplicationVersion, and an error, if there is any. +func (c *FakeHelmApplicationVersions) Update(ctx context.Context, helmApplicationVersion *v1alpha1.HelmApplicationVersion, opts v1.UpdateOptions) (result *v1alpha1.HelmApplicationVersion, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(helmapplicationversionsResource, helmApplicationVersion), &v1alpha1.HelmApplicationVersion{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmApplicationVersion), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeHelmApplicationVersions) UpdateStatus(ctx context.Context, helmApplicationVersion *v1alpha1.HelmApplicationVersion, opts v1.UpdateOptions) (*v1alpha1.HelmApplicationVersion, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(helmapplicationversionsResource, "status", helmApplicationVersion), &v1alpha1.HelmApplicationVersion{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmApplicationVersion), err +} + +// Delete takes name of the helmApplicationVersion and deletes it. Returns an error if one occurs. +func (c *FakeHelmApplicationVersions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(helmapplicationversionsResource, name), &v1alpha1.HelmApplicationVersion{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeHelmApplicationVersions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(helmapplicationversionsResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.HelmApplicationVersionList{}) + return err +} + +// Patch applies the patch and returns the patched helmApplicationVersion. +func (c *FakeHelmApplicationVersions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmApplicationVersion, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(helmapplicationversionsResource, name, pt, data, subresources...), &v1alpha1.HelmApplicationVersion{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmApplicationVersion), err +} diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmcategory.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmcategory.go new file mode 100644 index 0000000000000000000000000000000000000000..9ca22e44b96f6d10d2823f20963a350b76632a5e --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmcategory.go @@ -0,0 +1,133 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" +) + +// FakeHelmCategories implements HelmCategoryInterface +type FakeHelmCategories struct { + Fake *FakeApplicationV1alpha1 +} + +var helmcategoriesResource = schema.GroupVersionResource{Group: "application.kubesphere.io", Version: "v1alpha1", Resource: "helmcategories"} + +var helmcategoriesKind = schema.GroupVersionKind{Group: "application.kubesphere.io", Version: "v1alpha1", Kind: "HelmCategory"} + +// Get takes name of the helmCategory, and returns the corresponding helmCategory object, and an error if there is any. +func (c *FakeHelmCategories) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.HelmCategory, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(helmcategoriesResource, name), &v1alpha1.HelmCategory{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmCategory), err +} + +// List takes label and field selectors, and returns the list of HelmCategories that match those selectors. +func (c *FakeHelmCategories) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.HelmCategoryList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(helmcategoriesResource, helmcategoriesKind, opts), &v1alpha1.HelmCategoryList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.HelmCategoryList{ListMeta: obj.(*v1alpha1.HelmCategoryList).ListMeta} + for _, item := range obj.(*v1alpha1.HelmCategoryList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested helmCategories. +func (c *FakeHelmCategories) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(helmcategoriesResource, opts)) +} + +// Create takes the representation of a helmCategory and creates it. Returns the server's representation of the helmCategory, and an error, if there is any. +func (c *FakeHelmCategories) Create(ctx context.Context, helmCategory *v1alpha1.HelmCategory, opts v1.CreateOptions) (result *v1alpha1.HelmCategory, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(helmcategoriesResource, helmCategory), &v1alpha1.HelmCategory{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmCategory), err +} + +// Update takes the representation of a helmCategory and updates it. Returns the server's representation of the helmCategory, and an error, if there is any. +func (c *FakeHelmCategories) Update(ctx context.Context, helmCategory *v1alpha1.HelmCategory, opts v1.UpdateOptions) (result *v1alpha1.HelmCategory, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(helmcategoriesResource, helmCategory), &v1alpha1.HelmCategory{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmCategory), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeHelmCategories) UpdateStatus(ctx context.Context, helmCategory *v1alpha1.HelmCategory, opts v1.UpdateOptions) (*v1alpha1.HelmCategory, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(helmcategoriesResource, "status", helmCategory), &v1alpha1.HelmCategory{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmCategory), err +} + +// Delete takes name of the helmCategory and deletes it. Returns an error if one occurs. +func (c *FakeHelmCategories) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(helmcategoriesResource, name), &v1alpha1.HelmCategory{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeHelmCategories) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(helmcategoriesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.HelmCategoryList{}) + return err +} + +// Patch applies the patch and returns the patched helmCategory. +func (c *FakeHelmCategories) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmCategory, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(helmcategoriesResource, name, pt, data, subresources...), &v1alpha1.HelmCategory{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmCategory), err +} diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmrelease.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmrelease.go new file mode 100644 index 0000000000000000000000000000000000000000..07bd364ff54d89143c95c5bb6d2294e30476946b --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmrelease.go @@ -0,0 +1,133 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" +) + +// FakeHelmReleases implements HelmReleaseInterface +type FakeHelmReleases struct { + Fake *FakeApplicationV1alpha1 +} + +var helmreleasesResource = schema.GroupVersionResource{Group: "application.kubesphere.io", Version: "v1alpha1", Resource: "helmreleases"} + +var helmreleasesKind = schema.GroupVersionKind{Group: "application.kubesphere.io", Version: "v1alpha1", Kind: "HelmRelease"} + +// Get takes name of the helmRelease, and returns the corresponding helmRelease object, and an error if there is any. +func (c *FakeHelmReleases) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.HelmRelease, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(helmreleasesResource, name), &v1alpha1.HelmRelease{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmRelease), err +} + +// List takes label and field selectors, and returns the list of HelmReleases that match those selectors. +func (c *FakeHelmReleases) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.HelmReleaseList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(helmreleasesResource, helmreleasesKind, opts), &v1alpha1.HelmReleaseList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.HelmReleaseList{ListMeta: obj.(*v1alpha1.HelmReleaseList).ListMeta} + for _, item := range obj.(*v1alpha1.HelmReleaseList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested helmReleases. +func (c *FakeHelmReleases) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(helmreleasesResource, opts)) +} + +// Create takes the representation of a helmRelease and creates it. Returns the server's representation of the helmRelease, and an error, if there is any. +func (c *FakeHelmReleases) Create(ctx context.Context, helmRelease *v1alpha1.HelmRelease, opts v1.CreateOptions) (result *v1alpha1.HelmRelease, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(helmreleasesResource, helmRelease), &v1alpha1.HelmRelease{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmRelease), err +} + +// Update takes the representation of a helmRelease and updates it. Returns the server's representation of the helmRelease, and an error, if there is any. +func (c *FakeHelmReleases) Update(ctx context.Context, helmRelease *v1alpha1.HelmRelease, opts v1.UpdateOptions) (result *v1alpha1.HelmRelease, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(helmreleasesResource, helmRelease), &v1alpha1.HelmRelease{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmRelease), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeHelmReleases) UpdateStatus(ctx context.Context, helmRelease *v1alpha1.HelmRelease, opts v1.UpdateOptions) (*v1alpha1.HelmRelease, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(helmreleasesResource, "status", helmRelease), &v1alpha1.HelmRelease{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmRelease), err +} + +// Delete takes name of the helmRelease and deletes it. Returns an error if one occurs. +func (c *FakeHelmReleases) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(helmreleasesResource, name), &v1alpha1.HelmRelease{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeHelmReleases) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(helmreleasesResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.HelmReleaseList{}) + return err +} + +// Patch applies the patch and returns the patched helmRelease. +func (c *FakeHelmReleases) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmRelease, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(helmreleasesResource, name, pt, data, subresources...), &v1alpha1.HelmRelease{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmRelease), err +} diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmrepo.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmrepo.go new file mode 100644 index 0000000000000000000000000000000000000000..38f9f3cf5280d96e296ff8bb0bbee9c1cc12258c --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/fake/fake_helmrepo.go @@ -0,0 +1,133 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package fake + +import ( + "context" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" +) + +// FakeHelmRepos implements HelmRepoInterface +type FakeHelmRepos struct { + Fake *FakeApplicationV1alpha1 +} + +var helmreposResource = schema.GroupVersionResource{Group: "application.kubesphere.io", Version: "v1alpha1", Resource: "helmrepos"} + +var helmreposKind = schema.GroupVersionKind{Group: "application.kubesphere.io", Version: "v1alpha1", Kind: "HelmRepo"} + +// Get takes name of the helmRepo, and returns the corresponding helmRepo object, and an error if there is any. +func (c *FakeHelmRepos) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.HelmRepo, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(helmreposResource, name), &v1alpha1.HelmRepo{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmRepo), err +} + +// List takes label and field selectors, and returns the list of HelmRepos that match those selectors. +func (c *FakeHelmRepos) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.HelmRepoList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(helmreposResource, helmreposKind, opts), &v1alpha1.HelmRepoList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &v1alpha1.HelmRepoList{ListMeta: obj.(*v1alpha1.HelmRepoList).ListMeta} + for _, item := range obj.(*v1alpha1.HelmRepoList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested helmRepos. +func (c *FakeHelmRepos) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(helmreposResource, opts)) +} + +// Create takes the representation of a helmRepo and creates it. Returns the server's representation of the helmRepo, and an error, if there is any. +func (c *FakeHelmRepos) Create(ctx context.Context, helmRepo *v1alpha1.HelmRepo, opts v1.CreateOptions) (result *v1alpha1.HelmRepo, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(helmreposResource, helmRepo), &v1alpha1.HelmRepo{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmRepo), err +} + +// Update takes the representation of a helmRepo and updates it. Returns the server's representation of the helmRepo, and an error, if there is any. +func (c *FakeHelmRepos) Update(ctx context.Context, helmRepo *v1alpha1.HelmRepo, opts v1.UpdateOptions) (result *v1alpha1.HelmRepo, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(helmreposResource, helmRepo), &v1alpha1.HelmRepo{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmRepo), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeHelmRepos) UpdateStatus(ctx context.Context, helmRepo *v1alpha1.HelmRepo, opts v1.UpdateOptions) (*v1alpha1.HelmRepo, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(helmreposResource, "status", helmRepo), &v1alpha1.HelmRepo{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmRepo), err +} + +// Delete takes name of the helmRepo and deletes it. Returns an error if one occurs. +func (c *FakeHelmRepos) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(helmreposResource, name), &v1alpha1.HelmRepo{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeHelmRepos) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(helmreposResource, listOpts) + + _, err := c.Fake.Invokes(action, &v1alpha1.HelmRepoList{}) + return err +} + +// Patch applies the patch and returns the patched helmRepo. +func (c *FakeHelmRepos) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmRepo, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(helmreposResource, name, pt, data, subresources...), &v1alpha1.HelmRepo{}) + if obj == nil { + return nil, err + } + return obj.(*v1alpha1.HelmRepo), err +} diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/generated_expansion.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/generated_expansion.go new file mode 100644 index 0000000000000000000000000000000000000000..5ba851fcddd69fd5db6d1b00548ce5403c78da90 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/generated_expansion.go @@ -0,0 +1,29 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +type HelmApplicationExpansion interface{} + +type HelmApplicationVersionExpansion interface{} + +type HelmCategoryExpansion interface{} + +type HelmReleaseExpansion interface{} + +type HelmRepoExpansion interface{} diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/helmapplication.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/helmapplication.go new file mode 100644 index 0000000000000000000000000000000000000000..59f70e9f1fe4388ffdd7434668fa0738aaf7708a --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/helmapplication.go @@ -0,0 +1,184 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +// HelmApplicationsGetter has a method to return a HelmApplicationInterface. +// A group's client should implement this interface. +type HelmApplicationsGetter interface { + HelmApplications() HelmApplicationInterface +} + +// HelmApplicationInterface has methods to work with HelmApplication resources. +type HelmApplicationInterface interface { + Create(ctx context.Context, helmApplication *v1alpha1.HelmApplication, opts v1.CreateOptions) (*v1alpha1.HelmApplication, error) + Update(ctx context.Context, helmApplication *v1alpha1.HelmApplication, opts v1.UpdateOptions) (*v1alpha1.HelmApplication, error) + UpdateStatus(ctx context.Context, helmApplication *v1alpha1.HelmApplication, opts v1.UpdateOptions) (*v1alpha1.HelmApplication, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.HelmApplication, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.HelmApplicationList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmApplication, err error) + HelmApplicationExpansion +} + +// helmApplications implements HelmApplicationInterface +type helmApplications struct { + client rest.Interface +} + +// newHelmApplications returns a HelmApplications +func newHelmApplications(c *ApplicationV1alpha1Client) *helmApplications { + return &helmApplications{ + client: c.RESTClient(), + } +} + +// Get takes name of the helmApplication, and returns the corresponding helmApplication object, and an error if there is any. +func (c *helmApplications) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.HelmApplication, err error) { + result = &v1alpha1.HelmApplication{} + err = c.client.Get(). + Resource("helmapplications"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of HelmApplications that match those selectors. +func (c *helmApplications) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.HelmApplicationList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.HelmApplicationList{} + err = c.client.Get(). + Resource("helmapplications"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested helmApplications. +func (c *helmApplications) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("helmapplications"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a helmApplication and creates it. Returns the server's representation of the helmApplication, and an error, if there is any. +func (c *helmApplications) Create(ctx context.Context, helmApplication *v1alpha1.HelmApplication, opts v1.CreateOptions) (result *v1alpha1.HelmApplication, err error) { + result = &v1alpha1.HelmApplication{} + err = c.client.Post(). + Resource("helmapplications"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmApplication). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a helmApplication and updates it. Returns the server's representation of the helmApplication, and an error, if there is any. +func (c *helmApplications) Update(ctx context.Context, helmApplication *v1alpha1.HelmApplication, opts v1.UpdateOptions) (result *v1alpha1.HelmApplication, err error) { + result = &v1alpha1.HelmApplication{} + err = c.client.Put(). + Resource("helmapplications"). + Name(helmApplication.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmApplication). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *helmApplications) UpdateStatus(ctx context.Context, helmApplication *v1alpha1.HelmApplication, opts v1.UpdateOptions) (result *v1alpha1.HelmApplication, err error) { + result = &v1alpha1.HelmApplication{} + err = c.client.Put(). + Resource("helmapplications"). + Name(helmApplication.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmApplication). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the helmApplication and deletes it. Returns an error if one occurs. +func (c *helmApplications) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("helmapplications"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *helmApplications) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("helmapplications"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched helmApplication. +func (c *helmApplications) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmApplication, err error) { + result = &v1alpha1.HelmApplication{} + err = c.client.Patch(pt). + Resource("helmapplications"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/helmapplicationversion.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/helmapplicationversion.go new file mode 100644 index 0000000000000000000000000000000000000000..93af23bc6dd81579e998896301a27bd743955097 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/helmapplicationversion.go @@ -0,0 +1,184 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +// HelmApplicationVersionsGetter has a method to return a HelmApplicationVersionInterface. +// A group's client should implement this interface. +type HelmApplicationVersionsGetter interface { + HelmApplicationVersions() HelmApplicationVersionInterface +} + +// HelmApplicationVersionInterface has methods to work with HelmApplicationVersion resources. +type HelmApplicationVersionInterface interface { + Create(ctx context.Context, helmApplicationVersion *v1alpha1.HelmApplicationVersion, opts v1.CreateOptions) (*v1alpha1.HelmApplicationVersion, error) + Update(ctx context.Context, helmApplicationVersion *v1alpha1.HelmApplicationVersion, opts v1.UpdateOptions) (*v1alpha1.HelmApplicationVersion, error) + UpdateStatus(ctx context.Context, helmApplicationVersion *v1alpha1.HelmApplicationVersion, opts v1.UpdateOptions) (*v1alpha1.HelmApplicationVersion, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.HelmApplicationVersion, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.HelmApplicationVersionList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmApplicationVersion, err error) + HelmApplicationVersionExpansion +} + +// helmApplicationVersions implements HelmApplicationVersionInterface +type helmApplicationVersions struct { + client rest.Interface +} + +// newHelmApplicationVersions returns a HelmApplicationVersions +func newHelmApplicationVersions(c *ApplicationV1alpha1Client) *helmApplicationVersions { + return &helmApplicationVersions{ + client: c.RESTClient(), + } +} + +// Get takes name of the helmApplicationVersion, and returns the corresponding helmApplicationVersion object, and an error if there is any. +func (c *helmApplicationVersions) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.HelmApplicationVersion, err error) { + result = &v1alpha1.HelmApplicationVersion{} + err = c.client.Get(). + Resource("helmapplicationversions"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of HelmApplicationVersions that match those selectors. +func (c *helmApplicationVersions) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.HelmApplicationVersionList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.HelmApplicationVersionList{} + err = c.client.Get(). + Resource("helmapplicationversions"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested helmApplicationVersions. +func (c *helmApplicationVersions) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("helmapplicationversions"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a helmApplicationVersion and creates it. Returns the server's representation of the helmApplicationVersion, and an error, if there is any. +func (c *helmApplicationVersions) Create(ctx context.Context, helmApplicationVersion *v1alpha1.HelmApplicationVersion, opts v1.CreateOptions) (result *v1alpha1.HelmApplicationVersion, err error) { + result = &v1alpha1.HelmApplicationVersion{} + err = c.client.Post(). + Resource("helmapplicationversions"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmApplicationVersion). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a helmApplicationVersion and updates it. Returns the server's representation of the helmApplicationVersion, and an error, if there is any. +func (c *helmApplicationVersions) Update(ctx context.Context, helmApplicationVersion *v1alpha1.HelmApplicationVersion, opts v1.UpdateOptions) (result *v1alpha1.HelmApplicationVersion, err error) { + result = &v1alpha1.HelmApplicationVersion{} + err = c.client.Put(). + Resource("helmapplicationversions"). + Name(helmApplicationVersion.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmApplicationVersion). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *helmApplicationVersions) UpdateStatus(ctx context.Context, helmApplicationVersion *v1alpha1.HelmApplicationVersion, opts v1.UpdateOptions) (result *v1alpha1.HelmApplicationVersion, err error) { + result = &v1alpha1.HelmApplicationVersion{} + err = c.client.Put(). + Resource("helmapplicationversions"). + Name(helmApplicationVersion.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmApplicationVersion). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the helmApplicationVersion and deletes it. Returns an error if one occurs. +func (c *helmApplicationVersions) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("helmapplicationversions"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *helmApplicationVersions) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("helmapplicationversions"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched helmApplicationVersion. +func (c *helmApplicationVersions) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmApplicationVersion, err error) { + result = &v1alpha1.HelmApplicationVersion{} + err = c.client.Patch(pt). + Resource("helmapplicationversions"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/helmcategory.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/helmcategory.go new file mode 100644 index 0000000000000000000000000000000000000000..0317665e579a14f57ade8d904006ac6cb5385f24 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/helmcategory.go @@ -0,0 +1,184 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +// HelmCategoriesGetter has a method to return a HelmCategoryInterface. +// A group's client should implement this interface. +type HelmCategoriesGetter interface { + HelmCategories() HelmCategoryInterface +} + +// HelmCategoryInterface has methods to work with HelmCategory resources. +type HelmCategoryInterface interface { + Create(ctx context.Context, helmCategory *v1alpha1.HelmCategory, opts v1.CreateOptions) (*v1alpha1.HelmCategory, error) + Update(ctx context.Context, helmCategory *v1alpha1.HelmCategory, opts v1.UpdateOptions) (*v1alpha1.HelmCategory, error) + UpdateStatus(ctx context.Context, helmCategory *v1alpha1.HelmCategory, opts v1.UpdateOptions) (*v1alpha1.HelmCategory, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.HelmCategory, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.HelmCategoryList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmCategory, err error) + HelmCategoryExpansion +} + +// helmCategories implements HelmCategoryInterface +type helmCategories struct { + client rest.Interface +} + +// newHelmCategories returns a HelmCategories +func newHelmCategories(c *ApplicationV1alpha1Client) *helmCategories { + return &helmCategories{ + client: c.RESTClient(), + } +} + +// Get takes name of the helmCategory, and returns the corresponding helmCategory object, and an error if there is any. +func (c *helmCategories) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.HelmCategory, err error) { + result = &v1alpha1.HelmCategory{} + err = c.client.Get(). + Resource("helmcategories"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of HelmCategories that match those selectors. +func (c *helmCategories) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.HelmCategoryList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.HelmCategoryList{} + err = c.client.Get(). + Resource("helmcategories"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested helmCategories. +func (c *helmCategories) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("helmcategories"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a helmCategory and creates it. Returns the server's representation of the helmCategory, and an error, if there is any. +func (c *helmCategories) Create(ctx context.Context, helmCategory *v1alpha1.HelmCategory, opts v1.CreateOptions) (result *v1alpha1.HelmCategory, err error) { + result = &v1alpha1.HelmCategory{} + err = c.client.Post(). + Resource("helmcategories"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmCategory). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a helmCategory and updates it. Returns the server's representation of the helmCategory, and an error, if there is any. +func (c *helmCategories) Update(ctx context.Context, helmCategory *v1alpha1.HelmCategory, opts v1.UpdateOptions) (result *v1alpha1.HelmCategory, err error) { + result = &v1alpha1.HelmCategory{} + err = c.client.Put(). + Resource("helmcategories"). + Name(helmCategory.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmCategory). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *helmCategories) UpdateStatus(ctx context.Context, helmCategory *v1alpha1.HelmCategory, opts v1.UpdateOptions) (result *v1alpha1.HelmCategory, err error) { + result = &v1alpha1.HelmCategory{} + err = c.client.Put(). + Resource("helmcategories"). + Name(helmCategory.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmCategory). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the helmCategory and deletes it. Returns an error if one occurs. +func (c *helmCategories) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("helmcategories"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *helmCategories) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("helmcategories"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched helmCategory. +func (c *helmCategories) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmCategory, err error) { + result = &v1alpha1.HelmCategory{} + err = c.client.Patch(pt). + Resource("helmcategories"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/helmrelease.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/helmrelease.go new file mode 100644 index 0000000000000000000000000000000000000000..761c6b6df13d62d244149f7d3f4db4e72b0cce83 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/helmrelease.go @@ -0,0 +1,184 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +// HelmReleasesGetter has a method to return a HelmReleaseInterface. +// A group's client should implement this interface. +type HelmReleasesGetter interface { + HelmReleases() HelmReleaseInterface +} + +// HelmReleaseInterface has methods to work with HelmRelease resources. +type HelmReleaseInterface interface { + Create(ctx context.Context, helmRelease *v1alpha1.HelmRelease, opts v1.CreateOptions) (*v1alpha1.HelmRelease, error) + Update(ctx context.Context, helmRelease *v1alpha1.HelmRelease, opts v1.UpdateOptions) (*v1alpha1.HelmRelease, error) + UpdateStatus(ctx context.Context, helmRelease *v1alpha1.HelmRelease, opts v1.UpdateOptions) (*v1alpha1.HelmRelease, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.HelmRelease, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.HelmReleaseList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmRelease, err error) + HelmReleaseExpansion +} + +// helmReleases implements HelmReleaseInterface +type helmReleases struct { + client rest.Interface +} + +// newHelmReleases returns a HelmReleases +func newHelmReleases(c *ApplicationV1alpha1Client) *helmReleases { + return &helmReleases{ + client: c.RESTClient(), + } +} + +// Get takes name of the helmRelease, and returns the corresponding helmRelease object, and an error if there is any. +func (c *helmReleases) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.HelmRelease, err error) { + result = &v1alpha1.HelmRelease{} + err = c.client.Get(). + Resource("helmreleases"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of HelmReleases that match those selectors. +func (c *helmReleases) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.HelmReleaseList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.HelmReleaseList{} + err = c.client.Get(). + Resource("helmreleases"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested helmReleases. +func (c *helmReleases) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("helmreleases"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a helmRelease and creates it. Returns the server's representation of the helmRelease, and an error, if there is any. +func (c *helmReleases) Create(ctx context.Context, helmRelease *v1alpha1.HelmRelease, opts v1.CreateOptions) (result *v1alpha1.HelmRelease, err error) { + result = &v1alpha1.HelmRelease{} + err = c.client.Post(). + Resource("helmreleases"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmRelease). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a helmRelease and updates it. Returns the server's representation of the helmRelease, and an error, if there is any. +func (c *helmReleases) Update(ctx context.Context, helmRelease *v1alpha1.HelmRelease, opts v1.UpdateOptions) (result *v1alpha1.HelmRelease, err error) { + result = &v1alpha1.HelmRelease{} + err = c.client.Put(). + Resource("helmreleases"). + Name(helmRelease.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmRelease). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *helmReleases) UpdateStatus(ctx context.Context, helmRelease *v1alpha1.HelmRelease, opts v1.UpdateOptions) (result *v1alpha1.HelmRelease, err error) { + result = &v1alpha1.HelmRelease{} + err = c.client.Put(). + Resource("helmreleases"). + Name(helmRelease.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmRelease). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the helmRelease and deletes it. Returns an error if one occurs. +func (c *helmReleases) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("helmreleases"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *helmReleases) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("helmreleases"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched helmRelease. +func (c *helmReleases) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmRelease, err error) { + result = &v1alpha1.HelmRelease{} + err = c.client.Patch(pt). + Resource("helmreleases"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/clientset/versioned/typed/application/v1alpha1/helmrepo.go b/pkg/client/clientset/versioned/typed/application/v1alpha1/helmrepo.go new file mode 100644 index 0000000000000000000000000000000000000000..c82a48f5267667dca607cbb0f91c1169e42618f6 --- /dev/null +++ b/pkg/client/clientset/versioned/typed/application/v1alpha1/helmrepo.go @@ -0,0 +1,184 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by client-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + scheme "kubesphere.io/kubesphere/pkg/client/clientset/versioned/scheme" +) + +// HelmReposGetter has a method to return a HelmRepoInterface. +// A group's client should implement this interface. +type HelmReposGetter interface { + HelmRepos() HelmRepoInterface +} + +// HelmRepoInterface has methods to work with HelmRepo resources. +type HelmRepoInterface interface { + Create(ctx context.Context, helmRepo *v1alpha1.HelmRepo, opts v1.CreateOptions) (*v1alpha1.HelmRepo, error) + Update(ctx context.Context, helmRepo *v1alpha1.HelmRepo, opts v1.UpdateOptions) (*v1alpha1.HelmRepo, error) + UpdateStatus(ctx context.Context, helmRepo *v1alpha1.HelmRepo, opts v1.UpdateOptions) (*v1alpha1.HelmRepo, error) + Delete(ctx context.Context, name string, opts v1.DeleteOptions) error + DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error + Get(ctx context.Context, name string, opts v1.GetOptions) (*v1alpha1.HelmRepo, error) + List(ctx context.Context, opts v1.ListOptions) (*v1alpha1.HelmRepoList, error) + Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) + Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmRepo, err error) + HelmRepoExpansion +} + +// helmRepos implements HelmRepoInterface +type helmRepos struct { + client rest.Interface +} + +// newHelmRepos returns a HelmRepos +func newHelmRepos(c *ApplicationV1alpha1Client) *helmRepos { + return &helmRepos{ + client: c.RESTClient(), + } +} + +// Get takes name of the helmRepo, and returns the corresponding helmRepo object, and an error if there is any. +func (c *helmRepos) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.HelmRepo, err error) { + result = &v1alpha1.HelmRepo{} + err = c.client.Get(). + Resource("helmrepos"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(ctx). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of HelmRepos that match those selectors. +func (c *helmRepos) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.HelmRepoList, err error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + result = &v1alpha1.HelmRepoList{} + err = c.client.Get(). + Resource("helmrepos"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Do(ctx). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested helmRepos. +func (c *helmRepos) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { + var timeout time.Duration + if opts.TimeoutSeconds != nil { + timeout = time.Duration(*opts.TimeoutSeconds) * time.Second + } + opts.Watch = true + return c.client.Get(). + Resource("helmrepos"). + VersionedParams(&opts, scheme.ParameterCodec). + Timeout(timeout). + Watch(ctx) +} + +// Create takes the representation of a helmRepo and creates it. Returns the server's representation of the helmRepo, and an error, if there is any. +func (c *helmRepos) Create(ctx context.Context, helmRepo *v1alpha1.HelmRepo, opts v1.CreateOptions) (result *v1alpha1.HelmRepo, err error) { + result = &v1alpha1.HelmRepo{} + err = c.client.Post(). + Resource("helmrepos"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmRepo). + Do(ctx). + Into(result) + return +} + +// Update takes the representation of a helmRepo and updates it. Returns the server's representation of the helmRepo, and an error, if there is any. +func (c *helmRepos) Update(ctx context.Context, helmRepo *v1alpha1.HelmRepo, opts v1.UpdateOptions) (result *v1alpha1.HelmRepo, err error) { + result = &v1alpha1.HelmRepo{} + err = c.client.Put(). + Resource("helmrepos"). + Name(helmRepo.Name). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmRepo). + Do(ctx). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *helmRepos) UpdateStatus(ctx context.Context, helmRepo *v1alpha1.HelmRepo, opts v1.UpdateOptions) (result *v1alpha1.HelmRepo, err error) { + result = &v1alpha1.HelmRepo{} + err = c.client.Put(). + Resource("helmrepos"). + Name(helmRepo.Name). + SubResource("status"). + VersionedParams(&opts, scheme.ParameterCodec). + Body(helmRepo). + Do(ctx). + Into(result) + return +} + +// Delete takes name of the helmRepo and deletes it. Returns an error if one occurs. +func (c *helmRepos) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { + return c.client.Delete(). + Resource("helmrepos"). + Name(name). + Body(&opts). + Do(ctx). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *helmRepos) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { + var timeout time.Duration + if listOpts.TimeoutSeconds != nil { + timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second + } + return c.client.Delete(). + Resource("helmrepos"). + VersionedParams(&listOpts, scheme.ParameterCodec). + Timeout(timeout). + Body(&opts). + Do(ctx). + Error() +} + +// Patch applies the patch and returns the patched helmRepo. +func (c *helmRepos) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.HelmRepo, err error) { + result = &v1alpha1.HelmRepo{} + err = c.client.Patch(pt). + Resource("helmrepos"). + Name(name). + SubResource(subresources...). + VersionedParams(&opts, scheme.ParameterCodec). + Body(data). + Do(ctx). + Into(result) + return +} diff --git a/pkg/client/informers/externalversions/application/interface.go b/pkg/client/informers/externalversions/application/interface.go new file mode 100644 index 0000000000000000000000000000000000000000..0b5a216a6e2855f7d016af34923cd1bddb9bd252 --- /dev/null +++ b/pkg/client/informers/externalversions/application/interface.go @@ -0,0 +1,46 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package application + +import ( + v1alpha1 "kubesphere.io/kubesphere/pkg/client/informers/externalversions/application/v1alpha1" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1alpha1 provides access to shared informers for resources in V1alpha1. + V1alpha1() v1alpha1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1alpha1 returns a new v1alpha1.Interface. +func (g *group) V1alpha1() v1alpha1.Interface { + return v1alpha1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/pkg/client/informers/externalversions/application/v1alpha1/helmapplication.go b/pkg/client/informers/externalversions/application/v1alpha1/helmapplication.go new file mode 100644 index 0000000000000000000000000000000000000000..6433c3dc8193ad64f064de49d49aeb9da8260751 --- /dev/null +++ b/pkg/client/informers/externalversions/application/v1alpha1/helmapplication.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + applicationv1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "kubesphere.io/kubesphere/pkg/client/listers/application/v1alpha1" +) + +// HelmApplicationInformer provides access to a shared informer and lister for +// HelmApplications. +type HelmApplicationInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.HelmApplicationLister +} + +type helmApplicationInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewHelmApplicationInformer constructs a new informer for HelmApplication type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewHelmApplicationInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredHelmApplicationInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredHelmApplicationInformer constructs a new informer for HelmApplication type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredHelmApplicationInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ApplicationV1alpha1().HelmApplications().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ApplicationV1alpha1().HelmApplications().Watch(context.TODO(), options) + }, + }, + &applicationv1alpha1.HelmApplication{}, + resyncPeriod, + indexers, + ) +} + +func (f *helmApplicationInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredHelmApplicationInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *helmApplicationInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&applicationv1alpha1.HelmApplication{}, f.defaultInformer) +} + +func (f *helmApplicationInformer) Lister() v1alpha1.HelmApplicationLister { + return v1alpha1.NewHelmApplicationLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/application/v1alpha1/helmapplicationversion.go b/pkg/client/informers/externalversions/application/v1alpha1/helmapplicationversion.go new file mode 100644 index 0000000000000000000000000000000000000000..7ff8b20daa9a963a446f533bc791cef58c840db6 --- /dev/null +++ b/pkg/client/informers/externalversions/application/v1alpha1/helmapplicationversion.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + applicationv1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "kubesphere.io/kubesphere/pkg/client/listers/application/v1alpha1" +) + +// HelmApplicationVersionInformer provides access to a shared informer and lister for +// HelmApplicationVersions. +type HelmApplicationVersionInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.HelmApplicationVersionLister +} + +type helmApplicationVersionInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewHelmApplicationVersionInformer constructs a new informer for HelmApplicationVersion type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewHelmApplicationVersionInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredHelmApplicationVersionInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredHelmApplicationVersionInformer constructs a new informer for HelmApplicationVersion type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredHelmApplicationVersionInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ApplicationV1alpha1().HelmApplicationVersions().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ApplicationV1alpha1().HelmApplicationVersions().Watch(context.TODO(), options) + }, + }, + &applicationv1alpha1.HelmApplicationVersion{}, + resyncPeriod, + indexers, + ) +} + +func (f *helmApplicationVersionInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredHelmApplicationVersionInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *helmApplicationVersionInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&applicationv1alpha1.HelmApplicationVersion{}, f.defaultInformer) +} + +func (f *helmApplicationVersionInformer) Lister() v1alpha1.HelmApplicationVersionLister { + return v1alpha1.NewHelmApplicationVersionLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/application/v1alpha1/helmcategory.go b/pkg/client/informers/externalversions/application/v1alpha1/helmcategory.go new file mode 100644 index 0000000000000000000000000000000000000000..c0e1d5e463995571b6f0f65b94c449d1358e6bf9 --- /dev/null +++ b/pkg/client/informers/externalversions/application/v1alpha1/helmcategory.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + applicationv1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "kubesphere.io/kubesphere/pkg/client/listers/application/v1alpha1" +) + +// HelmCategoryInformer provides access to a shared informer and lister for +// HelmCategories. +type HelmCategoryInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.HelmCategoryLister +} + +type helmCategoryInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewHelmCategoryInformer constructs a new informer for HelmCategory type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewHelmCategoryInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredHelmCategoryInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredHelmCategoryInformer constructs a new informer for HelmCategory type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredHelmCategoryInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ApplicationV1alpha1().HelmCategories().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ApplicationV1alpha1().HelmCategories().Watch(context.TODO(), options) + }, + }, + &applicationv1alpha1.HelmCategory{}, + resyncPeriod, + indexers, + ) +} + +func (f *helmCategoryInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredHelmCategoryInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *helmCategoryInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&applicationv1alpha1.HelmCategory{}, f.defaultInformer) +} + +func (f *helmCategoryInformer) Lister() v1alpha1.HelmCategoryLister { + return v1alpha1.NewHelmCategoryLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/application/v1alpha1/helmrelease.go b/pkg/client/informers/externalversions/application/v1alpha1/helmrelease.go new file mode 100644 index 0000000000000000000000000000000000000000..d41874a2ba0ad120cb69686a40b9883ec5df2c71 --- /dev/null +++ b/pkg/client/informers/externalversions/application/v1alpha1/helmrelease.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + applicationv1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "kubesphere.io/kubesphere/pkg/client/listers/application/v1alpha1" +) + +// HelmReleaseInformer provides access to a shared informer and lister for +// HelmReleases. +type HelmReleaseInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.HelmReleaseLister +} + +type helmReleaseInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewHelmReleaseInformer constructs a new informer for HelmRelease type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewHelmReleaseInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredHelmReleaseInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredHelmReleaseInformer constructs a new informer for HelmRelease type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredHelmReleaseInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ApplicationV1alpha1().HelmReleases().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ApplicationV1alpha1().HelmReleases().Watch(context.TODO(), options) + }, + }, + &applicationv1alpha1.HelmRelease{}, + resyncPeriod, + indexers, + ) +} + +func (f *helmReleaseInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredHelmReleaseInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *helmReleaseInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&applicationv1alpha1.HelmRelease{}, f.defaultInformer) +} + +func (f *helmReleaseInformer) Lister() v1alpha1.HelmReleaseLister { + return v1alpha1.NewHelmReleaseLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/application/v1alpha1/helmrepo.go b/pkg/client/informers/externalversions/application/v1alpha1/helmrepo.go new file mode 100644 index 0000000000000000000000000000000000000000..4319cb6743c0a38412166c3880fa74285cd00a25 --- /dev/null +++ b/pkg/client/informers/externalversions/application/v1alpha1/helmrepo.go @@ -0,0 +1,89 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "context" + time "time" + + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" + applicationv1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" + v1alpha1 "kubesphere.io/kubesphere/pkg/client/listers/application/v1alpha1" +) + +// HelmRepoInformer provides access to a shared informer and lister for +// HelmRepos. +type HelmRepoInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1alpha1.HelmRepoLister +} + +type helmRepoInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewHelmRepoInformer constructs a new informer for HelmRepo type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewHelmRepoInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredHelmRepoInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredHelmRepoInformer constructs a new informer for HelmRepo type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredHelmRepoInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ApplicationV1alpha1().HelmRepos().List(context.TODO(), options) + }, + WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.ApplicationV1alpha1().HelmRepos().Watch(context.TODO(), options) + }, + }, + &applicationv1alpha1.HelmRepo{}, + resyncPeriod, + indexers, + ) +} + +func (f *helmRepoInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredHelmRepoInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *helmRepoInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&applicationv1alpha1.HelmRepo{}, f.defaultInformer) +} + +func (f *helmRepoInformer) Lister() v1alpha1.HelmRepoLister { + return v1alpha1.NewHelmRepoLister(f.Informer().GetIndexer()) +} diff --git a/pkg/client/informers/externalversions/application/v1alpha1/interface.go b/pkg/client/informers/externalversions/application/v1alpha1/interface.go new file mode 100644 index 0000000000000000000000000000000000000000..d0bd946eb606b0ba526d5cf0ec0cc0c303ef8c35 --- /dev/null +++ b/pkg/client/informers/externalversions/application/v1alpha1/interface.go @@ -0,0 +1,73 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by informer-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + internalinterfaces "kubesphere.io/kubesphere/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // HelmApplications returns a HelmApplicationInformer. + HelmApplications() HelmApplicationInformer + // HelmApplicationVersions returns a HelmApplicationVersionInformer. + HelmApplicationVersions() HelmApplicationVersionInformer + // HelmCategories returns a HelmCategoryInformer. + HelmCategories() HelmCategoryInformer + // HelmReleases returns a HelmReleaseInformer. + HelmReleases() HelmReleaseInformer + // HelmRepos returns a HelmRepoInformer. + HelmRepos() HelmRepoInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// HelmApplications returns a HelmApplicationInformer. +func (v *version) HelmApplications() HelmApplicationInformer { + return &helmApplicationInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// HelmApplicationVersions returns a HelmApplicationVersionInformer. +func (v *version) HelmApplicationVersions() HelmApplicationVersionInformer { + return &helmApplicationVersionInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// HelmCategories returns a HelmCategoryInformer. +func (v *version) HelmCategories() HelmCategoryInformer { + return &helmCategoryInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// HelmReleases returns a HelmReleaseInformer. +func (v *version) HelmReleases() HelmReleaseInformer { + return &helmReleaseInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} + +// HelmRepos returns a HelmRepoInformer. +func (v *version) HelmRepos() HelmRepoInformer { + return &helmRepoInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} diff --git a/pkg/client/informers/externalversions/factory.go b/pkg/client/informers/externalversions/factory.go index 89e3269e68455ee81280cf7edfb05cd4ab7c33a0..49260176bf91fb239e7d986d4ba91ac1298f7348 100644 --- a/pkg/client/informers/externalversions/factory.go +++ b/pkg/client/informers/externalversions/factory.go @@ -28,6 +28,7 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" versioned "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + application "kubesphere.io/kubesphere/pkg/client/informers/externalversions/application" auditing "kubesphere.io/kubesphere/pkg/client/informers/externalversions/auditing" cluster "kubesphere.io/kubesphere/pkg/client/informers/externalversions/cluster" devops "kubesphere.io/kubesphere/pkg/client/informers/externalversions/devops" @@ -181,6 +182,7 @@ type SharedInformerFactory interface { ForResource(resource schema.GroupVersionResource) (GenericInformer, error) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + Application() application.Interface Auditing() auditing.Interface Cluster() cluster.Interface Devops() devops.Interface @@ -193,6 +195,10 @@ type SharedInformerFactory interface { Types() types.Interface } +func (f *sharedInformerFactory) Application() application.Interface { + return application.New(f, f.namespace, f.tweakListOptions) +} + func (f *sharedInformerFactory) Auditing() auditing.Interface { return auditing.New(f, f.namespace, f.tweakListOptions) } diff --git a/pkg/client/informers/externalversions/generic.go b/pkg/client/informers/externalversions/generic.go index 02989bf5aefd8ebc29d30c70b4542f162946faa8..f0c144604a4496d7c72d3498fcc42e7d2df6c1c8 100644 --- a/pkg/client/informers/externalversions/generic.go +++ b/pkg/client/informers/externalversions/generic.go @@ -23,7 +23,8 @@ import ( schema "k8s.io/apimachinery/pkg/runtime/schema" cache "k8s.io/client-go/tools/cache" - v1alpha1 "kubesphere.io/kubesphere/pkg/apis/auditing/v1alpha1" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + auditingv1alpha1 "kubesphere.io/kubesphere/pkg/apis/auditing/v1alpha1" clusterv1alpha1 "kubesphere.io/kubesphere/pkg/apis/cluster/v1alpha1" devopsv1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1" v1alpha3 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3" @@ -63,10 +64,22 @@ func (f *genericInformer) Lister() cache.GenericLister { // TODO extend this to unknown resources with a client pool func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { switch resource { - // Group=auditing.kubesphere.io, Version=v1alpha1 - case v1alpha1.SchemeGroupVersion.WithResource("rules"): + // Group=application.kubesphere.io, Version=v1alpha1 + case v1alpha1.SchemeGroupVersion.WithResource("helmapplications"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Application().V1alpha1().HelmApplications().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("helmapplicationversions"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Application().V1alpha1().HelmApplicationVersions().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("helmcategories"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Application().V1alpha1().HelmCategories().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("helmreleases"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Application().V1alpha1().HelmReleases().Informer()}, nil + case v1alpha1.SchemeGroupVersion.WithResource("helmrepos"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Application().V1alpha1().HelmRepos().Informer()}, nil + + // Group=auditing.kubesphere.io, Version=v1alpha1 + case auditingv1alpha1.SchemeGroupVersion.WithResource("rules"): return &genericInformer{resource: resource.GroupResource(), informer: f.Auditing().V1alpha1().Rules().Informer()}, nil - case v1alpha1.SchemeGroupVersion.WithResource("webhooks"): + case auditingv1alpha1.SchemeGroupVersion.WithResource("webhooks"): return &genericInformer{resource: resource.GroupResource(), informer: f.Auditing().V1alpha1().Webhooks().Informer()}, nil // Group=cluster.kubesphere.io, Version=v1alpha1 diff --git a/pkg/client/listers/application/v1alpha1/expansion_generated.go b/pkg/client/listers/application/v1alpha1/expansion_generated.go new file mode 100644 index 0000000000000000000000000000000000000000..60db9d4392be22a3d0d0ef57cd6b0a207f0dce86 --- /dev/null +++ b/pkg/client/listers/application/v1alpha1/expansion_generated.go @@ -0,0 +1,39 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +// HelmApplicationListerExpansion allows custom methods to be added to +// HelmApplicationLister. +type HelmApplicationListerExpansion interface{} + +// HelmApplicationVersionListerExpansion allows custom methods to be added to +// HelmApplicationVersionLister. +type HelmApplicationVersionListerExpansion interface{} + +// HelmCategoryListerExpansion allows custom methods to be added to +// HelmCategoryLister. +type HelmCategoryListerExpansion interface{} + +// HelmReleaseListerExpansion allows custom methods to be added to +// HelmReleaseLister. +type HelmReleaseListerExpansion interface{} + +// HelmRepoListerExpansion allows custom methods to be added to +// HelmRepoLister. +type HelmRepoListerExpansion interface{} diff --git a/pkg/client/listers/application/v1alpha1/helmapplication.go b/pkg/client/listers/application/v1alpha1/helmapplication.go new file mode 100644 index 0000000000000000000000000000000000000000..a6ed5e63c3c1f9655fefb0e2b921e067412aaad3 --- /dev/null +++ b/pkg/client/listers/application/v1alpha1/helmapplication.go @@ -0,0 +1,65 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" +) + +// HelmApplicationLister helps list HelmApplications. +type HelmApplicationLister interface { + // List lists all HelmApplications in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.HelmApplication, err error) + // Get retrieves the HelmApplication from the index for a given name. + Get(name string) (*v1alpha1.HelmApplication, error) + HelmApplicationListerExpansion +} + +// helmApplicationLister implements the HelmApplicationLister interface. +type helmApplicationLister struct { + indexer cache.Indexer +} + +// NewHelmApplicationLister returns a new HelmApplicationLister. +func NewHelmApplicationLister(indexer cache.Indexer) HelmApplicationLister { + return &helmApplicationLister{indexer: indexer} +} + +// List lists all HelmApplications in the indexer. +func (s *helmApplicationLister) List(selector labels.Selector) (ret []*v1alpha1.HelmApplication, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.HelmApplication)) + }) + return ret, err +} + +// Get retrieves the HelmApplication from the index for a given name. +func (s *helmApplicationLister) Get(name string) (*v1alpha1.HelmApplication, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("helmapplication"), name) + } + return obj.(*v1alpha1.HelmApplication), nil +} diff --git a/pkg/client/listers/application/v1alpha1/helmapplicationversion.go b/pkg/client/listers/application/v1alpha1/helmapplicationversion.go new file mode 100644 index 0000000000000000000000000000000000000000..65037fb5eaceb3ebc57f5f9d223577360fd49f8e --- /dev/null +++ b/pkg/client/listers/application/v1alpha1/helmapplicationversion.go @@ -0,0 +1,65 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" +) + +// HelmApplicationVersionLister helps list HelmApplicationVersions. +type HelmApplicationVersionLister interface { + // List lists all HelmApplicationVersions in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.HelmApplicationVersion, err error) + // Get retrieves the HelmApplicationVersion from the index for a given name. + Get(name string) (*v1alpha1.HelmApplicationVersion, error) + HelmApplicationVersionListerExpansion +} + +// helmApplicationVersionLister implements the HelmApplicationVersionLister interface. +type helmApplicationVersionLister struct { + indexer cache.Indexer +} + +// NewHelmApplicationVersionLister returns a new HelmApplicationVersionLister. +func NewHelmApplicationVersionLister(indexer cache.Indexer) HelmApplicationVersionLister { + return &helmApplicationVersionLister{indexer: indexer} +} + +// List lists all HelmApplicationVersions in the indexer. +func (s *helmApplicationVersionLister) List(selector labels.Selector) (ret []*v1alpha1.HelmApplicationVersion, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.HelmApplicationVersion)) + }) + return ret, err +} + +// Get retrieves the HelmApplicationVersion from the index for a given name. +func (s *helmApplicationVersionLister) Get(name string) (*v1alpha1.HelmApplicationVersion, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("helmapplicationversion"), name) + } + return obj.(*v1alpha1.HelmApplicationVersion), nil +} diff --git a/pkg/client/listers/application/v1alpha1/helmcategory.go b/pkg/client/listers/application/v1alpha1/helmcategory.go new file mode 100644 index 0000000000000000000000000000000000000000..5b5841cf1fb1b5b780032d9580d6448c359baef8 --- /dev/null +++ b/pkg/client/listers/application/v1alpha1/helmcategory.go @@ -0,0 +1,65 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" +) + +// HelmCategoryLister helps list HelmCategories. +type HelmCategoryLister interface { + // List lists all HelmCategories in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.HelmCategory, err error) + // Get retrieves the HelmCategory from the index for a given name. + Get(name string) (*v1alpha1.HelmCategory, error) + HelmCategoryListerExpansion +} + +// helmCategoryLister implements the HelmCategoryLister interface. +type helmCategoryLister struct { + indexer cache.Indexer +} + +// NewHelmCategoryLister returns a new HelmCategoryLister. +func NewHelmCategoryLister(indexer cache.Indexer) HelmCategoryLister { + return &helmCategoryLister{indexer: indexer} +} + +// List lists all HelmCategories in the indexer. +func (s *helmCategoryLister) List(selector labels.Selector) (ret []*v1alpha1.HelmCategory, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.HelmCategory)) + }) + return ret, err +} + +// Get retrieves the HelmCategory from the index for a given name. +func (s *helmCategoryLister) Get(name string) (*v1alpha1.HelmCategory, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("helmcategory"), name) + } + return obj.(*v1alpha1.HelmCategory), nil +} diff --git a/pkg/client/listers/application/v1alpha1/helmrelease.go b/pkg/client/listers/application/v1alpha1/helmrelease.go new file mode 100644 index 0000000000000000000000000000000000000000..85ce5fcf775a7acfaee6e7f9725671ccfa0c590e --- /dev/null +++ b/pkg/client/listers/application/v1alpha1/helmrelease.go @@ -0,0 +1,65 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" +) + +// HelmReleaseLister helps list HelmReleases. +type HelmReleaseLister interface { + // List lists all HelmReleases in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.HelmRelease, err error) + // Get retrieves the HelmRelease from the index for a given name. + Get(name string) (*v1alpha1.HelmRelease, error) + HelmReleaseListerExpansion +} + +// helmReleaseLister implements the HelmReleaseLister interface. +type helmReleaseLister struct { + indexer cache.Indexer +} + +// NewHelmReleaseLister returns a new HelmReleaseLister. +func NewHelmReleaseLister(indexer cache.Indexer) HelmReleaseLister { + return &helmReleaseLister{indexer: indexer} +} + +// List lists all HelmReleases in the indexer. +func (s *helmReleaseLister) List(selector labels.Selector) (ret []*v1alpha1.HelmRelease, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.HelmRelease)) + }) + return ret, err +} + +// Get retrieves the HelmRelease from the index for a given name. +func (s *helmReleaseLister) Get(name string) (*v1alpha1.HelmRelease, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("helmrelease"), name) + } + return obj.(*v1alpha1.HelmRelease), nil +} diff --git a/pkg/client/listers/application/v1alpha1/helmrepo.go b/pkg/client/listers/application/v1alpha1/helmrepo.go new file mode 100644 index 0000000000000000000000000000000000000000..2641d7908cac0aff8c48ce3b0ffd484e9e178f2f --- /dev/null +++ b/pkg/client/listers/application/v1alpha1/helmrepo.go @@ -0,0 +1,65 @@ +/* +Copyright 2020 The KubeSphere 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. +*/ + +// Code generated by lister-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" + v1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" +) + +// HelmRepoLister helps list HelmRepos. +type HelmRepoLister interface { + // List lists all HelmRepos in the indexer. + List(selector labels.Selector) (ret []*v1alpha1.HelmRepo, err error) + // Get retrieves the HelmRepo from the index for a given name. + Get(name string) (*v1alpha1.HelmRepo, error) + HelmRepoListerExpansion +} + +// helmRepoLister implements the HelmRepoLister interface. +type helmRepoLister struct { + indexer cache.Indexer +} + +// NewHelmRepoLister returns a new HelmRepoLister. +func NewHelmRepoLister(indexer cache.Indexer) HelmRepoLister { + return &helmRepoLister{indexer: indexer} +} + +// List lists all HelmRepos in the indexer. +func (s *helmRepoLister) List(selector labels.Selector) (ret []*v1alpha1.HelmRepo, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1alpha1.HelmRepo)) + }) + return ret, err +} + +// Get retrieves the HelmRepo from the index for a given name. +func (s *helmRepoLister) Get(name string) (*v1alpha1.HelmRepo, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1alpha1.Resource("helmrepo"), name) + } + return obj.(*v1alpha1.HelmRepo), nil +} diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index ea1dd471d22adbc09f1121d5a4563d72c3e653f6..ea0de7d594a32129328eb5517a441d192025f574 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -32,14 +32,19 @@ const ( AdminUserName = "admin" IngressControllerPrefix = "kubesphere-router-" - WorkspaceLabelKey = "kubesphere.io/workspace" - NamespaceLabelKey = "kubesphere.io/namespace" - DisplayNameAnnotationKey = "kubesphere.io/alias-name" - DescriptionAnnotationKey = "kubesphere.io/description" - CreatorAnnotationKey = "kubesphere.io/creator" - UsernameLabelKey = "kubesphere.io/username" - DevOpsProjectLabelKey = "kubesphere.io/devopsproject" - KubefedManagedLabel = "kubefed.io/managed" + ClusterNameLabelKey = "kubesphere.io/cluster" + NameLabelKey = "kubesphere.io/name" + WorkspaceLabelKey = "kubesphere.io/workspace" + NamespaceLabelKey = "kubesphere.io/namespace" + DisplayNameAnnotationKey = "kubesphere.io/alias-name" + ChartRepoIdLabelKey = "application.kubesphere.io/repo-id" + ChartApplicationIdLabelKey = "application.kubesphere.io/app-id" + ChartApplicationVersionIdLabelKey = "application.kubesphere.io/app-version-id" + CategoryIdLabelKey = "application.kubesphere.io/app-category-id" + CreatorAnnotationKey = "kubesphere.io/creator" + UsernameLabelKey = "kubesphere.io/username" + DevOpsProjectLabelKey = "kubesphere.io/devopsproject" + KubefedManagedLabel = "kubefed.io/managed" UserNameHeader = "X-Token-Username" @@ -58,6 +63,7 @@ const ( DevOpsProjectRoleTag = "DevOps Project Role" NamespaceRoleTag = "Namespace Role" + OpenpitrixTag = "OpenPitrix Resources" OpenpitrixAppInstanceTag = "App Instance" OpenpitrixAppTemplateTag = "App Template" OpenpitrixCategoryTag = "Category" diff --git a/pkg/controller/cluster/cluster_controller.go b/pkg/controller/cluster/cluster_controller.go index 500d2265359fb1c6e784db4c21079b3fa4b45997..9662b0452bcd8cfe014571f6bab3f344cd7bbd47 100644 --- a/pkg/controller/cluster/cluster_controller.go +++ b/pkg/controller/cluster/cluster_controller.go @@ -51,7 +51,6 @@ import ( clusterclient "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/cluster/v1alpha1" clusterinformer "kubesphere.io/kubesphere/pkg/client/informers/externalversions/cluster/v1alpha1" clusterlister "kubesphere.io/kubesphere/pkg/client/listers/cluster/v1alpha1" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" ) // Cluster controller only runs under multicluster mode. Cluster controller is following below steps, @@ -145,8 +144,6 @@ type clusterController struct { clusterLister clusterlister.ClusterLister clusterHasSynced cache.InformerSynced - openpitrixClient openpitrix.Client - queue workqueue.RateLimitingInterface workerLoopPeriod time.Duration @@ -163,7 +160,6 @@ func NewClusterController( config *rest.Config, clusterInformer clusterinformer.ClusterInformer, clusterClient clusterclient.ClusterInterface, - openpitrixClient openpitrix.Client, resyncPeriod time.Duration, ) *clusterController { @@ -180,7 +176,6 @@ func NewClusterController( client: client, hostConfig: config, clusterClient: clusterClient, - openpitrixClient: openpitrixClient, queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "cluster"), workerLoopPeriod: time.Second, clusterMap: make(map[string]*clusterData), @@ -471,18 +466,6 @@ func (c *clusterController) syncCluster(key string) error { return err } - // clean up openpitrix runtime of the cluster - if _, ok := cluster.Annotations[openpitrixRuntime]; ok { - if c.openpitrixClient != nil { - err = c.openpitrixClient.CleanupRuntime(cluster.Name) - if err != nil { - klog.Errorf("Unable to delete openpitrix for cluster %s, error %v", cluster.Name, err) - return err - } - } - delete(cluster.Annotations, openpitrixRuntime) - } - // remove our cluster finalizer finalizers := sets.NewString(cluster.ObjectMeta.Finalizers...) finalizers.Delete(clusterv1alpha1.Finalizer) @@ -585,22 +568,6 @@ func (c *clusterController) syncCluster(key string) error { cluster.Labels[clusterv1alpha1.HostCluster] = "" } - if c.openpitrixClient != nil { // OpenPitrix is enabled, create runtime - if cluster.GetAnnotations() == nil { - cluster.Annotations = make(map[string]string) - } - - if _, ok = cluster.Annotations[openpitrixRuntime]; !ok { - err = c.openpitrixClient.UpsertRuntime(cluster.Name, string(cluster.Spec.Connection.KubeConfig)) - if err != nil { - klog.Errorf("Failed to create runtime for cluster %s, error %v", cluster.Name, err) - return err - } else { - cluster.Annotations[openpitrixRuntime] = cluster.Name - } - } - } - if !reflect.DeepEqual(oldCluster, cluster) { _, err = c.clusterClient.Update(context.TODO(), cluster, metav1.UpdateOptions{}) if err != nil { diff --git a/pkg/controller/openpitrix/helmapplication/helm_application_controller.go b/pkg/controller/openpitrix/helmapplication/helm_application_controller.go new file mode 100644 index 0000000000000000000000000000000000000000..ce2bd8d950704d6a6b9376a561405ddfc2d90240 --- /dev/null +++ b/pkg/controller/openpitrix/helmapplication/helm_application_controller.go @@ -0,0 +1,176 @@ +/* +Copyright 2019 The KubeSphere 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 helmapplication + +import ( + "context" + "fmt" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/types" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/utils/sliceutil" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "strconv" + "strings" +) + +func init() { + registerMetrics() +} + +const ( + helmApplicationControllerName = "helm-application-controller" +) + +var _ reconcile.Reconciler = &ReconcileHelmApplication{} + +// ReconcileHelmApplication reconciles a federated helm application object +type ReconcileHelmApplication struct { + client.Client +} + +const ( + appFinalizer = "helmapplication.application.kubesphere.io" +) + +func (r *ReconcileHelmApplication) Reconcile(request reconcile.Request) (reconcile.Result, error) { + klog.V(4).Info("sync helm application") + + rootCtx := context.Background() + app := &v1alpha1.HelmApplication{} + err := r.Client.Get(rootCtx, request.NamespacedName, app) + if err != nil { + if apierrors.IsNotFound(err) { + return reconcile.Result{}, nil + } + return reconcile.Result{}, err + } + + if app.DeletionTimestamp == nil { + // new app, update finalizer + if !sliceutil.HasString(app.ObjectMeta.Finalizers, appFinalizer) { + app.ObjectMeta.Finalizers = append(app.ObjectMeta.Finalizers, appFinalizer) + if err := r.Update(rootCtx, app); err != nil { + return ctrl.Result{}, err + } + // create app success + appOperationTotal.WithLabelValues("creation", app.GetTrueName(), strconv.FormatBool(inAppStore(app))).Inc() + } + + if !inAppStore(app) { + if app.Status.State == v1alpha1.StateActive || + app.Status.State == v1alpha1.StateSuspended { + return reconcile.Result{}, r.createAppCopyInAppStore(rootCtx, app) + } + } + } else { + // delete app copy in appStore + if !inAppStore(app) { + if err := r.deleteAppCopyInAppStore(rootCtx, app.Name); err != nil { + return reconcile.Result{}, err + } + } + + app.ObjectMeta.Finalizers = sliceutil.RemoveString(app.ObjectMeta.Finalizers, func(item string) bool { + return item == appFinalizer + }) + klog.V(4).Info("update app") + if err := r.Update(rootCtx, app); err != nil { + klog.Errorf("update app failed, error: %s", err) + return ctrl.Result{}, err + } else { + // delete app success + appOperationTotal.WithLabelValues("deletion", app.GetTrueName(), strconv.FormatBool(inAppStore(app))).Inc() + } + } + + return reconcile.Result{}, nil +} + +func (r *ReconcileHelmApplication) deleteAppCopyInAppStore(ctx context.Context, name string) error { + appInStore := &v1alpha1.HelmApplication{} + err := r.Client.Get(ctx, types.NamespacedName{Name: fmt.Sprintf("%s%s", name, v1alpha1.HelmApplicationAppStoreSuffix)}, appInStore) + if err != nil { + if !apierrors.IsNotFound(err) { + return err + } + } else { + err = r.Delete(ctx, appInStore) + return err + } + + return nil +} + +// create a application copy in app store +func (r *ReconcileHelmApplication) createAppCopyInAppStore(ctx context.Context, from *v1alpha1.HelmApplication) error { + name := fmt.Sprintf("%s%s", from.Name, v1alpha1.HelmApplicationAppStoreSuffix) + + app := &v1alpha1.HelmApplication{} + err := r.Get(ctx, types.NamespacedName{Name: name}, app) + if err != nil && !apierrors.IsNotFound(err) { + return err + } + + if app.Name == "" { + app.Name = name + labels := from.Labels + if len(labels) == 0 { + labels = make(map[string]string, 3) + } + labels[constants.ChartRepoIdLabelKey] = v1alpha1.AppStoreRepoId + + // assign a category to app + if labels[constants.CategoryIdLabelKey] == "" { + labels[constants.CategoryIdLabelKey] = v1alpha1.UncategorizedId + } + labels[v1alpha1.OriginWorkspaceLabelKey] = from.GetWorkspace() + + // apps in store are global resource. + delete(labels, constants.WorkspaceLabelKey) + app.Labels = labels + + app.Spec = *from.Spec.DeepCopy() + + err = r.Create(context.TODO(), app) + if err != nil { + return err + } + } + + if app.Status.State == "" { + // update status if needed + return updateHelmApplicationStatus(r.Client, from.Name, true) + } + + return nil +} + +func (r *ReconcileHelmApplication) SetupWithManager(mgr ctrl.Manager) error { + r.Client = mgr.GetClient() + + return ctrl.NewControllerManagedBy(mgr). + For(&v1alpha1.HelmApplication{}).Complete(r) +} + +func inAppStore(app *v1alpha1.HelmApplication) bool { + return strings.HasSuffix(app.Name, v1alpha1.HelmApplicationAppStoreSuffix) +} diff --git a/pkg/controller/openpitrix/helmapplication/helm_application_version_controller.go b/pkg/controller/openpitrix/helmapplication/helm_application_version_controller.go new file mode 100644 index 0000000000000000000000000000000000000000..502f12ddd8e0fa1088aeee42015c304ebbd39191 --- /dev/null +++ b/pkg/controller/openpitrix/helmapplication/helm_application_version_controller.go @@ -0,0 +1,283 @@ +/* +Copyright 2019 The KubeSphere 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 helmapplication + +import ( + "context" + "fmt" + "github.com/Masterminds/semver/v3" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/utils/sliceutil" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "time" +) + +const ( + HelmAppVersionFinalizer = "helmappversion.application.kubesphere.io" +) + +var _ reconcile.Reconciler = &ReconcileHelmApplicationVersion{} + +// ReconcileHelmApplicationVersion reconciles a helm application version object +type ReconcileHelmApplicationVersion struct { + client.Client +} + +// Reconcile reads that state of the cluster for a helmapplicationversions object and makes changes based on the state read +// and what is in the helmapplicationversions.Spec +func (r *ReconcileHelmApplicationVersion) Reconcile(request reconcile.Request) (reconcile.Result, error) { + start := time.Now() + klog.V(4).Infof("sync helm application version: %s", request.String()) + defer func() { + klog.V(4).Infof("sync helm application version end: %s, elapsed: %v", request.String(), time.Now().Sub(start)) + }() + + appVersion := &v1alpha1.HelmApplicationVersion{} + err := r.Client.Get(context.TODO(), request.NamespacedName, appVersion) + if err != nil { + if apierrors.IsNotFound(err) { + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + if appVersion.ObjectMeta.DeletionTimestamp.IsZero() { + + if appVersion.Status.State == "" { + // set status to draft + return reconcile.Result{}, r.updateStatus(appVersion) + } + + if !sliceutil.HasString(appVersion.ObjectMeta.Finalizers, HelmAppVersionFinalizer) { + appVersion.ObjectMeta.Finalizers = append(appVersion.ObjectMeta.Finalizers, HelmAppVersionFinalizer) + if err := r.Update(context.Background(), appVersion); err != nil { + return reconcile.Result{}, err + } else { + return reconcile.Result{}, nil + } + } + } else { + // The object is being deleted + if sliceutil.HasString(appVersion.ObjectMeta.Finalizers, HelmAppVersionFinalizer) { + // update related helm application + err = updateHelmApplicationStatus(r.Client, appVersion.GetHelmApplicationId(), false) + if err != nil { + return reconcile.Result{}, err + } + + err = updateHelmApplicationStatus(r.Client, appVersion.GetHelmApplicationId(), true) + if err != nil { + return reconcile.Result{}, err + } + + // Delete HelmApplicationVersion + appVersion.ObjectMeta.Finalizers = sliceutil.RemoveString(appVersion.ObjectMeta.Finalizers, func(item string) bool { + if item == HelmAppVersionFinalizer { + return true + } + return false + }) + if err := r.Update(context.Background(), appVersion); err != nil { + return reconcile.Result{}, err + } + } + return reconcile.Result{}, nil + } + + // update related helm application + err = updateHelmApplicationStatus(r.Client, appVersion.GetHelmApplicationId(), false) + if err != nil { + return reconcile.Result{}, err + } + + if appVersion.Status.State == v1alpha1.StateActive { + // add labels to helm application version + // The label will exists forever, since this helmapplicationversion's state only can be active and suspend. + if appVersion.GetHelmRepoId() == "" { + instanceCopy := appVersion.DeepCopy() + instanceCopy.Labels[constants.ChartRepoIdLabelKey] = v1alpha1.AppStoreRepoId + patch := client.MergeFrom(appVersion) + err = r.Client.Patch(context.TODO(), instanceCopy, patch) + if err != nil { + return reconcile.Result{}, err + } + } + + app := v1alpha1.HelmApplication{} + err = r.Get(context.TODO(), types.NamespacedName{Name: appVersion.GetHelmApplicationId()}, &app) + if err != nil { + return reconcile.Result{}, err + } + + return reconcile.Result{}, updateHelmApplicationStatus(r.Client, appVersion.GetHelmApplicationId(), true) + } else if appVersion.Status.State == v1alpha1.StateSuspended { + return reconcile.Result{}, updateHelmApplicationStatus(r.Client, appVersion.GetHelmApplicationId(), true) + } + + return reconcile.Result{}, nil +} + +func updateHelmApplicationStatus(c client.Client, appId string, inAppStore bool) error { + app := v1alpha1.HelmApplication{} + + var err error + if inAppStore { + // application name ends with `-store` + err = c.Get(context.TODO(), types.NamespacedName{Name: fmt.Sprintf("%s%s", appId, v1alpha1.HelmApplicationAppStoreSuffix)}, &app) + } else { + err = c.Get(context.TODO(), types.NamespacedName{Name: appId}, &app) + } + + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + + if !app.DeletionTimestamp.IsZero() { + return nil + } + + var versions v1alpha1.HelmApplicationVersionList + err = c.List(context.TODO(), &versions, client.MatchingLabels{ + constants.ChartApplicationIdLabelKey: appId, + }) + + if err != nil && !apierrors.IsNotFound(err) { + return err + } + + latestVersionName := getLatestVersionName(versions, inAppStore) + state := mergeApplicationVersionState(versions) + + now := time.Now() + if state != app.Status.State { + // update StatusTime when state changed + app.Status.StatusTime = &metav1.Time{Time: now} + } + + if state != app.Status.State || latestVersionName != app.Status.LatestVersion { + app.Status.State = state + app.Status.LatestVersion = latestVersionName + app.Status.UpdateTime = &metav1.Time{Time: now} + err := c.Status().Update(context.TODO(), &app) + if err != nil { + return err + } + } + return nil +} + +func (r *ReconcileHelmApplicationVersion) updateStatus(appVersion *v1alpha1.HelmApplicationVersion) error { + appVersion.Status = v1alpha1.HelmApplicationVersionStatus{ + State: v1alpha1.StateDraft, + Audit: []v1alpha1.Audit{ + { + State: v1alpha1.StateDraft, + Time: appVersion.CreationTimestamp, + Operator: appVersion.GetCreator(), + }, + }, + } + + err := r.Status().Update(context.TODO(), appVersion) + if err != nil { + return err + } + return nil +} + +func getLatestVersionName(versions v1alpha1.HelmApplicationVersionList, inAppStore bool) string { + l := versions.Items + if len(l) == 0 { + return "" + } + + verInd := 0 + if inAppStore { + // only check active app version + for ; verInd < len(l); verInd++ { + if l[verInd].Status.State == v1alpha1.StateActive { + break + } + } + } + + if verInd == len(l) { + return "" + } + + latestSemver, _ := semver.NewVersion(l[verInd].GetSemver()) + + for i := verInd + 1; i < len(l); i++ { + curr, _ := semver.NewVersion(l[i].GetSemver()) + if inAppStore { + if l[i].Status.State != v1alpha1.StateActive { + continue + } + } + if latestSemver.LessThan(curr) { + verInd = i + } + } + + return l[verInd].GetVersionName() +} + +func mergeApplicationVersionState(versions v1alpha1.HelmApplicationVersionList) string { + states := make(map[string]int, len(versions.Items)) + + for _, version := range versions.Items { + if version.DeletionTimestamp == nil { + state := version.Status.State + states[state] = states[state] + 1 + } + } + + // If there is on active appVersion, the helm application is active + if states[v1alpha1.StateActive] > 0 { + return v1alpha1.StateActive + } + + // All appVersion is draft, the helm application is draft + if states[v1alpha1.StateDraft] == len(versions.Items) { + return v1alpha1.StateDraft + } + + if states[v1alpha1.StateSuspended] > 0 { + return v1alpha1.StateSuspended + } + + // default state is draft + return v1alpha1.StateDraft +} + +func (r *ReconcileHelmApplicationVersion) SetupWithManager(mgr ctrl.Manager) error { + r.Client = mgr.GetClient() + return ctrl.NewControllerManagedBy(mgr). + For(&v1alpha1.HelmApplicationVersion{}). + Complete(r) +} diff --git a/pkg/controller/openpitrix/helmapplication/metrics.go b/pkg/controller/openpitrix/helmapplication/metrics.go new file mode 100644 index 0000000000000000000000000000000000000000..0ab0e1dc3ea21b46b4b27aab6316f0032c4bb496 --- /dev/null +++ b/pkg/controller/openpitrix/helmapplication/metrics.go @@ -0,0 +1,44 @@ +/* +Copyright 2020 The KubeSphere 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 helmapplication + +import ( + compbasemetrics "k8s.io/component-base/metrics" + "kubesphere.io/kubesphere/pkg/utils/metrics" +) + +var ( + appOperationTotal = compbasemetrics.NewCounterVec( + &compbasemetrics.CounterOpts{ + Subsystem: "ks_cm", + Name: "helm_application_operation_total", + Help: "Counter of app creation and deletion", + StabilityLevel: compbasemetrics.ALPHA, + }, + []string{"verb", "name", "appstore"}, + ) + + metricsList = []compbasemetrics.Registerable{ + appOperationTotal, + } +) + +func registerMetrics() { + for _, m := range metricsList { + metrics.MustRegister(m) + } +} diff --git a/pkg/controller/openpitrix/helmcategory/helm_category_controller.go b/pkg/controller/openpitrix/helmcategory/helm_category_controller.go new file mode 100644 index 0000000000000000000000000000000000000000..561fc849320f05b3ebc0721137c6b0e99f0dbd48 --- /dev/null +++ b/pkg/controller/openpitrix/helmcategory/helm_category_controller.go @@ -0,0 +1,337 @@ +/* +Copyright 2019 The KubeSphere 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 helmcategory + +import ( + "context" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + "k8s.io/client-go/util/workqueue" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/utils/sliceutil" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/event" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + "time" +) + +const ( + HelmCategoryFinalizer = "helmcategories.application.kubesphere.io" +) + +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ReconcileHelmCategory{Client: mgr.GetClient(), Scheme: mgr.GetScheme()} +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("helm-category-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to HelmCategory + err = c.Watch(&source.Kind{Type: &v1alpha1.HelmCategory{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + reconcileObj := r.(*ReconcileHelmCategory) + // Watch for changes to HelmApplication + err = c.Watch(&source.Kind{Type: &v1alpha1.HelmApplication{}}, &handler.Funcs{ + CreateFunc: func(event event.CreateEvent, limitingInterface workqueue.RateLimitingInterface) { + app := event.Object.(*v1alpha1.HelmApplication) + err := reconcileObj.updateUncategorizedApplicationLabels(app) + if err != nil { + limitingInterface.AddAfter(event, 20*time.Second) + return + } + + repoId := app.GetHelmRepoId() + if repoId == v1alpha1.AppStoreRepoId { + ctgId := app.GetHelmCategoryId() + if ctgId == "" { + ctgId = v1alpha1.UncategorizedId + } + err := reconcileObj.updateCategoryCount(ctgId) + if err != nil { + klog.Errorf("reconcile category %s failed, error: %s", ctgId, err) + } + } + }, + UpdateFunc: func(updateEvent event.UpdateEvent, limitingInterface workqueue.RateLimitingInterface) { + oldApp := updateEvent.ObjectOld.(*v1alpha1.HelmApplication) + newApp := updateEvent.ObjectNew.(*v1alpha1.HelmApplication) + err := reconcileObj.updateUncategorizedApplicationLabels(newApp) + if err != nil { + limitingInterface.AddAfter(updateEvent, 20*time.Second) + return + } + var oldId string + repoId := newApp.GetHelmRepoId() + if repoId == v1alpha1.AppStoreRepoId { + oldId = oldApp.GetHelmCategoryId() + if oldId == "" { + oldId = v1alpha1.UncategorizedId + } + err := reconcileObj.updateCategoryCount(oldId) + if err != nil { + klog.Errorf("reconcile category %s failed, error: %s", oldId, err) + } + } + + // new labels and new repo id + repoId = newApp.GetHelmRepoId() + if repoId == v1alpha1.AppStoreRepoId { + // new category id + newId := newApp.GetHelmCategoryId() + if newId == "" { + newId = v1alpha1.UncategorizedId + } + if oldId != newId { + err := reconcileObj.updateCategoryCount(newId) + if err != nil { + klog.Errorf("reconcile category %s failed, error: %s", newId, err) + } + } + } + }, + DeleteFunc: func(deleteEvent event.DeleteEvent, limitingInterface workqueue.RateLimitingInterface) { + app := deleteEvent.Object.(*v1alpha1.HelmApplication) + repoId := app.GetHelmRepoId() + if repoId == v1alpha1.AppStoreRepoId { + id := app.GetHelmCategoryId() + if id == "" { + id = v1alpha1.UncategorizedId + } + err := reconcileObj.updateCategoryCount(id) + if err != nil { + klog.Errorf("reconcile category %s failed, error: %s", id, err) + } + } + }, + }) + if err != nil { + return err + } + + go func() { + // create Uncategorized object + ticker := time.NewTicker(15 * time.Second) + for range ticker.C { + ctg := &v1alpha1.HelmCategory{} + err := reconcileObj.Get(context.TODO(), types.NamespacedName{Name: v1alpha1.UncategorizedId}, ctg) + if err != nil && !errors.IsNotFound(err) { + klog.Errorf("get helm category: %s failed, error: %s", v1alpha1.UncategorizedId, err) + } + if ctg.Name != "" { + // category exists now + return + } + + ctg = &v1alpha1.HelmCategory{ + ObjectMeta: metav1.ObjectMeta{ + Name: v1alpha1.UncategorizedId, + }, + Spec: v1alpha1.HelmCategorySpec{ + Description: v1alpha1.UncategorizedName, + Name: v1alpha1.UncategorizedName, + }, + } + err = reconcileObj.Create(context.TODO(), ctg) + if err != nil { + klog.Errorf("create helm category: %s failed, error: %s", v1alpha1.UncategorizedName, err) + } + } + }() + return nil +} + +var _ reconcile.Reconciler = &ReconcileHelmCategory{} + +// ReconcileWorkspace reconciles a Workspace object +type ReconcileHelmCategory struct { + client.Client + Scheme *runtime.Scheme + recorder record.EventRecorder + config *rest.Config +} + +// Reconcile reads that state of the cluster for a helmcategories object and makes changes based on the state read +// and what is in the helmreleases.Spec +// +kubebuilder:rbac:groups=application.kubesphere.io,resources=helmcategories,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=application.kubesphere.io,resources=helmcategories/status,verbs=get;update;patch +func (r *ReconcileHelmCategory) Reconcile(request reconcile.Request) (reconcile.Result, error) { + start := time.Now() + klog.V(4).Infof("sync helm category: %s", request.String()) + defer func() { + klog.V(4).Infof("sync helm category end: %s, elapsed: %v", request.String(), time.Now().Sub(start)) + }() + + instance := &v1alpha1.HelmCategory{} + err := r.Client.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + if errors.IsNotFound(err) { + if request.Name == v1alpha1.UncategorizedId { + err = r.ensureUncategorizedCategory() + // If create uncategorized category failed, we need create it again + return reconcile.Result{}, err + } + // Object not found, return. Created objects are automatically garbage collected. + // For additional cleanup logic use finalizers. + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + if instance.ObjectMeta.DeletionTimestamp.IsZero() { + // The object is not being deleted, so if it does not have our finalizer, + // then lets add the finalizer and update the object. + if !sliceutil.HasString(instance.ObjectMeta.Finalizers, HelmCategoryFinalizer) { + instance.ObjectMeta.Finalizers = append(instance.ObjectMeta.Finalizers, HelmCategoryFinalizer) + if err := r.Update(context.Background(), instance); err != nil { + return reconcile.Result{}, err + } + return reconcile.Result{}, nil + } + } else { + // The object is being deleted + if sliceutil.HasString(instance.ObjectMeta.Finalizers, HelmCategoryFinalizer) { + // our finalizer is present, so lets handle our external dependency + // remove our finalizer from the list and update it. + + if instance.Status.Total > 0 { + klog.Errorf("can not delete helm category: %s which owns applications", request.String()) + return reconcile.Result{}, nil + } + + instance.ObjectMeta.Finalizers = sliceutil.RemoveString(instance.ObjectMeta.Finalizers, func(item string) bool { + if item == HelmCategoryFinalizer { + return true + } + return false + }) + if err := r.Update(context.Background(), instance); err != nil { + return reconcile.Result{}, err + } + } + return reconcile.Result{}, nil + } + + err = r.updateCategoryCount(instance.Name) + if err != nil { + klog.Errorf("update helm category: %s status failed, error: %s", instance.Name, err) + return reconcile.Result{}, err + } + + return reconcile.Result{}, nil +} + +func (r *ReconcileHelmCategory) ensureUncategorizedCategory() error { + ctg := &v1alpha1.HelmCategory{} + err := r.Get(context.TODO(), types.NamespacedName{Name: v1alpha1.UncategorizedId}, ctg) + if err != nil && !errors.IsNotFound(err) { + return err + } + + ctg.Name = v1alpha1.UncategorizedId + ctg.Spec.Name = v1alpha1.UncategorizedName + ctg.Spec.Description = v1alpha1.UncategorizedName + err = r.Create(context.TODO(), ctg) + + return err +} + +func (r *ReconcileHelmCategory) updateCategoryCount(id string) error { + ctg := &v1alpha1.HelmCategory{} + err := r.Get(context.TODO(), types.NamespacedName{Name: id}, ctg) + if err != nil { + return err + } + + count, err := r.countApplications(id) + if err != nil { + return err + } + + if ctg.Status.Total == count { + return nil + } + + ctg.Status.Total = count + + err = r.Status().Update(context.TODO(), ctg) + return err +} + +func (r *ReconcileHelmCategory) countApplications(id string) (int, error) { + list := v1alpha1.HelmApplicationList{} + var err error + err = r.List(context.TODO(), &list, client.MatchingLabels{ + constants.CategoryIdLabelKey: id, + constants.ChartRepoIdLabelKey: v1alpha1.AppStoreRepoId, + }) + + if err != nil { + return 0, err + } + + count := 0 + // just count active helm application + for _, app := range list.Items { + if app.Status.State == v1alpha1.StateActive { + count += 1 + } + } + + return count, nil +} + +// add category id to helm application +func (r *ReconcileHelmCategory) updateUncategorizedApplicationLabels(app *v1alpha1.HelmApplication) error { + if app == nil { + return nil + } + if app.GetHelmRepoId() == v1alpha1.AppStoreRepoId && app.GetHelmCategoryId() == "" { + appCopy := app.DeepCopy() + appCopy.Labels[constants.CategoryIdLabelKey] = v1alpha1.UncategorizedId + patch := client.MergeFrom(app) + err := r.Client.Patch(context.TODO(), appCopy, patch) + if err != nil { + klog.Errorf("patch application: %s failed, error: %s", app.Name, err) + return err + } + } + return nil +} diff --git a/pkg/controller/openpitrix/helmcategory/helm_category_controller_suite_test.go b/pkg/controller/openpitrix/helmcategory/helm_category_controller_suite_test.go new file mode 100644 index 0000000000000000000000000000000000000000..eca73549563f85128f66b0db2fe82340f84204b5 --- /dev/null +++ b/pkg/controller/openpitrix/helmcategory/helm_category_controller_suite_test.go @@ -0,0 +1,107 @@ +/* +Copyright 2019 The KubeSphere 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 helmcategory + +import ( + "github.com/onsi/gomega/gexec" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/klog/klogr" + "kubesphere.io/kubesphere/pkg/apis" + "kubesphere.io/kubesphere/pkg/controller/openpitrix/helmapplication" + "os" + "path/filepath" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "testing" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/envtest/printer" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var k8sClient client.Client +var k8sManager ctrl.Manager +var testEnv *envtest.Environment + +func TestHelmCategoryController(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecsWithDefaultAndCustomReporters(t, + "HelmCategory Controller Test Suite", + []Reporter{printer.NewlineReporter{}}) +} + +var _ = BeforeSuite(func(done Done) { + logf.SetLogger(klogr.New()) + + By("bootstrapping test environment") + t := true + if os.Getenv("TEST_USE_EXISTING_CLUSTER") == "true" { + testEnv = &envtest.Environment{ + UseExistingCluster: &t, + } + } else { + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "..", "config", "crds")}, + AttachControlPlaneOutput: false, + } + } + + cfg, err := testEnv.Start() + Expect(err).ToNot(HaveOccurred()) + Expect(cfg).ToNot(BeNil()) + + err = apis.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + k8sManager, err = ctrl.NewManager(cfg, ctrl.Options{ + MetricsBindAddress: "0", + Scheme: scheme.Scheme, + }) + Expect(err).ToNot(HaveOccurred()) + + err = Add(k8sManager) + Expect(err).ToNot(HaveOccurred()) + + err = (&helmapplication.ReconcileHelmApplication{}).SetupWithManager(k8sManager) + Expect(err).ToNot(HaveOccurred()) + + err = (&helmapplication.ReconcileHelmApplicationVersion{}).SetupWithManager(k8sManager) + Expect(err).ToNot(HaveOccurred()) + + go func() { + err = k8sManager.Start(ctrl.SetupSignalHandler()) + Expect(err).ToNot(HaveOccurred()) + }() + + k8sClient = k8sManager.GetClient() + Expect(k8sClient).ToNot(BeNil()) + + close(done) +}, 60) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + gexec.KillAndWait(5 * time.Second) + err := testEnv.Stop() + Expect(err).ToNot(HaveOccurred()) +}) diff --git a/pkg/controller/openpitrix/helmcategory/helm_category_controller_test.go b/pkg/controller/openpitrix/helmcategory/helm_category_controller_test.go new file mode 100644 index 0000000000000000000000000000000000000000..c586d8c89e132c42385b91bf59c5a76b42c6168a --- /dev/null +++ b/pkg/controller/openpitrix/helmcategory/helm_category_controller_test.go @@ -0,0 +1,132 @@ +/* +Copyright 2019 The KubeSphere 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 helmcategory + +import ( + "context" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/utils/idutils" + "time" +) + +var _ = Describe("helmCategory", func() { + + const timeout = time.Second * 240 + const interval = time.Second * 1 + + app := createApp() + appVer := createAppVersion(app.GetHelmApplicationId()) + ctg := createCtg() + + BeforeEach(func() { + err := k8sClient.Create(context.Background(), app) + Expect(err).NotTo(HaveOccurred()) + + err = k8sClient.Create(context.Background(), appVer) + Expect(err).NotTo(HaveOccurred()) + + err = k8sClient.Create(context.Background(), ctg) + Expect(err).NotTo(HaveOccurred()) + }) + + Context("Helm category Controller", func() { + It("Should success", func() { + key := types.NamespacedName{ + Name: v1alpha1.UncategorizedId, + } + + By("Expecting category should exists") + Eventually(func() bool { + f := &v1alpha1.HelmCategory{} + k8sClient.Get(context.Background(), key, f) + return !f.CreationTimestamp.IsZero() + }, timeout, interval).Should(BeTrue()) + + By("Update helm app version status") + Eventually(func() bool { + k8sClient.Get(context.Background(), types.NamespacedName{Name: appVer.Name}, appVer) + appVer.Status = v1alpha1.HelmApplicationVersionStatus{ + State: v1alpha1.StateActive, + } + err := k8sClient.Status().Update(context.Background(), appVer) + return err == nil + }, timeout, interval).Should(BeTrue()) + + By("Wait for app status become active") + Eventually(func() bool { + appKey := types.NamespacedName{ + Name: app.Name, + } + k8sClient.Get(context.Background(), appKey, app) + return app.State() == v1alpha1.StateActive + }, timeout, interval).Should(BeTrue()) + + By("Reconcile for `uncategorized` category") + Eventually(func() bool { + key := types.NamespacedName{Name: v1alpha1.UncategorizedId} + ctg := v1alpha1.HelmCategory{} + k8sClient.Get(context.Background(), key, &ctg) + + return ctg.Status.Total == 1 + }, timeout, interval).Should(BeTrue()) + }) + }) +}) + +func createCtg() *v1alpha1.HelmCategory { + return &v1alpha1.HelmCategory{ + ObjectMeta: metav1.ObjectMeta{ + Name: idutils.GetUuid36(v1alpha1.HelmCategoryIdPrefix), + }, + Spec: v1alpha1.HelmCategorySpec{ + Name: "dummy-ctg", + }, + } +} + +func createApp() *v1alpha1.HelmApplication { + return &v1alpha1.HelmApplication{ + ObjectMeta: metav1.ObjectMeta{ + Name: idutils.GetUuid36(v1alpha1.HelmApplicationIdPrefix), + }, + Spec: v1alpha1.HelmApplicationSpec{ + Name: "dummy-chart", + }, + } +} + +func createAppVersion(appId string) *v1alpha1.HelmApplicationVersion { + return &v1alpha1.HelmApplicationVersion{ + ObjectMeta: metav1.ObjectMeta{ + Name: idutils.GetUuid36(v1alpha1.HelmApplicationVersionIdPrefix), + Labels: map[string]string{ + constants.ChartApplicationIdLabelKey: appId, + }, + }, + Spec: v1alpha1.HelmApplicationVersionSpec{ + Metadata: &v1alpha1.Metadata{ + Version: "0.0.1", + Name: "dummy-chart", + }, + }, + } +} diff --git a/pkg/controller/openpitrix/helmrelease/helm_release_controller.go b/pkg/controller/openpitrix/helmrelease/helm_release_controller.go new file mode 100644 index 0000000000000000000000000000000000000000..f1febe8ab52568137c4390f0803e543b48a2905d --- /dev/null +++ b/pkg/controller/openpitrix/helmrelease/helm_release_controller.go @@ -0,0 +1,472 @@ +/* +Copyright 2019 The KubeSphere 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 helmrelease + +import ( + "context" + "errors" + "fmt" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "k8s.io/client-go/kubernetes" + restclient "k8s.io/client-go/rest" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/client-go/tools/record" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmrepoindex" + "kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmwrapper" + "kubesphere.io/kubesphere/pkg/simple/client/s3" + "kubesphere.io/kubesphere/pkg/utils/clusterclient" + "kubesphere.io/kubesphere/pkg/utils/sliceutil" + "kubesphere.io/kubesphere/pkg/utils/stringutils" + "math" + "path" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "strings" + "time" +) + +const ( + HelmReleaseFinalizer = "helmrelease.application.kubesphere.io" + IndexerName = "clusterNamespace" +) + +var ( + ErrGetRepoFailed = errors.New("get repo failed") + ErrGetAppFailed = errors.New("get app failed") + ErrAppVersionDataIsEmpty = errors.New("app version data is empty") + ErrGetAppVersionFailed = errors.New("get app version failed") + ErrLoadChartFailed = errors.New("load chart failed") + ErrLoadChartFromStorageFailed = errors.New("load chart from storage failed") +) + +var _ reconcile.Reconciler = &ReconcileHelmRelease{} + +// ReconcileWorkspace reconciles a Workspace object +type ReconcileHelmRelease struct { + StorageClient s3.Interface + KsFactory externalversions.SharedInformerFactory + clusterClients clusterclient.ClusterClients + client.Client + recorder record.EventRecorder + // mock helm install && uninstall + helmMock bool + informer cache.SharedIndexInformer +} + +// +// <==>upgrading=================== +// | \ +// creating===>active=====>deleting=>deleted | +// \ ^ / | +// \ | /======> / +// \=>failed<========================== +// Reconcile reads that state of the cluster for a helmreleases object and makes changes based on the state read +// and what is in the helmreleases.Spec +// +kubebuilder:rbac:groups=application.kubesphere.io,resources=helmreleases,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=application.kubesphere.io,resources=helmreleases/status,verbs=get;update;patch +func (r *ReconcileHelmRelease) Reconcile(request reconcile.Request) (reconcile.Result, error) { + // Fetch the helmReleases instance + instance := &v1alpha1.HelmRelease{} + err := r.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + if apierrors.IsNotFound(err) { + // Object not found, return. Created objects are automatically garbage collected. + // For additional cleanup logic use finalizers. + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + if instance.Status.State == "" { + instance.Status.State = v1alpha1.HelmStatusCreating + instance.Status.LastUpdate = metav1.Now() + err = r.Status().Update(context.TODO(), instance) + return reconcile.Result{}, err + } + + if instance.ObjectMeta.DeletionTimestamp.IsZero() { + // The object is not being deleted, so if it does not have our finalizer, + // then lets add the finalizer and update the object. + if !sliceutil.HasString(instance.ObjectMeta.Finalizers, HelmReleaseFinalizer) { + instance.ObjectMeta.Finalizers = append(instance.ObjectMeta.Finalizers, HelmReleaseFinalizer) + // add owner References + if err := r.Update(context.Background(), instance); err != nil { + return reconcile.Result{}, err + } + return reconcile.Result{}, nil + } + } else { + // The object is being deleting + if sliceutil.HasString(instance.ObjectMeta.Finalizers, HelmReleaseFinalizer) { + + klog.V(3).Infof("helm uninstall %s/%s from host cluster", instance.GetRlsNamespace(), instance.Spec.Name) + err := r.uninstallHelmRelease(instance) + if err != nil { + return reconcile.Result{}, err + } + + klog.V(3).Infof("remove helm release %s finalizer", instance.Name) + // remove finalizer + instance.ObjectMeta.Finalizers = sliceutil.RemoveString(instance.ObjectMeta.Finalizers, func(item string) bool { + if item == HelmReleaseFinalizer { + return true + } + return false + }) + if err := r.Update(context.Background(), instance); err != nil { + return reconcile.Result{}, err + } + } + return reconcile.Result{}, nil + } + + return r.reconcile(instance) +} + +func (r *ReconcileHelmRelease) GetChartData(rls *v1alpha1.HelmRelease) (chartName string, chartData []byte, err error) { + if rls.Spec.RepoId != "" && rls.Spec.RepoId != v1alpha1.AppStoreRepoId { + // load chart data from helm repo + repo := v1alpha1.HelmRepo{} + err := r.Get(context.TODO(), types.NamespacedName{Name: rls.Spec.RepoId}, &repo) + if err != nil { + klog.Errorf("get helm repo %s failed, error: %v", rls.Spec.RepoId, err) + return chartName, chartData, ErrGetRepoFailed + } + + index, err := helmrepoindex.ByteArrayToSavedIndex([]byte(repo.Status.Data)) + + if version := index.GetApplicationVersion(rls.Spec.ApplicationId, rls.Spec.ApplicationVersionId); version != nil { + url := version.Spec.URLs[0] + if !(strings.HasPrefix(url, "https://") || strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "s3://")) { + url = repo.Spec.Url + "/" + url + } + buf, err := helmrepoindex.LoadChart(context.TODO(), url, &repo.Spec.Credential) + if err != nil { + klog.Infof("load chart failed, error: %s", err) + return chartName, chartData, ErrLoadChartFailed + } + chartData = buf.Bytes() + chartName = version.Name + } else { + klog.Errorf("get app version: %s failed", rls.Spec.ApplicationVersionId) + return chartName, chartData, ErrGetAppVersionFailed + } + } else { + // load chart data from helm application version + appVersion := &v1alpha1.HelmApplicationVersion{} + err = r.Get(context.TODO(), types.NamespacedName{Name: rls.Spec.ApplicationVersionId}, appVersion) + if err != nil { + klog.Errorf("get app version %s failed, error: %v", rls.Spec.ApplicationVersionId, err) + return chartName, chartData, ErrGetAppVersionFailed + } + + chartData, err = r.StorageClient.Read(path.Join(appVersion.GetWorkspace(), appVersion.Name)) + if err != nil { + klog.Errorf("load chart from storage failed, error: %s", err) + return chartName, chartData, ErrLoadChartFromStorageFailed + } + + chartName = appVersion.GetTrueName() + } + return +} + +func (r *ReconcileHelmRelease) reconcile(instance *v1alpha1.HelmRelease) (reconcile.Result, error) { + + if instance.Status.State == v1alpha1.HelmStatusActive && instance.Status.Version == instance.Spec.Version { + // check release status + return reconcile.Result{ + // recheck release status after 10 minutes + RequeueAfter: 10 * time.Minute, + }, nil + } + + ft := failedTimes(instance.Status.DeployStatus) + if v1alpha1.HelmStatusFailed == instance.Status.State && ft > 0 { + // exponential backoff, max delay 180s + retryAfter := time.Duration(math.Min(math.Exp2(float64(ft)), 180)) * time.Second + var lastDeploy time.Time + + if instance.Status.LastDeployed != nil { + lastDeploy = instance.Status.LastDeployed.Time + } else { + lastDeploy = instance.Status.LastUpdate.Time + } + if time.Now().Before(lastDeploy.Add(retryAfter)) { + return reconcile.Result{RequeueAfter: retryAfter}, nil + } + } + + var err error + switch instance.Status.State { + case v1alpha1.HelmStatusDeleting: + // no operation + return reconcile.Result{}, nil + case v1alpha1.HelmStatusActive: + instance.Status.State = v1alpha1.HelmStatusUpgrading + err = r.Status().Update(context.TODO(), instance) + return reconcile.Result{}, err + case v1alpha1.HelmStatusCreating: + // create new release + err = r.createOrUpgradeHelmRelease(instance, false) + case v1alpha1.HelmStatusFailed: + // check failed times + err = r.createOrUpgradeHelmRelease(instance, false) + case v1alpha1.HelmStatusUpgrading: + err = r.createOrUpgradeHelmRelease(instance, true) + case v1alpha1.HelmStatusRollbacking: + // TODO: rollback helm release + } + + now := metav1.Now() + var deployStatus v1alpha1.HelmReleaseDeployStatus + if err != nil { + instance.Status.State = v1alpha1.HelmStatusFailed + instance.Status.Message = stringutils.ShortenString(err.Error(), v1alpha1.MsgLen) + deployStatus.Message = instance.Status.Message + deployStatus.State = v1alpha1.HelmStatusFailed + } else { + instance.Status.State = v1alpha1.StateActive + instance.Status.Message = "" + instance.Status.Version = instance.Spec.Version + deployStatus.State = v1alpha1.HelmStatusSuccessful + } + + deployStatus.Time = now + instance.Status.LastUpdate = now + instance.Status.LastDeployed = &now + if len(instance.Status.DeployStatus) > 0 { + instance.Status.DeployStatus = append([]v1alpha1.HelmReleaseDeployStatus{deployStatus}, instance.Status.DeployStatus...) + if len(instance.Status.DeployStatus) >= 10 { + instance.Status.DeployStatus = instance.Status.DeployStatus[:10:10] + } + } else { + instance.Status.DeployStatus = append([]v1alpha1.HelmReleaseDeployStatus{deployStatus}) + } + + err = r.Status().Update(context.TODO(), instance) + if err != nil { + return reconcile.Result{}, err + } + + return reconcile.Result{}, nil +} + +func failedTimes(status []v1alpha1.HelmReleaseDeployStatus) int { + count := 0 + for i := range status { + if status[i].State == v1alpha1.HelmStatusFailed { + count += 1 + } + } + return count +} + +func (r *ReconcileHelmRelease) createOrUpgradeHelmRelease(rls *v1alpha1.HelmRelease, upgrade bool) error { + var chartData []byte + var err error + _, chartData, err = r.GetChartData(rls) + if err != nil { + return err + } + + if len(chartData) == 0 { + klog.Errorf("empty chart data failed, release name %s, chart name: %s", rls.Name, rls.Spec.ChartName) + return ErrAppVersionDataIsEmpty + } + + clusterName := rls.GetRlsCluster() + + var clusterConfig string + if clusterName != "" && r.KsFactory != nil { + clusterConfig, err = r.clusterClients.GetClusterKubeconfig(clusterName) + if err != nil { + klog.Errorf("get cluster %s config failed", clusterConfig) + return err + } + } + + // If clusterConfig is empty, this application will be installed in current host. + hw := helmwrapper.NewHelmWrapper(clusterConfig, rls.GetRlsNamespace(), rls.Spec.Name, helmwrapper.SetMock(r.helmMock)) + var res helmwrapper.HelmRes + if upgrade { + res, err = hw.Upgrade(rls.Spec.ChartName, string(chartData), string(rls.Spec.Values)) + } else { + res, err = hw.Install(rls.Spec.ChartName, string(chartData), string(rls.Spec.Values)) + } + if err != nil { + return errors.New(res.Message) + } + return nil +} + +func (r *ReconcileHelmRelease) uninstallHelmRelease(rls *v1alpha1.HelmRelease) error { + if rls.Status.State != v1alpha1.HelmStatusDeleting { + rls.Status.State = v1alpha1.HelmStatusDeleting + rls.Status.LastUpdate = metav1.Now() + err := r.Status().Update(context.TODO(), rls) + if err != nil { + return err + } + } + + clusterName := rls.GetRlsCluster() + var clusterConfig string + var err error + if clusterName != "" && r.KsFactory != nil { + clusterConfig, err = r.clusterClients.GetClusterKubeconfig(clusterName) + if err != nil { + klog.Errorf("get cluster %s config failed", clusterConfig) + return err + } + } + + hw := helmwrapper.NewHelmWrapper(clusterConfig, rls.GetRlsNamespace(), rls.Spec.Name, helmwrapper.SetMock(r.helmMock)) + + res, err := hw.Uninstall() + + if err != nil { + return errors.New(res.Message) + } + return nil +} + +func (r *ReconcileHelmRelease) SetupWithManager(mgr ctrl.Manager) error { + r.Client = mgr.GetClient() + if r.KsFactory != nil { + r.clusterClients = clusterclient.NewClusterClient(r.KsFactory.Cluster().V1alpha1().Clusters()) + + r.informer = r.KsFactory.Application().V1alpha1().HelmReleases().Informer() + err := r.informer.AddIndexers(map[string]cache.IndexFunc{ + IndexerName: func(obj interface{}) ([]string, error) { + rls := obj.(*v1alpha1.HelmRelease) + return []string{fmt.Sprintf("%s/%s", rls.GetRlsCluster(), rls.GetRlsNamespace())}, nil + }, + }) + if err != nil { + return err + } + + go func() { + <-mgr.Elected() + go r.cleanHelmReleaseWhenNamespaceDeleted() + }() + } + + return ctrl.NewControllerManagedBy(mgr). + For(&v1alpha1.HelmRelease{}). + Complete(r) +} + +func (r *ReconcileHelmRelease) getClusterConfig(cluster string) (string, error) { + if cluster == "" { + return "", nil + } + + clusterConfig, err := r.clusterClients.GetClusterKubeconfig(cluster) + if err != nil { + klog.Errorf("get cluster %s config failed", clusterConfig) + return "", err + } + + return clusterConfig, nil +} + +// When namespace have been removed from member cluster, we need clean all +// the helmRelease from the host cluster. +func (r *ReconcileHelmRelease) cleanHelmReleaseWhenNamespaceDeleted() { + + ticker := time.NewTicker(2 * time.Minute) + for _ = range ticker.C { + keys := r.informer.GetIndexer().ListIndexFuncValues(IndexerName) + for _, clusterNs := range keys { + klog.V(4).Infof("clean resource in %s", clusterNs) + parts := stringutils.Split(clusterNs, "/") + if len(parts) == 2 { + cluster, ns := parts[0], parts[1] + items, err := r.informer.GetIndexer().ByIndex(IndexerName, clusterNs) + if err != nil { + klog.Errorf("get items from index failed, error: %s", err) + continue + } + + kubeconfig, err := r.getClusterConfig(cluster) + if err != nil { + klog.Errorf("get cluster %s config failed, error: %s", cluster, err) + continue + } + + // connect to member or host cluster + var restConfig *restclient.Config + if kubeconfig == "" { + restConfig, err = restclient.InClusterConfig() + } else { + cc, err := clientcmd.NewClientConfigFromBytes([]byte(kubeconfig)) + if err != nil { + klog.Errorf("get client config for cluster %s failed, error: %s", cluster, err) + continue + } + restConfig, err = cc.ClientConfig() + } + + if err != nil { + klog.Errorf("build rest config for cluster %s failed, error: %s", cluster, err) + continue + } + + clientSet, err := kubernetes.NewForConfig(restConfig) + if err != nil { + klog.Errorf("create client set failed, error: %s", err) + continue + } + // check namespace exists or not + namespace, err := clientSet.CoreV1().Namespaces().Get(context.TODO(), ns, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + klog.V(2).Infof("delete all helm release in %s", clusterNs) + for ind := range items { + rls := items[ind].(*v1alpha1.HelmRelease) + err := r.Client.Delete(context.TODO(), rls) + if err != nil && !apierrors.IsNotFound(err) { + klog.Errorf("delete release %s failed", rls.Name) + } + } + } else { + klog.Errorf("get namespace %s from cluster %s failed, error: %s", ns, cluster, err) + continue + } + } else { + for ind := range items { + rls := items[ind].(*v1alpha1.HelmRelease) + if namespace.CreationTimestamp.After(rls.CreationTimestamp.Time) { + klog.V(2).Infof("delete helm release %s in %s", rls.Namespace, clusterNs) + // todo, namespace is newer than helmRelease, should we delete the helmRelease + } + } + } + } + } + } +} diff --git a/pkg/controller/openpitrix/helmrepo/helm_repo_controller.go b/pkg/controller/openpitrix/helmrepo/helm_repo_controller.go new file mode 100644 index 0000000000000000000000000000000000000000..6f4ec41e3f9ffd00967cf5f9eef18302b1bc3db2 --- /dev/null +++ b/pkg/controller/openpitrix/helmrepo/helm_repo_controller.go @@ -0,0 +1,307 @@ +/* +Copyright 2019 The KubeSphere 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 helmrepo + +import ( + "context" + "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/record" + "k8s.io/klog" + "k8s.io/utils/strings" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmrepoindex" + "kubesphere.io/kubesphere/pkg/utils/sliceutil" + "math" + "sigs.k8s.io/controller-runtime/pkg/client" + "sigs.k8s.io/controller-runtime/pkg/controller" + "sigs.k8s.io/controller-runtime/pkg/handler" + "sigs.k8s.io/controller-runtime/pkg/manager" + "sigs.k8s.io/controller-runtime/pkg/reconcile" + "sigs.k8s.io/controller-runtime/pkg/source" + "time" +) + +const ( + // min sync period in seconds + MinSyncPeriod = 180 + + MinRetryDuration = 60 + MaxRetryDuration = 600 + HelmRepoSyncStateLen = 10 + + StateSuccess = "successful" + StateFailed = "failed" + MessageLen = 512 +) + +const ( + HelmRepoFinalizer = "helmrepo.application.kubesphere.io" +) + +// Add creates a new Workspace Controller and adds it to the Manager with default RBAC. The Manager will set fields on the Controller +// and Start it when the Manager is Started. +func Add(mgr manager.Manager) error { + return add(mgr, newReconciler(mgr)) +} + +// newReconciler returns a new reconcile.Reconciler +func newReconciler(mgr manager.Manager) reconcile.Reconciler { + return &ReconcileHelmRepo{Client: mgr.GetClient(), scheme: mgr.GetScheme(), + recorder: mgr.GetEventRecorderFor("workspace-controller"), + config: mgr.GetConfig(), + } +} + +// add adds a new Controller to mgr with r as the reconcile.Reconciler +func add(mgr manager.Manager, r reconcile.Reconciler) error { + // Create a new controller + c, err := controller.New("helm-repo-controller", mgr, controller.Options{Reconciler: r}) + if err != nil { + return err + } + + // Watch for changes to HelmRelease + err = c.Watch(&source.Kind{Type: &v1alpha1.HelmRepo{}}, &handler.EnqueueRequestForObject{}) + if err != nil { + return err + } + + return nil +} + +var _ reconcile.Reconciler = &ReconcileHelmRepo{} + +// ReconcileWorkspace reconciles a Workspace object +type ReconcileHelmRepo struct { + client.Client + scheme *runtime.Scheme + recorder record.EventRecorder + config *rest.Config +} + +// Reconcile reads that state of the cluster for a helmrepoes object and makes changes based on the state read +// and what is in the helmreleases.Spec +// +kubebuilder:rbac:groups=application.kubesphere.io,resources=helmrepos,verbs=get;list;watch;create;update;patch;delete +// +kubebuilder:rbac:groups=application.kubesphere.io,resources=helmrepos/status,verbs=get;update;patch +func (r *ReconcileHelmRepo) Reconcile(request reconcile.Request) (reconcile.Result, error) { + start := time.Now() + klog.Infof("sync repo: %s", request.Name) + defer func() { + klog.Infof("sync repo end: %s, elapsed: %v", request.Name, time.Now().Sub(start)) + }() + // Fetch the helmrepoes instance + instance := &v1alpha1.HelmRepo{} + err := r.Client.Get(context.TODO(), request.NamespacedName, instance) + if err != nil { + if errors.IsNotFound(err) { + // Object not found, return. Created objects are automatically garbage collected. + // For additional cleanup logic use finalizers. + return reconcile.Result{}, nil + } + // Error reading the object - requeue the request. + return reconcile.Result{}, err + } + + if instance.ObjectMeta.DeletionTimestamp.IsZero() { + if instance.Status.State == "" { + instance.Status.State = v1alpha1.RepoStateSyncing + return reconcile.Result{}, r.Status().Update(context.Background(), instance) + } + + // The object is not being deleted, so if it does not have our finalizer, + // then lets add the finalizer and update the object. + if !sliceutil.HasString(instance.ObjectMeta.Finalizers, HelmRepoFinalizer) { + instance.ObjectMeta.Finalizers = append(instance.ObjectMeta.Finalizers, HelmRepoFinalizer) + if err := r.Update(context.Background(), instance); err != nil { + return reconcile.Result{}, err + } + return reconcile.Result{}, nil + } + } else { + // The object is being deleted + if sliceutil.HasString(instance.ObjectMeta.Finalizers, HelmRepoFinalizer) { + // remove our finalizer from the list and update it. + instance.ObjectMeta.Finalizers = sliceutil.RemoveString(instance.ObjectMeta.Finalizers, func(item string) bool { + if item == HelmRepoFinalizer { + return true + } + return false + }) + if err := r.Update(context.Background(), instance); err != nil { + return reconcile.Result{}, err + } + } + return reconcile.Result{}, nil + } + + copyInstance := instance.DeepCopy() + + if copyInstance.Spec.SyncPeriod != 0 && copyInstance.Spec.SyncPeriod < MinSyncPeriod { + copyInstance.Spec.SyncPeriod = MinSyncPeriod + } + + retryAfter := 0 + if syncNow, after := needReSyncNow(copyInstance); syncNow { + // sync repo + syncErr := r.syncRepo(copyInstance) + state := copyInstance.Status.SyncState + now := metav1.Now() + if syncErr != nil { + // failed + state = append([]v1alpha1.HelmRepoSyncState{{ + State: v1alpha1.RepoStateFailed, + Message: strings.ShortenString(syncErr.Error(), MessageLen), + SyncTime: &now, + }}, state...) + copyInstance.Status.State = v1alpha1.RepoStateFailed + } else { + state = append([]v1alpha1.HelmRepoSyncState{{ + State: v1alpha1.RepoStateSuccessful, + SyncTime: &now, + }}, state...) + + copyInstance.Status.Version = instance.Spec.Version + copyInstance.Status.State = v1alpha1.RepoStateSuccessful + } + + copyInstance.Status.LastUpdateTime = &now + if len(state) > HelmRepoSyncStateLen { + state = state[0:HelmRepoSyncStateLen] + } + copyInstance.Status.SyncState = state + + err = r.Client.Status().Update(context.TODO(), copyInstance) + if err != nil { + klog.Errorf("update status failed, error: %s", err) + return reconcile.Result{ + RequeueAfter: MinRetryDuration * time.Second, + }, err + } else { + retryAfter = MinSyncPeriod + if syncErr == nil { + retryAfter = copyInstance.Spec.SyncPeriod + } + } + } else { + retryAfter = after + } + + return reconcile.Result{ + RequeueAfter: time.Duration(retryAfter) * time.Second, + }, nil +} + +// needReSyncNow checks instance whether need resync now +// if resync is true, it should resync not +// if resync is false and after > 0, it should resync in after seconds +func needReSyncNow(instance *v1alpha1.HelmRepo) (syncNow bool, after int) { + + now := time.Now() + if instance.Status.SyncState == nil || len(instance.Status.SyncState) == 0 { + return true, 0 + } + + states := instance.Status.SyncState + + failedTimes := 0 + for i := range states { + if states[i].State != StateSuccess { + failedTimes += 1 + } else { + break + } + } + + state := states[0] + + if instance.Spec.Version != instance.Status.Version && failedTimes == 0 { + // repo has a successful synchronization + diff := now.Sub(state.SyncTime.Time) / time.Second + if diff > 0 && diff < MinRetryDuration { + return false, int(math.Max(10, float64(MinRetryDuration-diff))) + } else { + return true, 0 + } + } + + period := 0 + if state.State != StateSuccess { + period = MinRetryDuration * failedTimes + if period > MaxRetryDuration { + period = MaxRetryDuration + } + if now.After(state.SyncTime.Add(time.Duration(period) * time.Second)) { + return true, 0 + } + } else { + period = instance.Spec.SyncPeriod + if period != 0 { + if period < MinSyncPeriod { + period = MinSyncPeriod + } + if now.After(state.SyncTime.Add(time.Duration(period) * time.Second)) { + return true, 0 + } + } else { + // need not to sync + return false, 0 + } + } + + after = int(state.SyncTime.Time.Add(time.Duration(period) * time.Second).Sub(now).Seconds()) + + // may be less than 10 second + if after <= 10 { + after = 10 + } + return false, after +} + +func (r *ReconcileHelmRepo) syncRepo(instance *v1alpha1.HelmRepo) error { + // 1. load index from helm repo + index, err := helmrepoindex.LoadRepoIndex(context.TODO(), instance.Spec.Url, &instance.Spec.Credential) + + if err != nil { + klog.Errorf("load index failed, repo: %s, url: %s, err: %s", instance.GetTrueName(), instance.Spec.Url, err) + return err + } + + existsSavedIndex := &helmrepoindex.SavedIndex{} + if len(instance.Status.Data) != 0 { + existsSavedIndex, err = helmrepoindex.ByteArrayToSavedIndex([]byte(instance.Status.Data)) + if err != nil { + klog.Errorf("json unmarshal failed, repo: %s, error: %s", instance.GetTrueName(), err) + return err + } + } + + // 2. merge new index with old index which is stored in crd + savedIndex := helmrepoindex.MergeRepoIndex(index, existsSavedIndex) + + // 3. save index in crd + data, err := savedIndex.Bytes() + if err != nil { + klog.Errorf("json marshal failed, error: %s", err) + return err + } + + instance.Status.Data = string(data) + return nil +} diff --git a/pkg/controller/openpitrix/helmrepo/helm_repo_controller_suite_test.go b/pkg/controller/openpitrix/helmrepo/helm_repo_controller_suite_test.go new file mode 100644 index 0000000000000000000000000000000000000000..75c6e1ec41a1c38db2465b172937a9e8dce01f15 --- /dev/null +++ b/pkg/controller/openpitrix/helmrepo/helm_repo_controller_suite_test.go @@ -0,0 +1,100 @@ +/* +Copyright 2019 The KubeSphere 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 helmrepo + +import ( + "github.com/onsi/gomega/gexec" + "k8s.io/client-go/kubernetes/scheme" + "k8s.io/klog/klogr" + "kubesphere.io/kubesphere/pkg/apis" + "os" + "path/filepath" + ctrl "sigs.k8s.io/controller-runtime" + "sigs.k8s.io/controller-runtime/pkg/client" + logf "sigs.k8s.io/controller-runtime/pkg/log" + "testing" + "time" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + "sigs.k8s.io/controller-runtime/pkg/envtest" + "sigs.k8s.io/controller-runtime/pkg/envtest/printer" +) + +// These tests use Ginkgo (BDD-style Go testing framework). Refer to +// http://onsi.github.io/ginkgo/ to learn more about Ginkgo. + +var k8sClient client.Client +var k8sManager ctrl.Manager +var testEnv *envtest.Environment + +func TestHelmRepoController(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecsWithDefaultAndCustomReporters(t, + "HelmRepo Controller Test Suite", + []Reporter{printer.NewlineReporter{}}) +} + +var _ = BeforeSuite(func(done Done) { + logf.SetLogger(klogr.New()) + + By("bootstrapping test environment") + t := true + if os.Getenv("TEST_USE_EXISTING_CLUSTER") == "true" { + testEnv = &envtest.Environment{ + UseExistingCluster: &t, + } + } else { + testEnv = &envtest.Environment{ + CRDDirectoryPaths: []string{filepath.Join("..", "..", "..", "..", "config", "crds")}, + AttachControlPlaneOutput: false, + } + } + + cfg, err := testEnv.Start() + Expect(err).ToNot(HaveOccurred()) + Expect(cfg).ToNot(BeNil()) + + err = apis.AddToScheme(scheme.Scheme) + Expect(err).NotTo(HaveOccurred()) + + k8sManager, err = ctrl.NewManager(cfg, ctrl.Options{ + Scheme: scheme.Scheme, + MetricsBindAddress: "0", + }) + Expect(err).ToNot(HaveOccurred()) + + err = Add(k8sManager) + Expect(err).ToNot(HaveOccurred()) + + go func() { + err = k8sManager.Start(ctrl.SetupSignalHandler()) + Expect(err).ToNot(HaveOccurred()) + }() + + k8sClient = k8sManager.GetClient() + Expect(k8sClient).ToNot(BeNil()) + + close(done) +}, 60) + +var _ = AfterSuite(func() { + By("tearing down the test environment") + gexec.KillAndWait(5 * time.Second) + err := testEnv.Stop() + Expect(err).ToNot(HaveOccurred()) +}) diff --git a/pkg/controller/openpitrix/helmrepo/helm_repo_controller_test.go b/pkg/controller/openpitrix/helmrepo/helm_repo_controller_test.go new file mode 100644 index 0000000000000000000000000000000000000000..bdd34c3d503dda2755c7b120ab20dff935947822 --- /dev/null +++ b/pkg/controller/openpitrix/helmrepo/helm_repo_controller_test.go @@ -0,0 +1,69 @@ +/* +Copyright 2019 The KubeSphere 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 helmrepo + +import ( + "context" + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/types" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/utils/idutils" + "time" +) + +var repoUrl = "https://charts.kubesphere.io/main" + +var _ = Describe("helmRepo", func() { + + const timeout = time.Second * 360 + const interval = time.Second * 1 + + repo := createRepo() + + BeforeEach(func() { + err := k8sClient.Create(context.Background(), repo) + Expect(err).NotTo(HaveOccurred()) + }) + + Context("Helm Repo Controller", func() { + It("Should success", func() { + key := types.NamespacedName{ + Name: repo.Name, + } + + By("Expecting repo state is successful") + Eventually(func() bool { + repo := &v1alpha1.HelmRepo{} + k8sClient.Get(context.Background(), key, repo) + return repo.Status.State == v1alpha1.RepoStateSuccessful && len(repo.Status.Data) > 0 + }, timeout, interval).Should(BeTrue()) + }) + }) +}) + +func createRepo() *v1alpha1.HelmRepo { + return &v1alpha1.HelmRepo{ + ObjectMeta: metav1.ObjectMeta{ + Name: idutils.GetUuid36(v1alpha1.HelmRepoIdPrefix), + }, + Spec: v1alpha1.HelmRepoSpec{ + Url: repoUrl, + }, + } +} diff --git a/pkg/controller/workspacetemplate/workspacetemplate_controller.go b/pkg/controller/workspacetemplate/workspacetemplate_controller.go index a58fa43625fdbf9a1d8a082b6a36b4c9ad035ab0..2d5a38a497f7172b4c9596357dd5d32290580136 100644 --- a/pkg/controller/workspacetemplate/workspacetemplate_controller.go +++ b/pkg/controller/workspacetemplate/workspacetemplate_controller.go @@ -25,16 +25,19 @@ import ( rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/types" "k8s.io/apimachinery/pkg/util/yaml" "k8s.io/client-go/kubernetes/scheme" "k8s.io/client-go/tools/record" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" iamv1alpha2 "kubesphere.io/kubesphere/pkg/apis/iam/v1alpha2" tenantv1alpha1 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1" tenantv1alpha2 "kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha2" typesv1beta1 "kubesphere.io/kubesphere/pkg/apis/types/v1beta1" "kubesphere.io/kubesphere/pkg/constants" controllerutils "kubesphere.io/kubesphere/pkg/controller/utils/controller" + "kubesphere.io/kubesphere/pkg/utils/sliceutil" "reflect" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" @@ -43,7 +46,8 @@ import ( ) const ( - controllerName = "workspacetemplate-controller" + controllerName = "workspacetemplate-controller" + workspaceTemplateFinalizer = "finalizers.workspacetemplate.kubesphere.io" ) // Reconciler reconciles a WorkspaceRoleBinding object @@ -88,6 +92,37 @@ func (r *Reconciler) Reconcile(req ctrl.Request) (ctrl.Result, error) { return ctrl.Result{}, client.IgnoreNotFound(err) } + if workspaceTemplate.ObjectMeta.DeletionTimestamp.IsZero() { + // The object is not being deleted, so if it does not have our finalizer, + // then lets add the finalizer and update the object. + if !sliceutil.HasString(workspaceTemplate.ObjectMeta.Finalizers, workspaceTemplateFinalizer) { + workspaceTemplate.ObjectMeta.Finalizers = append(workspaceTemplate.ObjectMeta.Finalizers, workspaceTemplateFinalizer) + if err := r.Update(rootCtx, workspaceTemplate); err != nil { + return ctrl.Result{}, err + } + } + } else { + // The object is being deleted + if sliceutil.HasString(workspaceTemplate.ObjectMeta.Finalizers, workspaceTemplateFinalizer) { + if err := r.deleteOpenPitrixResourcesInWorkspace(rootCtx, workspaceTemplate.Name); err != nil { + logger.Error(err, "delete resource in workspace template failed") + return ctrl.Result{}, err + } + + // remove our finalizer from the list and update it. + workspaceTemplate.ObjectMeta.Finalizers = sliceutil.RemoveString(workspaceTemplate.ObjectMeta.Finalizers, func(item string) bool { + return item == workspaceTemplateFinalizer + }) + logger.V(4).Info("update workspace template") + if err := r.Update(rootCtx, workspaceTemplate); err != nil { + logger.Error(err, "update workspace template failed") + return ctrl.Result{}, err + } + } + // Our finalizer has finished, so the reconciler can do nothing. + return ctrl.Result{}, nil + } + if r.MultiClusterEnabled { if err := r.multiClusterSync(rootCtx, logger, workspaceTemplate); err != nil { return ctrl.Result{}, err @@ -301,6 +336,81 @@ func (r *Reconciler) initManagerRoleBinding(ctx context.Context, logger logr.Log return nil } +func (r *Reconciler) deleteOpenPitrixResourcesInWorkspace(ctx context.Context, ws string) error { + if len(ws) == 0 { + return nil + } + + var err error + // helm release, apps and appVersion only exist in host cluster. Delete these resource in workspace template controller + if err = r.deleteHelmReleases(ctx, ws); err != nil { + return err + } + + if err = r.deleteHelmApps(ctx, ws); err != nil { + return err + } + + if err = r.deleteHelmRepos(ctx, ws); err != nil { + return err + } + + return nil +} + +func (r *Reconciler) deleteHelmApps(ctx context.Context, ws string) error { + if len(ws) == 0 { + return nil + } + + apps := v1alpha1.HelmApplicationList{} + err := r.List(ctx, &apps, &client.ListOptions{LabelSelector: labels.SelectorFromSet(map[string]string{ + constants.WorkspaceLabelKey: ws}), + }) + if err != nil { + return err + } + for i := range apps.Items { + state := apps.Items[i].Status.State + // active and suspended applications belong to app store, they should not be removed here. + if !(state == v1alpha1.StateActive || state == v1alpha1.StateSuspended) { + err = r.Delete(ctx, &apps.Items[i]) + if err != nil { + return err + } + } + } + + return nil +} + +// Delete all helm releases in the workspace ws +func (r *Reconciler) deleteHelmReleases(ctx context.Context, ws string) error { + if len(ws) == 0 { + return nil + } + rls := &v1alpha1.HelmRelease{} + err := r.DeleteAllOf(ctx, rls, &client.DeleteAllOfOptions{ + ListOptions: client.ListOptions{LabelSelector: labels.SelectorFromSet(map[string]string{ + constants.WorkspaceLabelKey: ws, + }), + }}) + return err +} + +func (r *Reconciler) deleteHelmRepos(ctx context.Context, ws string) error { + if len(ws) == 0 { + return nil + } + rls := &v1alpha1.HelmRepo{} + err := r.DeleteAllOf(ctx, rls, &client.DeleteAllOfOptions{ + ListOptions: client.ListOptions{LabelSelector: labels.SelectorFromSet(map[string]string{ + constants.WorkspaceLabelKey: ws, + }), + }}) + + return err +} func workspaceRoleBindingChanger(workspaceRoleBinding *iamv1alpha2.WorkspaceRoleBinding, workspace, username, workspaceRoleName string) controllerutil.MutateFn { return func() error { diff --git a/pkg/controller/workspacetemplate/workspacetemplate_controller_suite_test.go b/pkg/controller/workspacetemplate/workspacetemplate_controller_suite_test.go index 2e3c77b3e5dbd05e83341a9646c149e579e9bb3c..a1f69224f98a550c5801c0e04d871a188d850218 100644 --- a/pkg/controller/workspacetemplate/workspacetemplate_controller_suite_test.go +++ b/pkg/controller/workspacetemplate/workspacetemplate_controller_suite_test.go @@ -18,9 +18,11 @@ package workspacetemplate import ( "github.com/onsi/gomega/gexec" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" "k8s.io/client-go/kubernetes/scheme" "k8s.io/klog/klogr" "kubesphere.io/kubesphere/pkg/apis" + helmappscheme "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" "os" "path/filepath" ctrl "sigs.k8s.io/controller-runtime" @@ -78,6 +80,8 @@ var _ = BeforeSuite(func(done Done) { }) Expect(err).ToNot(HaveOccurred()) + utilruntime.Must(helmappscheme.AddToScheme(k8sManager.GetScheme())) + err = (&Reconciler{}).SetupWithManager(k8sManager) Expect(err).ToNot(HaveOccurred()) diff --git a/pkg/kapis/metering/v1alpha1/handler.go b/pkg/kapis/metering/v1alpha1/handler.go index da722a97ef01488eb1a93b739f3f251ecc4d5cc9..f19bf17c894038ebe68478b7b9c0fdc245bfe2a2 100644 --- a/pkg/kapis/metering/v1alpha1/handler.go +++ b/pkg/kapis/metering/v1alpha1/handler.go @@ -25,7 +25,6 @@ import ( monitorhle "kubesphere.io/kubesphere/pkg/kapis/monitoring/v1alpha3" resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource" "kubesphere.io/kubesphere/pkg/simple/client/monitoring" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" ) type meterHandler interface { @@ -40,6 +39,6 @@ type meterHandler interface { HandlePVCMetersQuery(req *restful.Request, resp *restful.Response) } -func newHandler(k kubernetes.Interface, m monitoring.Interface, f informers.InformerFactory, o openpitrix.Client, resourceGetter *resourcev1alpha3.ResourceGetter) meterHandler { - return monitorhle.NewHandler(k, m, nil, f, o, resourceGetter) +func newHandler(k kubernetes.Interface, m monitoring.Interface, f informers.InformerFactory, resourceGetter *resourcev1alpha3.ResourceGetter) meterHandler { + return monitorhle.NewHandler(k, m, nil, f, resourceGetter) } diff --git a/pkg/kapis/metering/v1alpha1/register.go b/pkg/kapis/metering/v1alpha1/register.go index fb00da15e2dfbb04706bffa726d70753b956227f..4cf4a0b810ea6c410e2397859d309cb86a9573fb 100644 --- a/pkg/kapis/metering/v1alpha1/register.go +++ b/pkg/kapis/metering/v1alpha1/register.go @@ -31,7 +31,6 @@ import ( model "kubesphere.io/kubesphere/pkg/models/monitoring" resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource" "kubesphere.io/kubesphere/pkg/simple/client/monitoring" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" "sigs.k8s.io/controller-runtime/pkg/cache" ) @@ -42,10 +41,10 @@ const ( var GroupVersion = schema.GroupVersion{Group: groupName, Version: "v1alpha1"} -func AddToContainer(c *restful.Container, k8sClient kubernetes.Interface, meteringClient monitoring.Interface, factory informers.InformerFactory, opClient openpitrix.Client, cache cache.Cache) error { +func AddToContainer(c *restful.Container, k8sClient kubernetes.Interface, meteringClient monitoring.Interface, factory informers.InformerFactory, cache cache.Cache) error { ws := runtime.NewWebService(GroupVersion) - h := newHandler(k8sClient, meteringClient, factory, opClient, resourcev1alpha3.NewResourceGetter(factory, cache)) + h := newHandler(k8sClient, meteringClient, factory, resourcev1alpha3.NewResourceGetter(factory, cache)) ws.Route(ws.GET("/cluster"). To(h.HandleClusterMetersQuery). diff --git a/pkg/kapis/monitoring/v1alpha3/handler.go b/pkg/kapis/monitoring/v1alpha3/handler.go index 191ba1bb2581091eb2da26de1c48f21b18e36ed6..ab098e27f8be499a3e81a4f565c20c9919ab1613 100644 --- a/pkg/kapis/monitoring/v1alpha3/handler.go +++ b/pkg/kapis/monitoring/v1alpha3/handler.go @@ -30,7 +30,6 @@ import ( model "kubesphere.io/kubesphere/pkg/models/monitoring" resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource" "kubesphere.io/kubesphere/pkg/simple/client/monitoring" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" ) type handler struct { @@ -38,8 +37,8 @@ type handler struct { mo model.MonitoringOperator } -func NewHandler(k kubernetes.Interface, monitoringClient monitoring.Interface, metricsClient monitoring.Interface, f informers.InformerFactory, o openpitrix.Client, resourceGetter *resourcev1alpha3.ResourceGetter) *handler { - return &handler{k, model.NewMonitoringOperator(monitoringClient, metricsClient, k, f, o, resourceGetter)} +func NewHandler(k kubernetes.Interface, monitoringClient monitoring.Interface, metricsClient monitoring.Interface, f informers.InformerFactory, resourceGetter *resourcev1alpha3.ResourceGetter) *handler { + return &handler{k, model.NewMonitoringOperator(monitoringClient, metricsClient, k, f, resourceGetter)} } func (h handler) handleKubeSphereMetricsQuery(req *restful.Request, resp *restful.Response) { diff --git a/pkg/kapis/monitoring/v1alpha3/helper_test.go b/pkg/kapis/monitoring/v1alpha3/helper_test.go index 97eaaa01665c4eb672480419c2dbe7490b1295fb..317099464bbdfb006d0e744825f56c5f68ed8892 100644 --- a/pkg/kapis/monitoring/v1alpha3/helper_test.go +++ b/pkg/kapis/monitoring/v1alpha3/helper_test.go @@ -222,8 +222,7 @@ func TestParseRequestParams(t *testing.T) { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { client := fake.NewSimpleClientset(&tt.namespace) fakeInformerFactory := informers.NewInformerFactories(client, nil, nil, nil, nil, nil) - handler := NewHandler(client, nil, nil, fakeInformerFactory, nil, nil) - + handler := NewHandler(client, nil, nil, fakeInformerFactory, nil) result, err := handler.makeQueryOptions(tt.params, tt.lvl) if err != nil { if !tt.expectedErr { diff --git a/pkg/kapis/monitoring/v1alpha3/register.go b/pkg/kapis/monitoring/v1alpha3/register.go index 51e143a1a89091d97191e7b57211b3bb71c98747..41e2aed4a554477417952021f75939cea71e7266 100644 --- a/pkg/kapis/monitoring/v1alpha3/register.go +++ b/pkg/kapis/monitoring/v1alpha3/register.go @@ -29,7 +29,6 @@ import ( "kubesphere.io/kubesphere/pkg/informers" model "kubesphere.io/kubesphere/pkg/models/monitoring" "kubesphere.io/kubesphere/pkg/simple/client/monitoring" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" ) const ( @@ -39,10 +38,10 @@ const ( var GroupVersion = schema.GroupVersion{Group: groupName, Version: "v1alpha3"} -func AddToContainer(c *restful.Container, k8sClient kubernetes.Interface, monitoringClient monitoring.Interface, metricsClient monitoring.Interface, factory informers.InformerFactory, opClient openpitrix.Client) error { +func AddToContainer(c *restful.Container, k8sClient kubernetes.Interface, monitoringClient monitoring.Interface, metricsClient monitoring.Interface, factory informers.InformerFactory) error { ws := runtime.NewWebService(GroupVersion) - h := NewHandler(k8sClient, monitoringClient, metricsClient, factory, opClient, nil) + h := NewHandler(k8sClient, monitoringClient, metricsClient, factory, nil) ws.Route(ws.GET("/kubesphere"). To(h.handleKubeSphereMetricsQuery). diff --git a/pkg/kapis/openpitrix/v1/handler.go b/pkg/kapis/openpitrix/v1/handler.go index 014c10f8733a4e63fd7a0a81bc29ce07429cb6c0..c0a7d791c5546a806ba16e6e8db442e579fecbcf 100644 --- a/pkg/kapis/openpitrix/v1/handler.go +++ b/pkg/kapis/openpitrix/v1/handler.go @@ -14,70 +14,126 @@ limitations under the License. package v1 import ( + "encoding/json" "fmt" "github.com/emicklei/go-restful" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" - k8sinformers "k8s.io/client-go/informers" + "io/ioutil" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/klog" "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/request" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned" "kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/models/openpitrix" "kubesphere.io/kubesphere/pkg/server/errors" "kubesphere.io/kubesphere/pkg/server/params" - op "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" + openpitrixoptions "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" + "kubesphere.io/kubesphere/pkg/simple/client/s3" + "kubesphere.io/kubesphere/pkg/utils/idutils" + "kubesphere.io/kubesphere/pkg/utils/stringutils" + "net/url" "strconv" "strings" ) type openpitrixHandler struct { openpitrix openpitrix.Interface - informers k8sinformers.SharedInformerFactory } -func newOpenpitrixHandler(factory informers.InformerFactory, opClient op.Client) *openpitrixHandler { +func newOpenpitrixHandler(ksInformers informers.InformerFactory, ksClient versioned.Interface, option *openpitrixoptions.Options) *openpitrixHandler { + var s3Client s3.Interface + if option != nil && option.S3Options != nil && len(option.S3Options.Endpoint) != 0 { + var err error + s3Client, err = s3.NewS3Client(option.S3Options) + if err != nil { + klog.Errorf("failed to connect to storage, please check storage service status, error: %v", err) + } + } return &openpitrixHandler{ - openpitrix: openpitrix.NewOpenpitrixOperator(factory.KubernetesSharedInformerFactory(), opClient), - informers: factory.KubernetesSharedInformerFactory(), + openpitrix.NewOpenpitrixOperator(ksInformers, ksClient, s3Client), } } -func (h *openpitrixHandler) ListApplications(req *restful.Request, resp *restful.Response) { - limit, offset := params.ParsePaging(req) - clusterName := req.PathParameter("cluster") - namespace := req.PathParameter("namespace") - orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime) - reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false) - conditions, err := params.ParseConditions(req) +func (h *openpitrixHandler) CreateRepo(req *restful.Request, resp *restful.Response) { + createRepoRequest := &openpitrix.CreateRepoRequest{} + err := req.ReadEntity(createRepoRequest) if err != nil { klog.V(4).Infoln(err) api.HandleBadRequest(resp, nil, err) return } - conditions.Match[openpitrix.Zone] = namespace - // in openpitrix, runtime id is the cluster name - conditions.Match[openpitrix.RuntimeId] = clusterName - result, err := h.openpitrix.ListApplications(conditions, limit, offset, orderBy, reverse) + createRepoRequest.Workspace = new(string) + *createRepoRequest.Workspace = req.PathParameter("workspace") + user, _ := request.UserFrom(req.Request.Context()) + creator := "" + if user != nil { + creator = user.GetName() + } + parsedUrl, err := url.Parse(createRepoRequest.URL) if err != nil { - klog.Errorln(err) - api.HandleInternalError(resp, nil, err) + api.HandleBadRequest(resp, nil, err) return } - resp.WriteAsJson(result) -} + repo := v1alpha1.HelmRepo{ + ObjectMeta: metav1.ObjectMeta{ + Name: idutils.GetUuid36(v1alpha1.HelmRepoIdPrefix), + Annotations: map[string]string{ + constants.CreatorAnnotationKey: creator, + }, + Labels: map[string]string{ + constants.WorkspaceLabelKey: *createRepoRequest.Workspace, + }, + }, + Spec: v1alpha1.HelmRepoSpec{ + Name: createRepoRequest.Name, + Url: createRepoRequest.URL, + SyncPeriod: 0, + Description: stringutils.ShortenString(createRepoRequest.Description, 512), + }, + } + + if strings.HasPrefix(createRepoRequest.URL, "https://") || strings.HasPrefix(createRepoRequest.URL, "http://") { + if parsedUrl.User != nil { + repo.Spec.Credential.Username = parsedUrl.User.Username() + repo.Spec.Credential.Password, _ = parsedUrl.User.Password() + } + } else if strings.HasPrefix(createRepoRequest.URL, "s3://") { + cfg := v1alpha1.S3Config{} + err := json.Unmarshal([]byte(createRepoRequest.Credential), &cfg) + if err != nil { + api.HandleBadRequest(resp, nil, err) + return + } + repo.Spec.Credential.S3Config = cfg + } -func (h *openpitrixHandler) DescribeApplication(req *restful.Request, resp *restful.Response) { - clusterName := req.PathParameter("cluster") - namespace := req.PathParameter("namespace") - applicationId := req.PathParameter("application") + var result interface{} + // 1. validate repo + result, err = h.openpitrix.ValidateRepo(createRepoRequest.URL, &repo.Spec.Credential) + if err != nil { + klog.Errorf("validate repo failed, err: %s", err) + api.HandleBadRequest(resp, nil, err) + return + } - app, err := h.openpitrix.DescribeApplication(namespace, applicationId, clusterName) + // 2. create repo + validate, _ := strconv.ParseBool(req.QueryParameter("validate")) + if !validate { + if repo.GetTrueName() == "" { + api.HandleBadRequest(resp, nil, fmt.Errorf("repo name is empty")) + return + } + result, err = h.openpitrix.CreateRepo(&repo) + } if err != nil { klog.Errorln(err) @@ -85,77 +141,74 @@ func (h *openpitrixHandler) DescribeApplication(req *restful.Request, resp *rest return } - resp.WriteEntity(app) - return + resp.WriteEntity(result) } -func (h *openpitrixHandler) CreateApplication(req *restful.Request, resp *restful.Response) { - clusterName := req.PathParameter("cluster") - namespace := req.PathParameter("namespace") - var createClusterRequest openpitrix.CreateClusterRequest - err := req.ReadEntity(&createClusterRequest) +func (h *openpitrixHandler) DoRepoAction(req *restful.Request, resp *restful.Response) { + repoActionRequest := &openpitrix.RepoActionRequest{} + repoId := req.PathParameter("repo") + err := req.ReadEntity(repoActionRequest) if err != nil { klog.V(4).Infoln(err) api.HandleBadRequest(resp, nil, err) return } + repoActionRequest.Workspace = req.PathParameter("workspace") - createClusterRequest.Username = req.HeaderParameter(constants.UserNameHeader) - - err = h.openpitrix.CreateApplication(clusterName, namespace, createClusterRequest) + err = h.openpitrix.DoRepoAction(repoId, repoActionRequest) if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, nil, err) + handleOpenpitrixError(resp, err) return } resp.WriteEntity(errors.None) } -func (h *openpitrixHandler) ModifyApplication(req *restful.Request, resp *restful.Response) { - var modifyClusterAttributesRequest openpitrix.ModifyClusterAttributesRequest - clusterName := req.PathParameter("cluster") - applicationId := req.PathParameter("application") - namespace := req.PathParameter("namespace") - err := req.ReadEntity(&modifyClusterAttributesRequest) - if err != nil { - klog.V(4).Infoln(err) - api.HandleBadRequest(resp, nil, err) - return - } +func (h *openpitrixHandler) DeleteRepo(req *restful.Request, resp *restful.Response) { + repoId := req.PathParameter("repo") - app, err := h.openpitrix.DescribeApplication(namespace, applicationId, clusterName) + err := h.openpitrix.DeleteRepo(repoId) if err != nil { klog.Errorln(err) handleOpenpitrixError(resp, err) return + } else { + klog.V(4).Info("delete repo: ", repoId) } - if clusterName != app.Cluster.RuntimeId { - err = fmt.Errorf("runtime and cluster not match %s,%s", app.Cluster.RuntimeId, clusterName) + resp.WriteEntity(errors.None) +} + +func (h *openpitrixHandler) ModifyRepo(req *restful.Request, resp *restful.Response) { + var updateRepoRequest openpitrix.ModifyRepoRequest + repoId := req.PathParameter("repo") + err := req.ReadEntity(&updateRepoRequest) + if err != nil { klog.V(4).Infoln(err) - api.HandleForbidden(resp, nil, err) + api.HandleBadRequest(resp, nil, err) return } - err = h.openpitrix.ModifyApplication(modifyClusterAttributesRequest) + err = h.openpitrix.ModifyRepo(repoId, &updateRepoRequest) if err != nil { klog.Errorln(err) handleOpenpitrixError(resp, err) return + } else { + klog.V(4).Info("modify repo: ", repoId) } resp.WriteEntity(errors.None) } -func (h *openpitrixHandler) DeleteApplication(req *restful.Request, resp *restful.Response) { - clusterName := req.PathParameter("cluster") - applicationId := req.PathParameter("application") - namespace := req.PathParameter("namespace") - app, err := h.openpitrix.DescribeApplication(namespace, applicationId, clusterName) +func (h *openpitrixHandler) DescribeRepo(req *restful.Request, resp *restful.Response) { + repoId := req.PathParameter("repo") + + result, err := h.openpitrix.DescribeRepo(repoId) if err != nil { klog.Errorln(err) @@ -163,14 +216,26 @@ func (h *openpitrixHandler) DeleteApplication(req *restful.Request, resp *restfu return } - if clusterName != app.Cluster.RuntimeId { - err = fmt.Errorf("runtime and cluster not match %s,%s", app.Cluster.RuntimeId, clusterName) + resp.WriteEntity(result) +} + +func (h *openpitrixHandler) ListRepos(req *restful.Request, resp *restful.Response) { + limit, offset := params.ParsePaging(req) + orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime) + reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false) + conditions, err := params.ParseConditions(req) + + if err != nil { klog.V(4).Infoln(err) - api.HandleForbidden(resp, nil, err) + api.HandleBadRequest(resp, nil, err) return } - err = h.openpitrix.DeleteApplication(applicationId) + if req.PathParameter("workspace") != "" { + conditions.Match[openpitrix.WorkspaceLabel] = req.PathParameter("workspace") + } + + result, err := h.openpitrix.ListRepos(conditions, orderBy, reverse, limit, offset) if err != nil { klog.Errorln(err) @@ -178,24 +243,21 @@ func (h *openpitrixHandler) DeleteApplication(req *restful.Request, resp *restfu return } - resp.WriteEntity(errors.None) + resp.WriteEntity(result) } -func (h *openpitrixHandler) UpgradeApplication(req *restful.Request, resp *restful.Response) { - clusterName := req.PathParameter("cluster") - namespace := req.PathParameter("namespace") - applicationId := req.PathParameter("application") - var upgradeClusterRequest openpitrix.UpgradeClusterRequest - err := req.ReadEntity(&upgradeClusterRequest) +func (h *openpitrixHandler) ListRepoEvents(req *restful.Request, resp *restful.Response) { + repoId := req.PathParameter("repo") + limit, offset := params.ParsePaging(req) + conditions, err := params.ParseConditions(req) + if err != nil { klog.V(4).Infoln(err) api.HandleBadRequest(resp, nil, err) return } - upgradeClusterRequest.Username = req.HeaderParameter(constants.UserNameHeader) - - app, err := h.openpitrix.DescribeApplication(namespace, applicationId, clusterName) + result, err := h.openpitrix.ListRepoEvents(repoId, conditions, limit, offset) if err != nil { klog.Errorln(err) @@ -203,38 +265,27 @@ func (h *openpitrixHandler) UpgradeApplication(req *restful.Request, resp *restf return } - if clusterName != app.Cluster.RuntimeId { - err = fmt.Errorf("runtime and cluster not match %s,%s", app.Cluster.RuntimeId, clusterName) + resp.WriteEntity(result) +} + +func handleOpenpitrixError(resp *restful.Response, err error) { + if status.Code(err) == codes.NotFound { klog.V(4).Infoln(err) - api.HandleForbidden(resp, nil, err) + api.HandleNotFound(resp, nil, err) return } - - err = h.openpitrix.UpgradeApplication(upgradeClusterRequest) - - if err != nil { - klog.Errorln(err) - api.HandleInternalError(resp, nil, err) + if status.Code(err) == codes.InvalidArgument || status.Code(err) == codes.FailedPrecondition { + klog.V(4).Infoln(err) + api.HandleBadRequest(resp, nil, err) return } - - resp.WriteEntity(errors.None) + klog.Errorln(err) + api.HandleInternalError(resp, nil, err) } -func (h *openpitrixHandler) GetAppVersionPackage(req *restful.Request, resp *restful.Response) { - appId := req.PathParameter("app") - versionId := req.PathParameter("version") - - result, err := h.openpitrix.GetAppVersionPackage(appId, versionId) - - if err != nil { - klog.Errorln(err) - api.HandleInternalError(resp, nil, err) - return - } - - resp.WriteEntity(result) -} +//============= +// helm application template handler +//============= func (h *openpitrixHandler) DoAppAction(req *restful.Request, resp *restful.Response) { var doActionRequest openpitrix.ActionRequest @@ -245,7 +296,12 @@ func (h *openpitrixHandler) DoAppAction(req *restful.Request, resp *restful.Resp return } - appId := req.PathParameter("app") + user, _ := request.UserFrom(req.Request.Context()) + if user != nil { + doActionRequest.Username = user.GetName() + } + + appId := strings.TrimSuffix(req.PathParameter("app"), v1alpha1.HelmApplicationAppStoreSuffix) err = h.openpitrix.DoAppAction(appId, &doActionRequest) @@ -258,37 +314,62 @@ func (h *openpitrixHandler) DoAppAction(req *restful.Request, resp *restful.Resp resp.WriteEntity(errors.None) } -func (h *openpitrixHandler) DoAppVersionAction(req *restful.Request, resp *restful.Response) { - var doActionRequest openpitrix.ActionRequest - err := req.ReadEntity(&doActionRequest) +func (h *openpitrixHandler) CreateApp(req *restful.Request, resp *restful.Response) { + createAppRequest := &openpitrix.CreateAppRequest{} + err := req.ReadEntity(createAppRequest) if err != nil { klog.V(4).Infoln(err) api.HandleBadRequest(resp, nil, err) return } - doActionRequest.Username = req.HeaderParameter(constants.UserNameHeader) - versionId := req.PathParameter("version") + user, _ := request.UserFrom(req.Request.Context()) + if user != nil { + createAppRequest.Username = user.GetName() + } - err = h.openpitrix.DoAppVersionAction(versionId, &doActionRequest) + if req.PathParameter("workspace") != "" { + createAppRequest.Isv = req.PathParameter("workspace") + } + + validate, _ := strconv.ParseBool(req.QueryParameter("validate")) + + var result interface{} + + if validate { + validatePackageRequest := &openpitrix.ValidatePackageRequest{ + VersionPackage: createAppRequest.VersionPackage, + VersionType: createAppRequest.VersionType, + } + _ = validatePackageRequest + result, err = h.openpitrix.ValidatePackage(validatePackageRequest) + } else { + result, err = h.openpitrix.CreateApp(createAppRequest) + } if err != nil { - klog.Errorln(err) - handleOpenpitrixError(resp, err) + if status.Code(err) == codes.InvalidArgument { + api.HandleBadRequest(resp, nil, err) + return + } + api.HandleInternalError(resp, nil, err) return } - resp.WriteEntity(errors.None) + resp.WriteEntity(result) } +func (h *openpitrixHandler) ModifyApp(req *restful.Request, resp *restful.Response) { + var patchAppRequest openpitrix.ModifyAppRequest + err := req.ReadEntity(&patchAppRequest) + appId := req.PathParameter("app") -func (h *openpitrixHandler) GetAppVersionFiles(req *restful.Request, resp *restful.Response) { - versionId := req.PathParameter("version") - getAppVersionFilesRequest := &openpitrix.GetAppVersionFilesRequest{} - if f := req.QueryParameter("files"); f != "" { - getAppVersionFilesRequest.Files = strings.Split(f, ",") + if err != nil { + klog.V(4).Infoln(err) + api.HandleBadRequest(resp, nil, err) + return } - result, err := h.openpitrix.GetAppVersionFiles(versionId, getAppVersionFilesRequest) + err = h.openpitrix.ModifyApp(appId, &patchAppRequest) if err != nil { klog.Errorln(err) @@ -296,15 +377,13 @@ func (h *openpitrixHandler) GetAppVersionFiles(req *restful.Request, resp *restf return } - resp.WriteEntity(result) + resp.WriteEntity(errors.None) } -func (h *openpitrixHandler) ListAppVersionAudits(req *restful.Request, resp *restful.Response) { +func (h *openpitrixHandler) ListApps(req *restful.Request, resp *restful.Response) { limit, offset := params.ParsePaging(req) - orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.StatusTime) + orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime) reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false) - appId := req.PathParameter("app") - versionId := req.PathParameter("version") conditions, err := params.ParseConditions(req) if err != nil { @@ -313,12 +392,15 @@ func (h *openpitrixHandler) ListAppVersionAudits(req *restful.Request, resp *res return } - conditions.Match[openpitrix.AppId] = appId - if versionId != "" { - conditions.Match[openpitrix.VersionId] = versionId + if req.PathParameter("workspace") != "" { + conditions.Match[openpitrix.WorkspaceLabel] = req.PathParameter("workspace") } - result, err := h.openpitrix.ListAppVersionAudits(conditions, orderBy, reverse, limit, offset) + if conditions.Match[openpitrix.WorkspaceLabel] == "" { + conditions.Match[openpitrix.WorkspaceLabel] = req.QueryParameter("workspace") + } + + result, err := h.openpitrix.ListApps(conditions, orderBy, reverse, limit, offset) if err != nil { klog.Errorln(err) @@ -329,74 +411,110 @@ func (h *openpitrixHandler) ListAppVersionAudits(req *restful.Request, resp *res resp.WriteEntity(result) } -func (h *openpitrixHandler) ListReviews(req *restful.Request, resp *restful.Response) { - limit, offset := params.ParsePaging(req) - orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.StatusTime) - reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false) - conditions, err := params.ParseConditions(req) +func (h *openpitrixHandler) DescribeApp(req *restful.Request, resp *restful.Response) { + appId := req.PathParameter("app") + + result, err := h.openpitrix.DescribeApp(appId) if err != nil { - klog.V(4).Infoln(err) - api.HandleBadRequest(resp, nil, err) + klog.Errorln(err) + handleOpenpitrixError(resp, err) return } - result, err := h.openpitrix.ListAppVersionReviews(conditions, orderBy, reverse, limit, offset) + resp.WriteEntity(result) +} + +func (h *openpitrixHandler) DeleteApp(req *restful.Request, resp *restful.Response) { + appId := strings.TrimSuffix(req.PathParameter("app"), v1alpha1.HelmApplicationAppStoreSuffix) + + err := h.openpitrix.DeleteApp(appId) if err != nil { - klog.Errorln(err) + if status.Code(err) == codes.NotFound { + api.HandleNotFound(resp, nil, err) + return + } api.HandleInternalError(resp, nil, err) return } - resp.WriteEntity(result) + resp.WriteEntity(errors.None) } -func (h *openpitrixHandler) ListAppVersions(req *restful.Request, resp *restful.Response) { - limit, offset := params.ParsePaging(req) - orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime) - reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false) - appId := req.PathParameter("app") - statistics := params.GetBoolValueWithDefault(req, "statistics", false) - conditions, err := params.ParseConditions(req) - +// app version +func (h *openpitrixHandler) CreateAppVersion(req *restful.Request, resp *restful.Response) { + var createAppVersionRequest openpitrix.CreateAppVersionRequest + err := req.ReadEntity(&createAppVersionRequest) if err != nil { klog.V(4).Infoln(err) api.HandleBadRequest(resp, nil, err) return } - conditions.Match[openpitrix.AppId] = appId + // override app id + createAppVersionRequest.AppId = req.PathParameter("app") + user, _ := request.UserFrom(req.Request.Context()) + if user != nil { + createAppVersionRequest.Username = user.GetName() + } + validate, _ := strconv.ParseBool(req.QueryParameter("validate")) - result, err := h.openpitrix.ListAppVersions(conditions, orderBy, reverse, limit, offset) + var result interface{} + + if validate { + validatePackageRequest := &openpitrix.ValidatePackageRequest{ + VersionPackage: createAppVersionRequest.Package, + VersionType: createAppVersionRequest.Type, + } + result, err = h.openpitrix.ValidatePackage(validatePackageRequest) + } else { + result, err = h.openpitrix.CreateAppVersion(&createAppVersionRequest) + } if err != nil { klog.Errorln(err) - api.HandleInternalError(resp, nil, err) + handleOpenpitrixError(resp, err) return } - if statistics { - for _, item := range result.Items { - if version, ok := item.(*openpitrix.AppVersion); ok { - statisticsResult, err := h.openpitrix.ListApplications(¶ms.Conditions{Match: map[string]string{openpitrix.AppId: version.AppId, openpitrix.VersionId: version.VersionId}}, 0, 0, "", false) - if err != nil { - klog.Errorln(err) - api.HandleInternalError(resp, nil, err) - return - } - version.ClusterTotal = &statisticsResult.TotalCount - } - } + resp.WriteEntity(result) +} + +func (h *openpitrixHandler) DeleteAppVersion(req *restful.Request, resp *restful.Response) { + versionId := req.PathParameter("version") + + err := h.openpitrix.DeleteAppVersion(versionId) + + if err != nil { + klog.Errorln(err) + handleOpenpitrixError(resp, err) + return + } + + resp.WriteEntity(errors.None) +} + +func (h *openpitrixHandler) DescribeAppVersion(req *restful.Request, resp *restful.Response) { + versionId := req.PathParameter("version") + + result, err := h.openpitrix.DescribeAppVersion(versionId) + + if err != nil { + klog.Errorln(err) + handleOpenpitrixError(resp, err) + return } resp.WriteEntity(result) } -func (h *openpitrixHandler) ListApps(req *restful.Request, resp *restful.Response) { +func (h *openpitrixHandler) ListAppVersions(req *restful.Request, resp *restful.Response) { limit, offset := params.ParsePaging(req) orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime) reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false) - statistics := params.GetBoolValueWithDefault(req, "statistics", false) + appId := req.PathParameter("app") + appId = strings.TrimSuffix(appId, v1alpha1.HelmApplicationAppStoreSuffix) + conditions, err := params.ParseConditions(req) if err != nil { @@ -404,46 +522,32 @@ func (h *openpitrixHandler) ListApps(req *restful.Request, resp *restful.Respons api.HandleBadRequest(resp, nil, err) return } + conditions.Match[openpitrix.AppId] = appId if req.PathParameter("workspace") != "" { - conditions.Match[openpitrix.ISV] = req.PathParameter("workspace") + conditions.Match[openpitrix.WorkspaceLabel] = req.PathParameter("workspace") } - if conditions.Match[openpitrix.ISV] == "" { - conditions.Match[openpitrix.ISV] = req.QueryParameter("workspace") + if conditions.Match[openpitrix.WorkspaceLabel] == "" { + conditions.Match[openpitrix.WorkspaceLabel] = req.QueryParameter("workspace") } - result, err := h.openpitrix.ListApps(conditions, orderBy, reverse, limit, offset) + result, err := h.openpitrix.ListAppVersions(conditions, orderBy, reverse, limit, offset) if err != nil { klog.Errorln(err) - handleOpenpitrixError(resp, err) + api.HandleInternalError(resp, nil, err) return } - if statistics { - for _, item := range result.Items { - if app, ok := item.(*openpitrix.App); ok { - statuses := "active|used|enabled|stopped|pending|creating|upgrading|updating|rollbacking|stopping|starting|recovering|resizing|scaling|deleting" - statisticsResult, err := h.openpitrix.ListApplications(¶ms.Conditions{Match: map[string]string{openpitrix.AppId: app.AppId, openpitrix.Status: statuses}}, 0, 0, "", false) - if err != nil { - klog.Errorln(err) - handleOpenpitrixError(resp, err) - return - } - app.ClusterTotal = &statisticsResult.TotalCount - } - } - } - resp.WriteEntity(result) } -func (h *openpitrixHandler) ModifyApp(req *restful.Request, resp *restful.Response) { +func (h *openpitrixHandler) ModifyAppVersion(req *restful.Request, resp *restful.Response) { - var patchAppRequest openpitrix.ModifyAppRequest - err := req.ReadEntity(&patchAppRequest) - appId := req.PathParameter("app") + var patchAppVersionRequest openpitrix.ModifyAppVersionRequest + err := req.ReadEntity(&patchAppVersionRequest) + versionId := req.PathParameter("version") if err != nil { klog.V(4).Infoln(err) @@ -451,7 +555,7 @@ func (h *openpitrixHandler) ModifyApp(req *restful.Request, resp *restful.Respon return } - err = h.openpitrix.ModifyApp(appId, &patchAppRequest) + err = h.openpitrix.ModifyAppVersion(versionId, &patchAppVersionRequest) if err != nil { klog.Errorln(err) @@ -462,104 +566,61 @@ func (h *openpitrixHandler) ModifyApp(req *restful.Request, resp *restful.Respon resp.WriteEntity(errors.None) } -func (h *openpitrixHandler) DescribeApp(req *restful.Request, resp *restful.Response) { +func (h *openpitrixHandler) GetAppVersionPackage(req *restful.Request, resp *restful.Response) { appId := req.PathParameter("app") + versionId := req.PathParameter("version") - result, err := h.openpitrix.DescribeApp(appId) + result, err := h.openpitrix.GetAppVersionPackage(appId, versionId) if err != nil { klog.Errorln(err) - handleOpenpitrixError(resp, err) - return - } - - resp.WriteEntity(result) -} - -func (h *openpitrixHandler) DeleteApp(req *restful.Request, resp *restful.Response) { - appId := req.PathParameter("app") - - err := h.openpitrix.DeleteApp(appId) - - if err != nil { - if status.Code(err) == codes.NotFound { - api.HandleNotFound(resp, nil, err) - return - } api.HandleInternalError(resp, nil, err) return } - resp.WriteEntity(errors.None) + resp.WriteEntity(result) } -func (h *openpitrixHandler) CreateApp(req *restful.Request, resp *restful.Response) { - createAppRequest := &openpitrix.CreateAppRequest{} - err := req.ReadEntity(createAppRequest) - if err != nil { - klog.V(4).Infoln(err) - api.HandleBadRequest(resp, nil, err) - return - } - - createAppRequest.Username = req.HeaderParameter(constants.UserNameHeader) - - if req.PathParameter("workspace") != "" { - createAppRequest.Isv = req.PathParameter("workspace") +func (h *openpitrixHandler) GetAppVersionFiles(req *restful.Request, resp *restful.Response) { + versionId := req.PathParameter("version") + getAppVersionFilesRequest := &openpitrix.GetAppVersionFilesRequest{} + if f := req.QueryParameter("files"); f != "" { + getAppVersionFilesRequest.Files = strings.Split(f, ",") } - validate, _ := strconv.ParseBool(req.QueryParameter("validate")) - - var result interface{} - - if validate { - validatePackageRequest := &openpitrix.ValidatePackageRequest{ - VersionPackage: createAppRequest.VersionPackage, - VersionType: createAppRequest.VersionType, - } - result, err = h.openpitrix.ValidatePackage(validatePackageRequest) - } else { - result, err = h.openpitrix.CreateApp(createAppRequest) - } + result, err := h.openpitrix.GetAppVersionFiles(versionId, getAppVersionFilesRequest) if err != nil { - if status.Code(err) == codes.InvalidArgument { - api.HandleBadRequest(resp, nil, err) - return - } - api.HandleInternalError(resp, nil, err) + klog.Errorln(err) + handleOpenpitrixError(resp, err) return } resp.WriteEntity(result) } -func (h *openpitrixHandler) CreateAppVersion(req *restful.Request, resp *restful.Response) { - var createAppVersionRequest openpitrix.CreateAppVersionRequest - err := req.ReadEntity(&createAppVersionRequest) +// app version audit +func (h *openpitrixHandler) ListAppVersionAudits(req *restful.Request, resp *restful.Response) { + limit, offset := params.ParsePaging(req) + orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.StatusTime) + reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false) + appId := req.PathParameter("app") + versionId := req.PathParameter("version") + conditions, err := params.ParseConditions(req) + if err != nil { klog.V(4).Infoln(err) api.HandleBadRequest(resp, nil, err) return } - // override app id - createAppVersionRequest.AppId = req.PathParameter("app") - createAppVersionRequest.Username = req.HeaderParameter(constants.UserNameHeader) - validate, _ := strconv.ParseBool(req.QueryParameter("validate")) - - var result interface{} - - if validate { - validatePackageRequest := &openpitrix.ValidatePackageRequest{ - VersionPackage: createAppVersionRequest.Package, - VersionType: createAppVersionRequest.Type, - } - result, err = h.openpitrix.ValidatePackage(validatePackageRequest) - } else { - result, err = h.openpitrix.CreateAppVersion(&createAppVersionRequest) + conditions.Match[openpitrix.AppId] = strings.TrimSuffix(appId, v1alpha1.HelmApplicationAppStoreSuffix) + if versionId != "" { + conditions.Match[openpitrix.VersionId] = versionId } + result, err := h.openpitrix.ListAppVersionAudits(conditions, orderBy, reverse, limit, offset) + if err != nil { klog.Errorln(err) handleOpenpitrixError(resp, err) @@ -569,19 +630,23 @@ func (h *openpitrixHandler) CreateAppVersion(req *restful.Request, resp *restful resp.WriteEntity(result) } -func (h *openpitrixHandler) ModifyAppVersion(req *restful.Request, resp *restful.Response) { - - var patchAppVersionRequest openpitrix.ModifyAppVersionRequest - err := req.ReadEntity(&patchAppVersionRequest) - versionId := req.PathParameter("version") - +func (h *openpitrixHandler) DoAppVersionAction(req *restful.Request, resp *restful.Response) { + var doActionRequest openpitrix.ActionRequest + err := req.ReadEntity(&doActionRequest) if err != nil { klog.V(4).Infoln(err) api.HandleBadRequest(resp, nil, err) return } + doActionRequest.Username = req.HeaderParameter(constants.UserNameHeader) - err = h.openpitrix.ModifyAppVersion(versionId, &patchAppVersionRequest) + user, _ := request.UserFrom(req.Request.Context()) + if user != nil { + doActionRequest.Username = user.GetName() + } + versionId := req.PathParameter("version") + + err = h.openpitrix.DoAppVersionAction(versionId, &doActionRequest) if err != nil { klog.Errorln(err) @@ -592,10 +657,15 @@ func (h *openpitrixHandler) ModifyAppVersion(req *restful.Request, resp *restful resp.WriteEntity(errors.None) } -func (h *openpitrixHandler) DeleteAppVersion(req *restful.Request, resp *restful.Response) { - versionId := req.PathParameter("version") +// application release - err := h.openpitrix.DeleteAppVersion(versionId) +func (h *openpitrixHandler) DescribeApplication(req *restful.Request, resp *restful.Response) { + clusterName := req.PathParameter("cluster") + workspace := req.PathParameter("workspace") + applicationId := req.PathParameter("application") + namespace := req.PathParameter("namespace") + + app, err := h.openpitrix.DescribeApplication(workspace, clusterName, namespace, applicationId) if err != nil { klog.Errorln(err) @@ -603,13 +673,17 @@ func (h *openpitrixHandler) DeleteAppVersion(req *restful.Request, resp *restful return } - resp.WriteEntity(errors.None) + resp.WriteEntity(app) + return } -func (h *openpitrixHandler) DescribeAppVersion(req *restful.Request, resp *restful.Response) { - versionId := req.PathParameter("version") +func (h *openpitrixHandler) DeleteApplication(req *restful.Request, resp *restful.Response) { + clusterName := req.PathParameter("cluster") + workspace := req.PathParameter("workspace") + applicationId := req.PathParameter("application") + namespace := req.PathParameter("namespace") - result, err := h.openpitrix.DescribeAppVersion(versionId) + err := h.openpitrix.DeleteApplication(workspace, clusterName, namespace, applicationId) if err != nil { klog.Errorln(err) @@ -617,110 +691,86 @@ func (h *openpitrixHandler) DescribeAppVersion(req *restful.Request, resp *restf return } - resp.WriteEntity(result) + resp.WriteEntity(errors.None) } -func (h *openpitrixHandler) DescribeAttachment(req *restful.Request, resp *restful.Response) { - attachmentId := req.PathParameter("attachment") - fileName := req.QueryParameter("filename") - result, err := h.openpitrix.DescribeAttachment(attachmentId) +func (h *openpitrixHandler) ListApplications(req *restful.Request, resp *restful.Response) { + limit, offset := params.ParsePaging(req) + clusterName := req.PathParameter("cluster") + namespace := req.PathParameter("namespace") + workspace := req.PathParameter("workspace") + orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime) + reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false) + conditions, err := params.ParseConditions(req) - if err != nil { - klog.Errorln(err) - handleOpenpitrixError(resp, err) - return + if offset < 0 { + offset = 0 } - // file raw - if fileName != "" { - data := result.AttachmentContent[fileName] - resp.Write(data) - resp.Header().Set("Content-Type", "text/plain") - return + if limit <= 0 { + limit = 10 } - resp.WriteEntity(result) -} - -func (h *openpitrixHandler) CreateCategory(req *restful.Request, resp *restful.Response) { - createCategoryRequest := &openpitrix.CreateCategoryRequest{} - err := req.ReadEntity(createCategoryRequest) if err != nil { klog.V(4).Infoln(err) api.HandleBadRequest(resp, nil, err) return } - result, err := h.openpitrix.CreateCategory(createCategoryRequest) + result, err := h.openpitrix.ListApplications(workspace, clusterName, namespace, conditions, limit, offset, orderBy, reverse) if err != nil { klog.Errorln(err) - handleOpenpitrixError(resp, err) + api.HandleInternalError(resp, nil, err) return } - resp.WriteEntity(result) + resp.WriteAsJson(result) } -func (h *openpitrixHandler) DeleteCategory(req *restful.Request, resp *restful.Response) { - categoryId := req.PathParameter("category") - - err := h.openpitrix.DeleteCategory(categoryId) - - if err != nil { - klog.Errorln(err) - handleOpenpitrixError(resp, err) - return - } - resp.WriteEntity(errors.None) -} -func (h *openpitrixHandler) ModifyCategory(req *restful.Request, resp *restful.Response) { - var modifyCategoryRequest openpitrix.ModifyCategoryRequest - categoryId := req.PathParameter("category") - err := req.ReadEntity(&modifyCategoryRequest) +func (h *openpitrixHandler) UpgradeApplication(req *restful.Request, resp *restful.Response) { + namespace := req.PathParameter("namespace") + applicationId := req.PathParameter("application") + var upgradeClusterRequest openpitrix.UpgradeClusterRequest + err := req.ReadEntity(&upgradeClusterRequest) if err != nil { klog.V(4).Infoln(err) api.HandleBadRequest(resp, nil, err) return } - err = h.openpitrix.ModifyCategory(categoryId, &modifyCategoryRequest) - - if err != nil { - klog.Errorln(err) - handleOpenpitrixError(resp, err) - return + upgradeClusterRequest.Namespace = namespace + upgradeClusterRequest.ClusterId = applicationId + user, _ := request.UserFrom(req.Request.Context()) + if user != nil { + upgradeClusterRequest.Username = user.GetName() } - resp.WriteEntity(errors.None) -} -func (h *openpitrixHandler) DescribeCategory(req *restful.Request, resp *restful.Response) { - categoryId := req.PathParameter("category") - - result, err := h.openpitrix.DescribeCategory(categoryId) - + err = h.openpitrix.UpgradeApplication(upgradeClusterRequest) if err != nil { klog.Errorln(err) - handleOpenpitrixError(resp, err) + api.HandleInternalError(resp, nil, err) return } - resp.WriteEntity(result) + resp.WriteEntity(errors.None) } -func (h *openpitrixHandler) ListCategories(req *restful.Request, resp *restful.Response) { - limit, offset := params.ParsePaging(req) - orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime) - reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false) - statistics := params.GetBoolValueWithDefault(req, "statistics", false) - conditions, err := params.ParseConditions(req) +func (h *openpitrixHandler) ModifyApplication(req *restful.Request, resp *restful.Response) { + var modifyClusterAttributesRequest openpitrix.ModifyClusterAttributesRequest + applicationId := req.PathParameter("application") + namespace := req.PathParameter("namespace") + err := req.ReadEntity(&modifyClusterAttributesRequest) if err != nil { klog.V(4).Infoln(err) api.HandleBadRequest(resp, nil, err) return } - result, err := h.openpitrix.ListCategories(conditions, orderBy, reverse, limit, offset) + modifyClusterAttributesRequest.Namespace = namespace + modifyClusterAttributesRequest.ClusterID = applicationId + + err = h.openpitrix.ModifyApplication(modifyClusterAttributesRequest) if err != nil { klog.Errorln(err) @@ -728,80 +778,47 @@ func (h *openpitrixHandler) ListCategories(req *restful.Request, resp *restful.R return } - if statistics { - for _, item := range result.Items { - if category, ok := item.(*openpitrix.Category); ok { - statisticsResult, err := h.openpitrix.ListApps(¶ms.Conditions{ - Match: map[string]string{ - openpitrix.CategoryId: category.CategoryID, - openpitrix.Status: openpitrix.StatusActive, - openpitrix.RepoId: openpitrix.BuiltinRepoId, - }, - }, "", false, 0, 0) - if err != nil { - klog.Errorln(err) - handleOpenpitrixError(resp, err) - return - } - category.AppTotal = &statisticsResult.TotalCount - } - } - } - - resp.WriteEntity(result) + resp.WriteEntity(errors.None) } -func (h *openpitrixHandler) CreateRepo(req *restful.Request, resp *restful.Response) { - createRepoRequest := &openpitrix.CreateRepoRequest{} - err := req.ReadEntity(createRepoRequest) +func (h *openpitrixHandler) CreateApplication(req *restful.Request, resp *restful.Response) { + clusterName := req.PathParameter("cluster") + namespace := req.PathParameter("namespace") + workspace := req.PathParameter("workspace") + var createClusterRequest openpitrix.CreateClusterRequest + err := req.ReadEntity(&createClusterRequest) + createClusterRequest.Workspace = workspace if err != nil { klog.V(4).Infoln(err) api.HandleBadRequest(resp, nil, err) return } - - if req.PathParameter("workspace") != "" { - if createRepoRequest.Workspace == nil { - createRepoRequest.Workspace = new(string) - } - *createRepoRequest.Workspace = req.PathParameter("workspace") + user, _ := request.UserFrom(req.Request.Context()) + if user != nil { + createClusterRequest.Username = user.GetName() } - validate, _ := strconv.ParseBool(req.QueryParameter("validate")) - - var result interface{} - - if validate { - validateRepoRequest := &openpitrix.ValidateRepoRequest{ - Type: createRepoRequest.Type, - Url: createRepoRequest.URL, - Credential: createRepoRequest.Credential, - } - result, err = h.openpitrix.ValidateRepo(validateRepoRequest) - } else { - result, err = h.openpitrix.CreateRepo(createRepoRequest) - } + err = h.openpitrix.CreateApplication(workspace, clusterName, namespace, createClusterRequest) if err != nil { klog.Errorln(err) - handleOpenpitrixError(resp, err) + api.HandleInternalError(resp, nil, err) return } - resp.WriteEntity(result) + resp.WriteEntity(errors.None) } -func (h *openpitrixHandler) DoRepoAction(req *restful.Request, resp *restful.Response) { - repoActionRequest := &openpitrix.RepoActionRequest{} - repoId := req.PathParameter("repo") - err := req.ReadEntity(repoActionRequest) +func (h *openpitrixHandler) CreateCategory(req *restful.Request, resp *restful.Response) { + createCategoryRequest := &openpitrix.CreateCategoryRequest{} + err := req.ReadEntity(createCategoryRequest) if err != nil { klog.V(4).Infoln(err) api.HandleBadRequest(resp, nil, err) return } - err = h.openpitrix.DoRepoAction(repoId, repoActionRequest) + result, err := h.openpitrix.CreateCategory(createCategoryRequest) if err != nil { klog.Errorln(err) @@ -809,13 +826,12 @@ func (h *openpitrixHandler) DoRepoAction(req *restful.Request, resp *restful.Res return } - resp.WriteEntity(errors.None) + resp.WriteEntity(result) } +func (h *openpitrixHandler) DeleteCategory(req *restful.Request, resp *restful.Response) { + categoryId := req.PathParameter("category") -func (h *openpitrixHandler) DeleteRepo(req *restful.Request, resp *restful.Response) { - repoId := req.PathParameter("repo") - - err := h.openpitrix.DeleteRepo(repoId) + err := h.openpitrix.DeleteCategory(categoryId) if err != nil { klog.Errorln(err) @@ -825,18 +841,17 @@ func (h *openpitrixHandler) DeleteRepo(req *restful.Request, resp *restful.Respo resp.WriteEntity(errors.None) } - -func (h *openpitrixHandler) ModifyRepo(req *restful.Request, resp *restful.Response) { - var updateRepoRequest openpitrix.ModifyRepoRequest - repoId := req.PathParameter("repo") - err := req.ReadEntity(&updateRepoRequest) +func (h *openpitrixHandler) ModifyCategory(req *restful.Request, resp *restful.Response) { + var modifyCategoryRequest openpitrix.ModifyCategoryRequest + categoryId := req.PathParameter("category") + err := req.ReadEntity(&modifyCategoryRequest) if err != nil { klog.V(4).Infoln(err) api.HandleBadRequest(resp, nil, err) return } - err = h.openpitrix.ModifyRepo(repoId, &updateRepoRequest) + err = h.openpitrix.ModifyCategory(categoryId, &modifyCategoryRequest) if err != nil { klog.Errorln(err) @@ -846,11 +861,10 @@ func (h *openpitrixHandler) ModifyRepo(req *restful.Request, resp *restful.Respo resp.WriteEntity(errors.None) } +func (h *openpitrixHandler) DescribeCategory(req *restful.Request, resp *restful.Response) { + categoryId := req.PathParameter("category") -func (h *openpitrixHandler) DescribeRepo(req *restful.Request, resp *restful.Response) { - repoId := req.PathParameter("repo") - - result, err := h.openpitrix.DescribeRepo(repoId) + result, err := h.openpitrix.DescribeCategory(categoryId) if err != nil { klog.Errorln(err) @@ -860,8 +874,7 @@ func (h *openpitrixHandler) DescribeRepo(req *restful.Request, resp *restful.Res resp.WriteEntity(result) } - -func (h *openpitrixHandler) ListRepos(req *restful.Request, resp *restful.Response) { +func (h *openpitrixHandler) ListCategories(req *restful.Request, resp *restful.Response) { limit, offset := params.ParsePaging(req) orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.CreateTime) reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false) @@ -873,17 +886,7 @@ func (h *openpitrixHandler) ListRepos(req *restful.Request, resp *restful.Respon return } - if req.PathParameter("workspace") != "" { - conditions.Match[openpitrix.WorkspaceLabel] = req.PathParameter("workspace") - } - - if err != nil { - klog.V(4).Infoln(err) - api.HandleBadRequest(resp, nil, err) - return - } - - result, err := h.openpitrix.ListRepos(conditions, orderBy, reverse, limit, offset) + result, err := h.openpitrix.ListCategories(conditions, orderBy, reverse, limit, offset) if err != nil { klog.Errorln(err) @@ -894,9 +897,11 @@ func (h *openpitrixHandler) ListRepos(req *restful.Request, resp *restful.Respon resp.WriteEntity(result) } -func (h *openpitrixHandler) ListRepoEvents(req *restful.Request, resp *restful.Response) { - repoId := req.PathParameter("repo") +// review +func (h *openpitrixHandler) ListReviews(req *restful.Request, resp *restful.Response) { limit, offset := params.ParsePaging(req) + orderBy := params.GetStringValueWithDefault(req, params.OrderByParam, openpitrix.StatusTime) + reverse := params.GetBoolValueWithDefault(req, params.ReverseParam, false) conditions, err := params.ParseConditions(req) if err != nil { @@ -905,28 +910,76 @@ func (h *openpitrixHandler) ListRepoEvents(req *restful.Request, resp *restful.R return } - result, err := h.openpitrix.ListRepoEvents(repoId, conditions, limit, offset) + result, err := h.openpitrix.ListAppVersionReviews(conditions, orderBy, reverse, limit, offset) if err != nil { klog.Errorln(err) - handleOpenpitrixError(resp, err) + api.HandleInternalError(resp, nil, err) return } resp.WriteEntity(result) } -func handleOpenpitrixError(resp *restful.Response, err error) { - if status.Code(err) == codes.NotFound { - klog.V(4).Infoln(err) - api.HandleNotFound(resp, nil, err) +func (h *openpitrixHandler) DescribeAttachment(req *restful.Request, resp *restful.Response) { + attachmentId := req.PathParameter("attachment") + fileName := req.QueryParameter("filename") + result, err := h.openpitrix.DescribeAttachment(attachmentId) + + if err != nil { + klog.Errorln(err) + handleOpenpitrixError(resp, err) return } - if status.Code(err) == codes.InvalidArgument || status.Code(err) == codes.FailedPrecondition { - klog.V(4).Infoln(err) + + // file raw + if fileName != "" { + data := result.AttachmentContent[fileName] + resp.Write(data) + resp.Header().Set("Content-Type", "text/plain") + return + } + + resp.WriteEntity(result) +} + +func (h *openpitrixHandler) CreateAttachment(req *restful.Request, resp *restful.Response) { + + r := req.Request + err := r.ParseMultipartForm(10 << 20) + if err != nil { api.HandleBadRequest(resp, nil, err) return } - klog.Errorln(err) - api.HandleInternalError(resp, nil, err) + + var att *openpitrix.Attachment + // just save one attachment + for fName := range r.MultipartForm.File { + f, _, err := r.FormFile(fName) + if err != nil { + api.HandleBadRequest(resp, nil, err) + return + } + data, err := ioutil.ReadAll(f) + f.Close() + + att, err = h.openpitrix.CreateAttachment(data) + if err != nil { + api.HandleInternalError(resp, nil, err) + return + } + break + } + + resp.WriteEntity(att) +} + +func (h *openpitrixHandler) DeleteAttachments(req *restful.Request, resp *restful.Response) { + attachmentId := req.PathParameter("attachment") + + ids := strings.Split(attachmentId, ",") + err := h.openpitrix.DeleteAttachments(ids) + if err != nil { + api.HandleInternalError(resp, nil, err) + } } diff --git a/pkg/kapis/openpitrix/v1/register.go b/pkg/kapis/openpitrix/v1/register.go index 55dc2b7240373a42d6419b9730039ae9f991ce73..2c15a39db802394eb1a2599a4bb2f3f210cd24da 100644 --- a/pkg/kapis/openpitrix/v1/register.go +++ b/pkg/kapis/openpitrix/v1/register.go @@ -19,13 +19,14 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "kubesphere.io/kubesphere/pkg/api" "kubesphere.io/kubesphere/pkg/apiserver/runtime" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned" "kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/models" - openpitrix2 "kubesphere.io/kubesphere/pkg/models/openpitrix" + "kubesphere.io/kubesphere/pkg/models/openpitrix" "kubesphere.io/kubesphere/pkg/server/errors" "kubesphere.io/kubesphere/pkg/server/params" - op "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" + openpitrixoptions "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" "net/http" ) @@ -35,184 +36,280 @@ const ( var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} -func AddToContainer(c *restful.Container, factory informers.InformerFactory, op op.Client) error { - mimePatch := []string{restful.MIME_JSON, runtime.MimeMergePatchJson, runtime.MimeJsonPatchJson} +func AddToContainer(c *restful.Container, ksInfomrers informers.InformerFactory, ksClient versioned.Interface, options *openpitrixoptions.Options) error { + mimePatch := []string{restful.MIME_JSON, runtime.MimeJsonPatchJson, runtime.MimeMergePatchJson} webservice := runtime.NewWebService(GroupVersion) - handler := newOpenpitrixHandler(factory, op) - webservice.Route(webservice.GET("/applications"). - To(handler.ListApplications). - Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppInstanceTag}). - Doc("List all applications"). - Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). + handler := newOpenpitrixHandler(ksInfomrers, ksClient, options) + + webservice.Route(webservice.POST("/repos"). + To(handler.CreateRepo). + Doc("Create a global repository, which is used to store package of app"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Param(webservice.QueryParameter("validate", "Validate repository")). + Returns(http.StatusOK, api.StatusOK, openpitrix.CreateRepoResponse{}). + Reads(openpitrix.CreateRepoRequest{})) + webservice.Route(webservice.POST("/workspaces/{workspace}/repos"). + To(handler.CreateRepo). + Doc("Create repository in the specified workspace, which is used to store package of app"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Param(webservice.QueryParameter("validate", "Validate repository")). + Returns(http.StatusOK, api.StatusOK, openpitrix.CreateRepoResponse{}). + Reads(openpitrix.CreateRepoRequest{})) + webservice.Route(webservice.DELETE("/repos/{repo}"). + To(handler.DeleteRepo). + Doc("Delete the specified global repository"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("repo", "repo id"))) + webservice.Route(webservice.DELETE("/workspaces/{workspace}/repos/{repo}"). + To(handler.DeleteRepo). + Doc("Delete the specified repository in the specified workspace"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("repo", "repo id"))) + webservice.Route(webservice.GET("/repos"). + To(handler.ListRepos). + Doc("List global repositories"). + Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). Required(false). - DataFormat("key=value,key~value"). - DefaultValue("")). + DataFormat("key=%s,key~%s")). Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1"). Required(false). DataFormat("limit=%d,page=%d"). - DefaultValue("limit=10,page=1"))) - - webservice.Route(webservice.GET("/workspaces/{workspace}/namespaces/{namespace}/applications"). - To(handler.ListApplications). - Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppInstanceTag}). - Doc("List all applications within the specified namespace"). - Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). + DefaultValue("limit=10,page=1")). + Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). + Returns(http.StatusOK, api.StatusOK, models.PageableResponse{})) + webservice.Route(webservice.GET("/workspaces/{workspace}/repos"). + To(handler.ListRepos). + Doc("List repositories in the specified workspace"). + Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). Required(false). - DataFormat("key=value,key~value"). - DefaultValue("")). - Param(webservice.PathParameter("namespace", "the name of the project.").Required(true)). + DataFormat("key=%s,key~%s")). Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1"). Required(false). DataFormat("limit=%d,page=%d"). - DefaultValue("limit=10,page=1"))) + DefaultValue("limit=10,page=1")). + Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). + Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, models.PageableResponse{})) - webservice.Route(webservice.GET("/workspaces/{workspace}/namespaces/{namespace}/applications/{application}"). - To(handler.DescribeApplication). - Returns(http.StatusOK, api.StatusOK, openpitrix2.Application{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppInstanceTag}). - Doc("Describe the specified application of the namespace"). - Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). - Param(webservice.PathParameter("application", "the id of the application").Required(true))) + webservice.Route(webservice.GET("/repos/{repo}"). + To(handler.DescribeRepo). + Doc("Describe the specified global repository"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, openpitrix.Repo{}). + Param(webservice.PathParameter("repo", "repo id"))) + webservice.Route(webservice.GET("/workspaces/{workspace}/repos/{repo}"). + To(handler.DescribeRepo). + Doc("Describe the specified repository in the specified workspace"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, openpitrix.Repo{}). + Param(webservice.PathParameter("repo", "repo id"))) - webservice.Route(webservice.GET("/workspaces/{workspace}/clusters/{cluster}/applications"). - To(handler.ListApplications). + webservice.Route(webservice.PATCH("/workspaces/{workspace}/repos/{repo}"). + Consumes(mimePatch...). + To(handler.ModifyRepo). + Doc("Patch the specified repository in the specified workspace"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Reads(openpitrix.ModifyRepoRequest{}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("repo", "repo id"))) + + webservice.Route(webservice.PATCH("/repos/{repo}"). + Consumes(mimePatch...). + To(handler.ModifyRepo). + Doc("Patch the specified global repository"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Reads(openpitrix.ModifyRepoRequest{}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("repo", "repo id"))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/repos/{repo}/events"). + To(handler.ListRepoEvents). + Doc("Get repository events"). Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppInstanceTag}). - Doc("List all applications in special cluster"). - Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Param(webservice.PathParameter("repo", "repo id"))) + + webservice.Route(webservice.GET("/repos/{repo}/events"). + To(handler.ListRepoEvents). + Doc("Get global repository events"). + Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Param(webservice.PathParameter("repo", "repo id"))) + + webservice.Route(webservice.POST("/repos/{repo}/action"). + To(handler.DoRepoAction). + Deprecate(). + Doc("Start index repository event"). + Reads(openpitrix.RepoActionRequest{}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Param(webservice.PathParameter("repo", "repo id"))) + + webservice.Route(webservice.POST("/workspaces/{workspace}/repos/{repo}/action"). + To(handler.DoRepoAction). + Doc("Start index repository event"). + Reads(openpitrix.RepoActionRequest{}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("repo", "repo id"))) + + // app template + webservice.Route(webservice.POST("/apps/{app}/action"). + Deprecate(). + To(handler.DoAppAction). + Doc("Perform recover or suspend operation on app"). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("version", "app template version id")). + Param(webservice.PathParameter("app", "app template id"))) + webservice.Route(webservice.POST("/workspaces/{workspace}/apps/{app}/action"). + To(handler.DoAppAction). + Doc("Perform recover or suspend operation on app"). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("version", "app template version id")). + Param(webservice.PathParameter("app", "app template id"))) + webservice.Route(webservice.POST("/apps"). + Deprecate(). + To(handler.CreateApp). + Doc("Create a new app template"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, openpitrix.CreateAppResponse{}). + Reads(openpitrix.CreateAppRequest{}). + Param(webservice.PathParameter("app", "app template id"))) + webservice.Route(webservice.POST("/workspaces/{workspace}/apps"). + To(handler.CreateApp). + Doc("Create a new app template"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, openpitrix.CreateAppResponse{}). + Reads(openpitrix.CreateAppRequest{}). + Param(webservice.PathParameter("app", "app template id"))) + + webservice.Route(webservice.PATCH("/apps/{app}"). + Deprecate(). + Consumes(mimePatch...). + To(handler.ModifyApp). + Doc("Patch the specified app template"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Reads(openpitrix.ModifyAppVersionRequest{}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("app", "app template id"))) + webservice.Route(webservice.PATCH("/workspaces/{workspace}/apps/{app}"). + Consumes(mimePatch...). + To(handler.ModifyApp). + Doc("Patch the specified app template"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Reads(openpitrix.ModifyAppVersionRequest{}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("app", "app template id"))) + + webservice.Route(webservice.GET("/apps"). + Deprecate(). + To(handler.ListApps). + Doc("List app templates"). + Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). Required(false). - DataFormat("key=value,key~value"). - DefaultValue("")). - Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). + DataFormat("key=%s,key~%s")). Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1"). Required(false). DataFormat("limit=%d,page=%d"). - DefaultValue("limit=10,page=1"))) - - webservice.Route(webservice.GET("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications"). - To(handler.ListApplications). - Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppInstanceTag}). - Doc("List all applications within the specified namespace"). - Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). + DefaultValue("limit=10,page=1")). + Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). + Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, models.PageableResponse{})) + webservice.Route(webservice.GET("/workspaces/{workspace}/apps"). + To(handler.ListApps). + Doc("List app templates in the specified workspace."). + Param(webservice.PathParameter("workspace", "workspace name")). + Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). Required(false). - DataFormat("key=value,key~value"). - DefaultValue("")). - Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). - Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). + DataFormat("key=%s,key~%s")). Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1"). Required(false). DataFormat("limit=%d,page=%d"). - DefaultValue("limit=10,page=1"))) - - webservice.Route(webservice.GET("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications/{application}"). - To(handler.DescribeApplication). - Returns(http.StatusOK, api.StatusOK, openpitrix2.Application{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppInstanceTag}). - Doc("Describe the specified application of the namespace"). - Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). - Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). - Param(webservice.PathParameter("application", "the id of the application").Required(true))) + DefaultValue("limit=10,page=1")). + Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). + Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, models.PageableResponse{})) - webservice.Route(webservice.POST("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications"). - To(handler.CreateApplication). - Doc("Deploy a new application"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppInstanceTag}). - Reads(openpitrix2.CreateClusterRequest{}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). - Param(webservice.PathParameter("namespace", "the name of the project").Required(true))) + webservice.Route(webservice.GET("/workspaces/{workspace}/apps/{app}"). + To(handler.DescribeApp). + Doc("Describe the specified app template"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, openpitrix.AppVersion{}). + Param(webservice.PathParameter("app", "app template id"))) + webservice.Route(webservice.GET("/apps/{app}"). + Deprecate(). + To(handler.DescribeApp). + Doc("Describe the specified app template"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, openpitrix.AppVersion{}). + Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.PATCH("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications/{application}"). - Consumes(mimePatch...). - To(handler.ModifyApplication). - Doc("Modify application"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppInstanceTag}). - Reads(openpitrix2.ModifyClusterAttributesRequest{}). + webservice.Route(webservice.DELETE("/apps/{app}"). + Deprecate(). + To(handler.DeleteApp). + Doc("Delete the specified app template"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). - Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). - Param(webservice.PathParameter("application", "the id of the application").Required(true))) - - webservice.Route(webservice.DELETE("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications/{application}"). - To(handler.DeleteApplication). - Doc("Delete the specified application"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppInstanceTag}). + Param(webservice.PathParameter("app", "app template id"))) + webservice.Route(webservice.DELETE("/workspaces/{workspace}/apps/{app}"). + To(handler.DeleteApp). + Doc("Delete the specified app template"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). - Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). - Param(webservice.PathParameter("application", "the id of the application").Required(true))) + Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.POST("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications/{application}"). - Consumes(mimePatch...). - To(handler.UpgradeApplication). - Doc("Upgrade application"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppInstanceTag}). - Reads(openpitrix2.UpgradeClusterRequest{}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). - Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). - Param(webservice.PathParameter("application", "the id of the application").Required(true))) + // app versions webservice.Route(webservice.POST("/apps/{app}/versions"). + Deprecate(). To(handler.CreateAppVersion). Doc("Create a new app template version"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Reads(openpitrix2.CreateAppVersionRequest{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Reads(openpitrix.CreateAppVersionRequest{}). Param(webservice.QueryParameter("validate", "Validate format of package(pack by op tool)")). - Returns(http.StatusOK, api.StatusOK, openpitrix2.CreateAppVersionResponse{}). + Returns(http.StatusOK, api.StatusOK, openpitrix.CreateAppVersionResponse{}). Param(webservice.PathParameter("app", "app template id"))) webservice.Route(webservice.POST("/workspaces/{workspace}/apps/{app}/versions"). To(handler.CreateAppVersion). Doc("Create a new app template version"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Reads(openpitrix2.CreateAppVersionRequest{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Reads(openpitrix.CreateAppVersionRequest{}). Param(webservice.QueryParameter("validate", "Validate format of package(pack by op tool)")). - Returns(http.StatusOK, api.StatusOK, openpitrix2.CreateAppVersionResponse{}). + Returns(http.StatusOK, api.StatusOK, openpitrix.CreateAppVersionResponse{}). Param(webservice.PathParameter("app", "app template id"))) webservice.Route(webservice.DELETE("/apps/{app}/versions/{version}"). + Deprecate(). To(handler.DeleteAppVersion). Doc("Delete the specified app template version"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). Returns(http.StatusOK, api.StatusOK, errors.Error{}). Param(webservice.PathParameter("version", "app template version id")). Param(webservice.PathParameter("app", "app template id"))) webservice.Route(webservice.DELETE("/workspaces/{workspace}/apps/{app}/versions/{version}"). To(handler.DeleteAppVersion). Doc("Delete the specified app template version"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("version", "app template version id")). - Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.PATCH("/apps/{app}/versions/{version}"). - Consumes(mimePatch...). - To(handler.ModifyAppVersion). - Doc("Patch the specified app template version"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Reads(openpitrix2.ModifyAppVersionRequest{}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("version", "app template version id")). - Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.PATCH("/workspaces/{workspace}/apps/{app}/versions/{version}"). - Consumes(mimePatch...). - To(handler.ModifyAppVersion). - Doc("Patch the specified app template version"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Reads(openpitrix2.ModifyAppVersionRequest{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). Returns(http.StatusOK, api.StatusOK, errors.Error{}). Param(webservice.PathParameter("version", "app template version id")). Param(webservice.PathParameter("app", "app template id"))) + webservice.Route(webservice.GET("/apps/{app}/versions/{version}"). + Deprecate(). To(handler.DescribeAppVersion). Doc("Describe the specified app template version"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.AppVersion{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, openpitrix.AppVersion{}). Param(webservice.PathParameter("version", "app template version id")). Param(webservice.PathParameter("app", "app template id"))) webservice.Route(webservice.GET("/apps/{app}/versions"). + Deprecate(). To(handler.ListAppVersions). Doc("Get active versions of app, can filter with these fields(version_id, app_id, name, owner, description, package_name, status, type), default return all active app versions"). Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). @@ -225,13 +322,13 @@ func AddToContainer(c *restful.Container, factory informers.InformerFactory, op Param(webservice.PathParameter("app", "app template id")). Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). Returns(http.StatusOK, api.StatusOK, models.PageableResponse{})) webservice.Route(webservice.GET("/workspaces/{workspace}/apps/{app}/versions/{version}"). To(handler.DescribeAppVersion). Doc("Describe the specified app template version"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.AppVersion{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, openpitrix.AppVersion{}). Param(webservice.PathParameter("version", "app template version id")). Param(webservice.PathParameter("app", "app template id"))) webservice.Route(webservice.GET("/workspaces/{workspace}/apps/{app}/versions"). @@ -247,191 +344,293 @@ func AddToContainer(c *restful.Container, factory informers.InformerFactory, op Param(webservice.PathParameter("app", "app template id")). Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). Returns(http.StatusOK, api.StatusOK, models.PageableResponse{})) - webservice.Route(webservice.GET("/workspaces/{workspace}/apps/{app}/versions/{version}/audits"). - To(handler.ListAppVersionAudits). - Doc("List audits information of version-specific app template"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixManagementTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.AppVersionAudit{}). - Param(webservice.PathParameter("version", "app template version id")). - Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.GET("/apps/{app}/versions/{version}/audits"). - To(handler.ListAppVersionAudits). - Doc("List audits information of version-specific app template"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixManagementTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.AppVersionAudit{}). - Param(webservice.PathParameter("version", "app template version id")). - Param(webservice.PathParameter("app", "app template id"))) + webservice.Route(webservice.GET("/apps/{app}/versions/{version}/package"). To(handler.GetAppVersionPackage). Doc("Get packages of version-specific app"). - Returns(http.StatusOK, api.StatusOK, openpitrix2.GetAppVersionPackageResponse{}). + Returns(http.StatusOK, api.StatusOK, openpitrix.GetAppVersionPackageResponse{}). Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). Param(webservice.PathParameter("version", "app template version id")). Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.POST("/apps/{app}/versions/{version}/action"). - To(handler.DoAppVersionAction). - Doc("Perform submit or other operations on app"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixManagementTag}). + + webservice.Route(webservice.PATCH("/apps/{app}/versions/{version}"). + Deprecate(). + Consumes(mimePatch...). + To(handler.ModifyAppVersion). + Doc("Patch the specified app template version"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Reads(openpitrix.ModifyAppVersionRequest{}). Returns(http.StatusOK, api.StatusOK, errors.Error{}). Param(webservice.PathParameter("version", "app template version id")). Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.POST("/workspaces/{workspace}/apps/{app}/versions/{version}/action"). - To(handler.DoAppVersionAction). - Doc("Perform submit or other operations on app"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixManagementTag}). + webservice.Route(webservice.PATCH("/workspaces/{workspace}/apps/{app}/versions/{version}"). + Consumes(mimePatch...). + To(handler.ModifyAppVersion). + Doc("Patch the specified app template version"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Reads(openpitrix.ModifyAppVersionRequest{}). Returns(http.StatusOK, api.StatusOK, errors.Error{}). Param(webservice.PathParameter("version", "app template version id")). Param(webservice.PathParameter("app", "app template id"))) + webservice.Route(webservice.GET("/apps/{app}/versions/{version}/files"). + Deprecate(). To(handler.GetAppVersionFiles). Doc("Get app template package files"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.GetAppVersionPackageFilesResponse{}). + Returns(http.StatusOK, api.StatusOK, openpitrix.GetAppVersionPackageFilesResponse{}). Param(webservice.PathParameter("version", "app template version id")). Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.GET("/reviews"). - To(handler.ListReviews). - Doc("Get reviews of version-specific app"). - Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). - Required(false). - DataFormat("key=%s,key~%s")). - Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1"). - Required(false). - DataFormat("limit=%d,page=%d"). - DefaultValue("limit=10,page=1")). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixManagementTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.AppVersionReview{})) + + // app version audits + webservice.Route(webservice.GET("/apps/{app}/audits"). + Deprecate(). To(handler.ListAppVersionAudits). Doc("List audits information of the specific app template"). Param(webservice.PathParameter("app", "app template id")). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixManagementTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.AppVersionAudit{})) - webservice.Route(webservice.POST("/apps"). - To(handler.CreateApp). - Doc("Create a new app template"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.CreateAppResponse{}). - Reads(openpitrix2.CreateAppRequest{}). - Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.POST("/workspaces/{workspace}/apps"). - To(handler.CreateApp). - Doc("Create a new app template"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.CreateAppResponse{}). - Reads(openpitrix2.CreateAppRequest{}). - Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.DELETE("/apps/{app}"). - To(handler.DeleteApp). - Doc("Delete the specified app template"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.DELETE("/workspaces/{workspace}/apps/{app}"). - To(handler.DeleteApp). - Doc("Delete the specified app template"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.PATCH("/apps/{app}"). - Consumes(mimePatch...). - To(handler.ModifyApp). - Doc("Patch the specified app template"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Reads(openpitrix2.ModifyAppVersionRequest{}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.PATCH("/workspaces/{workspace}/apps/{app}"). - Consumes(mimePatch...). - To(handler.ModifyApp). - Doc("Patch the specified app template"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Reads(openpitrix2.ModifyAppVersionRequest{}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.GET("/workspaces/{workspace}/apps/{app}"). - To(handler.DescribeApp). - Doc("Describe the specified app template"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.AppVersion{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, openpitrix.AppVersionAudit{})) + webservice.Route(webservice.GET("/workspaces/{workspace}/apps/{app}/versions/{version}/audits"). + To(handler.ListAppVersionAudits). + Doc("List audits information of version-specific app template"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, openpitrix.AppVersionAudit{}). + Param(webservice.PathParameter("version", "app template version id")). Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.GET("/apps/{app}"). - To(handler.DescribeApp). - Doc("Describe the specified app template"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.AppVersion{}). + webservice.Route(webservice.GET("/apps/{app}/versions/{version}/audits"). + Deprecate(). + To(handler.ListAppVersionAudits). + Doc("List audits information of version-specific app template"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, openpitrix.AppVersionAudit{}). + Param(webservice.PathParameter("version", "app template version id")). Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.POST("/apps/{app}/action"). - To(handler.DoAppAction). - Doc("Perform recover or suspend operation on app"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixManagementTag}). + webservice.Route(webservice.POST("/apps/{app}/versions/{version}/action"). + Deprecate(). + To(handler.DoAppVersionAction). + Doc("Perform submit or other operations on app"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). Returns(http.StatusOK, api.StatusOK, errors.Error{}). Param(webservice.PathParameter("version", "app template version id")). Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.POST("/workspaces/{workspace}/apps/{app}/action"). - To(handler.DoAppAction). - Doc("Perform recover or suspend operation on app"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixManagementTag}). + webservice.Route(webservice.POST("/workspaces/{workspace}/apps/{app}/versions/{version}/action"). + To(handler.DoAppVersionAction). + Doc("Perform submit or other operations on app"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). Returns(http.StatusOK, api.StatusOK, errors.Error{}). Param(webservice.PathParameter("version", "app template version id")). Param(webservice.PathParameter("app", "app template id"))) - webservice.Route(webservice.GET("/apps"). - To(handler.ListApps). - Doc("List app templates"). - Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). + + // application release + + webservice.Route(webservice.GET("/applications"). + Deprecate(). + To(handler.ListApplications). + Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Doc("List all applications"). + Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). Required(false). - DataFormat("key=%s,key~%s")). + DataFormat("key=value,key~value"). + DefaultValue("")). Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1"). Required(false). DataFormat("limit=%d,page=%d"). - DefaultValue("limit=10,page=1")). - Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). - Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Returns(http.StatusOK, api.StatusOK, models.PageableResponse{})) - webservice.Route(webservice.GET("/workspaces/{workspace}/apps"). - To(handler.ListApps). - Doc("List app templates in the specified workspace."). - Param(webservice.PathParameter("workspace", "workspace name")). - Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). + DefaultValue("limit=10,page=1"))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/namespaces/{namespace}/applications"). + To(handler.ListApplications). + Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Doc("List all applications within the specified namespace"). + Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). Required(false). - DataFormat("key=%s,key~%s")). + DataFormat("key=value,key~value"). + DefaultValue("")). + Param(webservice.PathParameter("namespace", "the name of the project.").Required(true)). Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1"). Required(false). DataFormat("limit=%d,page=%d"). - DefaultValue("limit=10,page=1")). - Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). - Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAppTemplateTag}). - Returns(http.StatusOK, api.StatusOK, models.PageableResponse{})) + DefaultValue("limit=10,page=1"))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/clusters/{cluster}/applications"). + To(handler.ListApplications). + Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Doc("List all applications within the specified cluster"). + Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). + Required(false). + DataFormat("key=value,key~value"). + DefaultValue("")). + Param(webservice.PathParameter("namespace", "the name of the project.").Required(true)). + Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1"). + Required(false). + DataFormat("limit=%d,page=%d"). + DefaultValue("limit=10,page=1"))) + + webservice.Route(webservice.GET("/clusters/{cluster}/applications"). + To(handler.ListApplications). + Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Doc("List all applications within the specified cluster"). + Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). + Required(false). + DataFormat("key=value,key~value"). + DefaultValue("")). + Param(webservice.PathParameter("namespace", "the name of the project.").Required(true)). + Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1"). + Required(false). + DataFormat("limit=%d,page=%d"). + DefaultValue("limit=10,page=1"))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications"). + To(handler.ListApplications). + Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Doc("List all applications within the specified namespace"). + Param(webservice.QueryParameter(params.ConditionsParam, "query conditions, connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). + Required(false). + DataFormat("key=value,key~value"). + DefaultValue("")). + Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). + Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1"). + Required(false). + DataFormat("limit=%d,page=%d"). + DefaultValue("limit=10,page=1"))) + + webservice.Route(webservice.PATCH("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications/{application}"). + Consumes(mimePatch...). + To(handler.ModifyApplication). + Doc("Modify application"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Reads(openpitrix.ModifyClusterAttributesRequest{}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). + Param(webservice.PathParameter("application", "the id of the application").Required(true))) + + webservice.Route(webservice.PATCH("/workspaces/{workspace}/namespaces/{namespace}/applications/{application}"). + Consumes(mimePatch...). + To(handler.ModifyApplication). + Doc("Modify application"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Reads(openpitrix.ModifyClusterAttributesRequest{}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). + Param(webservice.PathParameter("application", "the id of the application").Required(true))) + + webservice.Route(webservice.POST("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications/{application}"). + Consumes(mimePatch...). + To(handler.UpgradeApplication). + Doc("Upgrade application"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Reads(openpitrix.UpgradeClusterRequest{}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). + Param(webservice.PathParameter("application", "the id of the application").Required(true))) + + webservice.Route(webservice.POST("/workspaces/{workspace}/namespaces/{namespace}/applications/{application}"). + Consumes(mimePatch...). + To(handler.UpgradeApplication). + Doc("Upgrade application"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Reads(openpitrix.UpgradeClusterRequest{}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). + Param(webservice.PathParameter("application", "the id of the application").Required(true))) + + webservice.Route(webservice.POST("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications"). + To(handler.CreateApplication). + Doc("Deploy a new application"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Reads(openpitrix.CreateClusterRequest{}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true))) + + webservice.Route(webservice.POST("/workspaces/{workspace}/namespaces/{namespace}/applications"). + To(handler.CreateApplication). + Doc("Deploy a new application"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Reads(openpitrix.CreateClusterRequest{}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications/{application}"). + To(handler.DescribeApplication). + Returns(http.StatusOK, api.StatusOK, openpitrix.Application{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Doc("Describe the specified application of the namespace"). + Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). + Param(webservice.PathParameter("application", "the id of the application").Required(true))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/namespaces/{namespace}/applications/{application}"). + To(handler.DescribeApplication). + Returns(http.StatusOK, api.StatusOK, openpitrix.Application{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Doc("Describe the specified application of the namespace"). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). + Param(webservice.PathParameter("application", "the id of the application").Required(true))) + + webservice.Route(webservice.DELETE("/workspaces/{workspace}/namespaces/{namespace}/applications/{application}"). + To(handler.DeleteApplication). + Doc("Delete the specified application"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). + Param(webservice.PathParameter("workspace", "the workspace of the project").Required(true)). + Param(webservice.PathParameter("application", "the id of the application").Required(true))) + + webservice.Route(webservice.DELETE("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications/{application}"). + To(handler.DeleteApplication). + Doc("Delete the specified application"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). + Param(webservice.PathParameter("application", "the id of the application").Required(true))) + + webservice.Route(webservice.DELETE("/workspaces/{workspace}/clusters/{cluster}/applications/{application}"). + To(handler.DeleteApplication). + Doc("Delete the specified application"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Returns(http.StatusOK, api.StatusOK, errors.Error{}). + Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). + Param(webservice.PathParameter("workspace", "the workspaces of the project").Required(true)). + Param(webservice.PathParameter("application", "the id of the application").Required(true))) + + // category webservice.Route(webservice.POST("/categories"). To(handler.CreateCategory). Doc("Create app template category"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixCategoryTag}). - Reads(openpitrix2.CreateCategoryRequest{}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.CreateCategoryResponse{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Reads(openpitrix.CreateCategoryRequest{}). + Returns(http.StatusOK, api.StatusOK, openpitrix.CreateCategoryResponse{}). Param(webservice.PathParameter("app", "app template id"))) webservice.Route(webservice.DELETE("/categories/{category}"). To(handler.DeleteCategory). Doc("Delete the specified category"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixCategoryTag}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). Returns(http.StatusOK, api.StatusOK, errors.Error{}). Param(webservice.PathParameter("category", "category id"))) webservice.Route(webservice.PATCH("/categories/{category}"). Consumes(mimePatch...). To(handler.ModifyCategory). Doc("Patch the specified category"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixCategoryTag}). - Reads(openpitrix2.ModifyCategoryRequest{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Reads(openpitrix.ModifyCategoryRequest{}). Returns(http.StatusOK, api.StatusOK, errors.Error{}). Param(webservice.PathParameter("category", "category id"))) webservice.Route(webservice.GET("/categories/{category}"). To(handler.DescribeCategory). Doc("Describe the specified category"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixCategoryTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.Category{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, openpitrix.Category{}). Param(webservice.PathParameter("category", "category id"))) webservice.Route(webservice.GET("/categories"). To(handler.ListCategories). @@ -445,87 +644,12 @@ func AddToContainer(c *restful.Container, factory informers.InformerFactory, op DefaultValue("limit=10,page=1")). Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixCategoryTag}). Returns(http.StatusOK, api.StatusOK, models.PageableResponse{})) - webservice.Route(webservice.GET("/attachments/{attachment}"). - To(handler.DescribeAttachment). - Doc("Get attachment by attachment id"). - Param(webservice.PathParameter("attachment", "attachment id")). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixAttachmentTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.Attachment{})) - - webservice.Route(webservice.POST("/repos"). - To(handler.CreateRepo). - Doc("Create repository in the specified workspace, repository used to store package of app"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixRepositoryTag}). - Param(webservice.QueryParameter("validate", "Validate repository")). - Returns(http.StatusOK, api.StatusOK, openpitrix2.CreateRepoResponse{}). - Reads(openpitrix2.CreateRepoRequest{})) - webservice.Route(webservice.POST("/workspaces/{workspace}/repos"). - To(handler.CreateRepo). - Doc("Create repository in the specified workspace, repository used to store package of app"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixRepositoryTag}). - Param(webservice.QueryParameter("validate", "Validate repository")). - Returns(http.StatusOK, api.StatusOK, openpitrix2.CreateRepoResponse{}). - Reads(openpitrix2.CreateRepoRequest{})) - webservice.Route(webservice.DELETE("/repos/{repo}"). - To(handler.DeleteRepo). - Doc("Delete the specified repository in the specified workspace"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixRepositoryTag}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("repo", "repo id"))) - webservice.Route(webservice.DELETE("/workspaces/{workspace}/repos/{repo}"). - To(handler.DeleteRepo). - Doc("Delete the specified repository in the specified workspace"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixRepositoryTag}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("repo", "repo id"))) - webservice.Route(webservice.PATCH("/repos/{repo}"). - Consumes(mimePatch...). - To(handler.ModifyRepo). - Doc("Patch the specified repository in the specified workspace"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixRepositoryTag}). - Reads(openpitrix2.ModifyRepoRequest{}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("repo", "repo id"))) - webservice.Route(webservice.PATCH("/workspaces/{workspace}/repos/{repo}"). - Consumes(mimePatch...). - To(handler.ModifyRepo). - Doc("Patch the specified repository in the specified workspace"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixRepositoryTag}). - Reads(openpitrix2.ModifyRepoRequest{}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Param(webservice.PathParameter("repo", "repo id"))) - webservice.Route(webservice.GET("/repos/{repo}"). - To(handler.DescribeRepo). - Doc("Describe the specified repository in the specified workspace"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixRepositoryTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.Repo{}). - Param(webservice.PathParameter("repo", "repo id"))) - webservice.Route(webservice.GET("/workspaces/{workspace}/repos/{repo}"). - To(handler.DescribeRepo). - Doc("Describe the specified repository in the specified workspace"). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixRepositoryTag}). - Returns(http.StatusOK, api.StatusOK, openpitrix2.Repo{}). - Param(webservice.PathParameter("repo", "repo id"))) - webservice.Route(webservice.GET("/repos"). - To(handler.ListRepos). - Doc("List repositories in the specified workspace"). - Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). - Required(false). - DataFormat("key=%s,key~%s")). - Param(webservice.QueryParameter(params.PagingParam, "paging query, e.g. limit=100,page=1"). - Required(false). - DataFormat("limit=%d,page=%d"). - DefaultValue("limit=10,page=1")). - Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixRepositoryTag}). - Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). - Returns(http.StatusOK, api.StatusOK, models.PageableResponse{})) - webservice.Route(webservice.GET("/workspaces/{workspace}/repos"). - To(handler.ListRepos). - Doc("List repositories in the specified workspace"). + // review + webservice.Route(webservice.GET("/reviews"). + To(handler.ListReviews). + Doc("Get reviews of version-specific app"). Param(webservice.QueryParameter(params.ConditionsParam, "query conditions,connect multiple conditions with commas, equal symbol for exact query, wave symbol for fuzzy query e.g. name~a"). Required(false). DataFormat("key=%s,key~%s")). @@ -533,37 +657,25 @@ func AddToContainer(c *restful.Container, factory informers.InformerFactory, op Required(false). DataFormat("limit=%d,page=%d"). DefaultValue("limit=10,page=1")). - Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). - Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixRepositoryTag}). - Returns(http.StatusOK, api.StatusOK, models.PageableResponse{})) + Returns(http.StatusOK, api.StatusOK, openpitrix.AppVersionReview{})) - webservice.Route(webservice.POST("/repos/{repo}/action"). - To(handler.DoRepoAction). - Doc("Start index repository event"). - Reads(openpitrix2.RepoActionRequest{}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixManagementTag}). - Param(webservice.PathParameter("repo", "repo id"))) - webservice.Route(webservice.POST("/workspaces/{workspace}/repos/{repo}/action"). - To(handler.DoRepoAction). - Doc("Start index repository event"). - Reads(openpitrix2.RepoActionRequest{}). - Returns(http.StatusOK, api.StatusOK, errors.Error{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixManagementTag}). - Param(webservice.PathParameter("repo", "repo id"))) - webservice.Route(webservice.GET("/repos/{repo}/events"). - To(handler.ListRepoEvents). - Doc("Get repository events"). - Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixRepositoryTag}). - Param(webservice.PathParameter("repo", "repo id"))) - webservice.Route(webservice.GET("/workspaces/{workspace}/repos/{repo}/events"). - To(handler.ListRepoEvents). - Doc("Get repository events"). - Returns(http.StatusOK, api.StatusOK, models.PageableResponse{}). - Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixRepositoryTag}). - Param(webservice.PathParameter("repo", "repo id"))) + webservice.Route(webservice.GET("/attachments/{attachment}"). + To(handler.DescribeAttachment). + Doc("Get attachment by attachment id"). + Param(webservice.PathParameter("attachment", "attachment id")). + Returns(http.StatusOK, api.StatusOK, openpitrix.Attachment{})) + + webservice.Route(webservice.POST("/attachments"). + To(handler.CreateAttachment). + Consumes(runtime.MimeMultipartFormData). + Doc("Create an attachment"). + Returns(http.StatusOK, api.StatusOK, openpitrix.Attachment{})) + + webservice.Route(webservice.DELETE("/attachments/{attachment}"). + To(handler.DeleteAttachments). + Doc("Delete one or multiple attachments, whose ids are separated by comma"). + Param(webservice.PathParameter("attachment", "attachment id")). + Returns(http.StatusOK, api.StatusOK, errors.Error{})) c.Add(webservice) diff --git a/pkg/kapis/openpitrix/v2alpha1/handler.go b/pkg/kapis/openpitrix/v2alpha1/handler.go new file mode 100644 index 0000000000000000000000000000000000000000..7076323773334be3af803fcba4697a751d513cd8 --- /dev/null +++ b/pkg/kapis/openpitrix/v2alpha1/handler.go @@ -0,0 +1,191 @@ +/* +Copyright 2020 The KubeSphere 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 v2alpha1 + +import ( + "github.com/emicklei/go-restful" + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + "kubesphere.io/kubesphere/pkg/informers" + openpitrix "kubesphere.io/kubesphere/pkg/models/openpitrix/v2alpha1" + openpitrixoptions "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" +) + +type openpitrixHandler struct { + openpitrix openpitrix.Interface +} + +func newOpenpitrixHandler(ksInformers informers.InformerFactory, ksClient versioned.Interface, options *openpitrixoptions.Options) *openpitrixHandler { + return &openpitrixHandler{ + openpitrix.NewOpenPitrixOperator(ksInformers), + } +} + +func (h *openpitrixHandler) DescribeRepo(req *restful.Request, resp *restful.Response) { + repoId := req.PathParameter("repo") + + result, err := h.openpitrix.DescribeRepo(repoId) + + if err != nil { + if apierrors.IsNotFound(err) { + api.HandleNotFound(resp, req, err) + return + } + klog.Errorln(err) + api.HandleInternalError(resp, req, err) + return + } + + resp.WriteEntity(result) +} + +func (h *openpitrixHandler) ListRepos(req *restful.Request, resp *restful.Response) { + q := query.ParseQueryParameter(req) + workspace := req.PathParameter("workspace") + + result, err := h.openpitrix.ListRepos(workspace, q) + + if err != nil { + klog.Errorln(err) + api.HandleInternalError(resp, req, err) + return + } + + resp.WriteEntity(result) +} + +func (h *openpitrixHandler) DescribeApplication(req *restful.Request, resp *restful.Response) { + clusterName := req.PathParameter("cluster") + workspace := req.PathParameter("workspace") + applicationId := req.PathParameter("application") + namespace := req.PathParameter("namespace") + + app, err := h.openpitrix.DescribeApplication(workspace, clusterName, namespace, applicationId) + + if err != nil { + klog.Errorln(err) + api.HandleInternalError(resp, nil, err) + return + } + + resp.WriteEntity(app) + return +} + +func (h *openpitrixHandler) ListApplications(req *restful.Request, resp *restful.Response) { + clusterName := req.PathParameter("cluster") + namespace := req.PathParameter("namespace") + workspace := req.PathParameter("workspace") + q := query.ParseQueryParameter(req) + + result, err := h.openpitrix.ListApplications(workspace, clusterName, namespace, q) + + if err != nil { + klog.Errorln(err) + api.HandleInternalError(resp, nil, err) + return + } + + resp.WriteAsJson(result) +} + +func (h *openpitrixHandler) ListApps(req *restful.Request, resp *restful.Response) { + workspace := req.PathParameter("workspace") + q := query.ParseQueryParameter(req) + + result, err := h.openpitrix.ListApps(workspace, q) + + if err != nil { + klog.Errorln(err) + api.HandleInternalError(resp, nil, err) + return + } + + resp.WriteAsJson(result) +} + +func (h *openpitrixHandler) ListAppVersion(req *restful.Request, resp *restful.Response) { + workspace := req.PathParameter("workspace") + app := req.PathParameter("app") + q := query.ParseQueryParameter(req) + + result, err := h.openpitrix.ListAppVersions(workspace, app, q) + + if err != nil { + klog.Errorln(err) + api.HandleInternalError(resp, nil, err) + return + } + + resp.WriteAsJson(result) +} + +func (h *openpitrixHandler) ListCategories(req *restful.Request, resp *restful.Response) { + q := query.ParseQueryParameter(req) + + result, err := h.openpitrix.ListCategories(q) + + if err != nil { + klog.Errorln(err) + api.HandleInternalError(resp, nil, err) + return + } + + resp.WriteAsJson(result) +} + +func (h *openpitrixHandler) DescribeCategory(req *restful.Request, resp *restful.Response) { + id := req.PathParameter("category") + + result, err := h.openpitrix.DescribeCategory(id) + + if err != nil { + klog.Errorln(err) + api.HandleInternalError(resp, nil, err) + return + } + + resp.WriteAsJson(result) +} + +func (h *openpitrixHandler) DescribeApp(req *restful.Request, resp *restful.Response) { + app := req.PathParameter("app") + + result, err := h.openpitrix.DescribeApp(app) + + if err != nil { + klog.Errorln(err) + api.HandleInternalError(resp, nil, err) + return + } + + resp.WriteAsJson(result) +} + +func (h *openpitrixHandler) DescribeAppVersion(req *restful.Request, resp *restful.Response) { + id := req.PathParameter("version") + + result, err := h.openpitrix.DescribeAppVersion(id) + + if err != nil { + klog.Errorln(err) + api.HandleInternalError(resp, nil, err) + return + } + + resp.WriteAsJson(result) +} diff --git a/pkg/kapis/openpitrix/v2alpha1/register.go b/pkg/kapis/openpitrix/v2alpha1/register.go new file mode 100644 index 0000000000000000000000000000000000000000..0617962e5728dd32c104a1f359a990f803197781 --- /dev/null +++ b/pkg/kapis/openpitrix/v2alpha1/register.go @@ -0,0 +1,243 @@ +/* +Copyright 2020 The KubeSphere 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 v2alpha1 + +import ( + "github.com/emicklei/go-restful" + "github.com/emicklei/go-restful-openapi" + "k8s.io/apimachinery/pkg/runtime/schema" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/apiserver/runtime" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/informers" + "kubesphere.io/kubesphere/pkg/models/openpitrix" + "kubesphere.io/kubesphere/pkg/server/params" + openpitrixoptions "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" + "net/http" +) + +const ( + GroupName = "openpitrix.io" +) + +var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v2alpha1"} + +func AddToContainer(c *restful.Container, ksInfomrers informers.InformerFactory, ksClient versioned.Interface, options *openpitrixoptions.Options) error { + webservice := runtime.NewWebService(GroupVersion) + + handler := newOpenpitrixHandler(ksInfomrers, ksClient, options) + + webservice.Route(webservice.GET("/workspaces/{workspace}/repos"). + To(handler.ListRepos). + Doc("List repositories in the specified workspace"). + Param(webservice.PathParameter("workspace", "the name of the workspace.").Required(true)). + Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). + Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). + Param(webservice.QueryParameter(query.ParameterName, "name used to do filtering").Required(false)). + Param(webservice.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")). + Param(webservice.QueryParameter(query.ParameterLimit, "limit").Required(false)). + Param(webservice.QueryParameter(query.ParameterAscending, "sort parameters, e.g. reverse=true").Required(false).DefaultValue("ascending=false")). + Param(webservice.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime")). + Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{v1alpha1.HelmRepo{}}}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag})) + + webservice.Route(webservice.GET("/workspaces/{workspace}/repos/{repo}"). + To(handler.DescribeRepo). + Doc("Describe the specified repository in the specified workspace"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, v1alpha1.HelmRepo{}). + Param(webservice.PathParameter("repo", "repo id"))) + + webservice.Route(webservice.GET("/applications"). + Deprecate(). + To(handler.ListApplications). + Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{v1alpha1.HelmRepo{}}}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Doc("List all applications"). + Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). + Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). + Param(webservice.QueryParameter(query.ParameterName, "name used to do filtering").Required(false)). + Param(webservice.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")). + Param(webservice.QueryParameter(query.ParameterLimit, "limit").Required(false)). + Param(webservice.QueryParameter(query.ParameterAscending, "sort parameters, e.g. reverse=true").Required(false).DefaultValue("ascending=false")). + Param(webservice.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime"))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications"). + To(handler.ListApplications). + Doc("List all applications within the specified namespace"). + Param(webservice.PathParameter("namespace", "the name of the namespace.").Required(true)). + Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). + Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). + Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). + Param(webservice.QueryParameter(query.ParameterName, "name used to do filtering").Required(false)). + Param(webservice.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")). + Param(webservice.QueryParameter(query.ParameterLimit, "limit").Required(false)). + Param(webservice.QueryParameter(query.ParameterAscending, "sort parameters, e.g. reverse=true").Required(false).DefaultValue("ascending=false")). + Param(webservice.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime"))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/applications"). + To(handler.ListApplications). + Param(webservice.PathParameter("workspace", "the name of the workspace.").Required(true)). + Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{v1alpha1.HelmRepo{}}}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Doc("List all applications within the specified workspace"). + Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). + Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). + Param(webservice.QueryParameter(query.ParameterName, "name used to do filtering").Required(false)). + Param(webservice.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")). + Param(webservice.QueryParameter(query.ParameterLimit, "limit").Required(false)). + Param(webservice.QueryParameter(query.ParameterAscending, "sort parameters, e.g. reverse=true").Required(false).DefaultValue("ascending=false")). + Param(webservice.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime"))) + + webservice.Route(webservice.GET("/applications/{application}"). + To(handler.DescribeApplication). + Returns(http.StatusOK, api.StatusOK, v1alpha1.HelmRelease{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Doc("Describe the specified application of the namespace"). + Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). + Param(webservice.PathParameter("application", "the id of the application").Required(true))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/applications/{application} "). + To(handler.DescribeApplication). + Returns(http.StatusOK, api.StatusOK, v1alpha1.HelmRelease{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Doc("Describe the specified application of the namespace"). + Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). + Param(webservice.PathParameter("application", "the id of the application").Required(true))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/clusters/{cluster}/namespaces/{namespace}/applications/{application}"). + To(handler.DescribeApplication). + Returns(http.StatusOK, api.StatusOK, v1alpha1.HelmRelease{}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.NamespaceResourcesTag}). + Doc("Describe the specified application of the namespace"). + Param(webservice.PathParameter("cluster", "the name of the cluster.").Required(true)). + Param(webservice.PathParameter("namespace", "the name of the project").Required(true)). + Param(webservice.PathParameter("application", "the id of the application").Required(true))) + + webservice.Route(webservice.GET("/apps"). + To(handler.ListApps). + Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{v1alpha1.HelmRepo{}}}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Doc("List all apps"). + Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). + Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). + Param(webservice.QueryParameter(query.ParameterName, "name used to do filtering").Required(false)). + Param(webservice.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")). + Param(webservice.QueryParameter(query.ParameterLimit, "limit").Required(false)). + Param(webservice.QueryParameter(query.ParameterAscending, "sort parameters, e.g. reverse=true").Required(false).DefaultValue("ascending=false")). + Param(webservice.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime"))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/apps"). + To(handler.ListApps). + Param(webservice.PathParameter("workspace", "the name of the workspace.").Required(true)). + Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{v1alpha1.HelmRepo{}}}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Doc("List all apps within the specified workspace"). + Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). + Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). + Param(webservice.QueryParameter(query.ParameterName, "name used to do filtering").Required(false)). + Param(webservice.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")). + Param(webservice.QueryParameter(query.ParameterLimit, "limit").Required(false)). + Param(webservice.QueryParameter(query.ParameterAscending, "sort parameters, e.g. reverse=true").Required(false).DefaultValue("ascending=false")). + Param(webservice.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime"))) + + webservice.Route(webservice.GET("/apps/{app}"). + To(handler.DescribeApp). + Doc("Describe the specified app template"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, v1alpha1.HelmApplication{}). + Param(webservice.PathParameter("app", "app template id"))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/apps/{app}"). + To(handler.DescribeApp). + Doc("Describe the specified app template"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, v1alpha1.HelmApplication{}). + Param(webservice.PathParameter("app", "app template id"))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/apps/{app}/versions"). + To(handler.ListAppVersion). + Param(webservice.PathParameter("workspace", "the name of the workspace.").Required(true)). + Param(webservice.PathParameter("app", "the id of the app.").Required(true)). + Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{v1alpha1.HelmRepo{}}}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Doc("List all apps within the specified workspace"). + Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). + Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). + Param(webservice.QueryParameter(query.ParameterName, "name used to do filtering").Required(false)). + Param(webservice.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")). + Param(webservice.QueryParameter(query.ParameterLimit, "limit").Required(false)). + Param(webservice.QueryParameter(query.ParameterAscending, "sort parameters, e.g. reverse=true").Required(false).DefaultValue("ascending=false")). + Param(webservice.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime"))) + + webservice.Route(webservice.GET("/apps/{app}/versions"). + To(handler.ListAppVersion). + Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{v1alpha1.HelmRepo{}}}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Param(webservice.PathParameter("app", "the id of the app.").Required(true)). + Doc("List all apps"). + Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). + Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). + Param(webservice.QueryParameter(query.ParameterName, "name used to do filtering").Required(false)). + Param(webservice.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")). + Param(webservice.QueryParameter(query.ParameterLimit, "limit").Required(false)). + Param(webservice.QueryParameter(query.ParameterAscending, "sort parameters, e.g. reverse=true").Required(false).DefaultValue("ascending=false")). + Param(webservice.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime"))) + + webservice.Route(webservice.GET("/workspaces/{workspace}/apps/{app}/versions/{version}"). + To(handler.DescribeAppVersion). + Doc("Describe the specified app template version"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, v1alpha1.HelmApplication{}). + Param(webservice.PathParameter("version", "app template version id")). + Param(webservice.PathParameter("app", "app template id")). + Param(webservice.PathParameter("workspaces", "the name of the workspace"))) + + webservice.Route(webservice.GET("/apps/{app}/versions/{version}"). + To(handler.DescribeAppVersion). + Doc("Describe the specified app template version"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, v1alpha1.HelmApplication{}). + Param(webservice.PathParameter("version", "app template version id")). + Param(webservice.PathParameter("app", "app template id"))) + + webservice.Route(webservice.GET("/categories"). + To(handler.ListCategories). + Doc("List categories"). + Returns(http.StatusOK, api.StatusOK, api.ListResult{Items: []interface{}{v1alpha1.HelmCategory{}}}). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Param(webservice.QueryParameter(params.ReverseParam, "sort parameters, e.g. reverse=true")). + Param(webservice.QueryParameter(params.OrderByParam, "sort parameters, e.g. orderBy=createTime")). + Param(webservice.QueryParameter(query.ParameterName, "name used to do filtering").Required(false)). + Param(webservice.QueryParameter(query.ParameterPage, "page").Required(false).DataFormat("page=%d").DefaultValue("page=1")). + Param(webservice.QueryParameter(query.ParameterLimit, "limit").Required(false)). + Param(webservice.QueryParameter(query.ParameterAscending, "sort parameters, e.g. reverse=true").Required(false).DefaultValue("ascending=false")). + Param(webservice.QueryParameter(query.ParameterOrderBy, "sort parameters, e.g. orderBy=createTime"))) + + webservice.Route(webservice.GET("/categories/{category}"). + To(handler.DescribeCategory). + Doc("Describe the specified category"). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag}). + Returns(http.StatusOK, api.StatusOK, openpitrix.Category{}). + Param(webservice.PathParameter("category", "category id")). + Metadata(restfulspec.KeyOpenAPITags, []string{constants.OpenpitrixTag})) + + c.Add(webservice) + return nil +} diff --git a/pkg/kapis/tenant/v1alpha2/handler.go b/pkg/kapis/tenant/v1alpha2/handler.go index cf534708ac9f3946912d1ddb94e5fba294325df7..542a4ea2e76e1a3a613aa188dcef6311584ae195 100644 --- a/pkg/kapis/tenant/v1alpha2/handler.go +++ b/pkg/kapis/tenant/v1alpha2/handler.go @@ -45,7 +45,6 @@ import ( "kubesphere.io/kubesphere/pkg/simple/client/events" "kubesphere.io/kubesphere/pkg/simple/client/logging" monitoringclient "kubesphere.io/kubesphere/pkg/simple/client/monitoring" - opclient "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" ) type tenantHandler struct { @@ -55,11 +54,11 @@ type tenantHandler struct { func newTenantHandler(factory informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface, evtsClient events.Client, loggingClient logging.Client, auditingclient auditing.Client, am am.AccessManagementInterface, authorizer authorizer.Authorizer, - monitoringclient monitoringclient.Interface, opClient opclient.Client, + monitoringclient monitoringclient.Interface, resourceGetter *resourcev1alpha3.ResourceGetter) *tenantHandler { return &tenantHandler{ - tenant: tenant.New(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, opClient, resourceGetter), + tenant: tenant.New(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourceGetter), } } diff --git a/pkg/kapis/tenant/v1alpha2/register.go b/pkg/kapis/tenant/v1alpha2/register.go index ac0bada101df249b4534d99000346e9a641efc8b..70427e90bc82a532023c18cd020ef7e6527318d7 100644 --- a/pkg/kapis/tenant/v1alpha2/register.go +++ b/pkg/kapis/tenant/v1alpha2/register.go @@ -48,7 +48,6 @@ import ( "kubesphere.io/kubesphere/pkg/simple/client/events" "kubesphere.io/kubesphere/pkg/simple/client/logging" monitoringclient "kubesphere.io/kubesphere/pkg/simple/client/monitoring" - opclient "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" ) const ( @@ -64,11 +63,11 @@ func Resource(resource string) schema.GroupResource { func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface, evtsClient events.Client, loggingClient logging.Client, auditingclient auditing.Client, am am.AccessManagementInterface, authorizer authorizer.Authorizer, - monitoringclient monitoringclient.Interface, opClient opclient.Client, cache cache.Cache) error { + monitoringclient monitoringclient.Interface, cache cache.Cache) error { mimePatch := []string{restful.MIME_JSON, runtime.MimeMergePatchJson, runtime.MimeJsonPatchJson} ws := runtime.NewWebService(GroupVersion) - handler := newTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, opClient, resourcev1alpha3.NewResourceGetter(factory, cache)) + handler := newTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourcev1alpha3.NewResourceGetter(factory, cache)) ws.Route(ws.GET("/clusters"). To(handler.ListClusters). diff --git a/pkg/models/monitoring/monitoring.go b/pkg/models/monitoring/monitoring.go index d934476024947e8f23123c178bce0f3a1ff076b4..8a5fe6d4079b135bb4a40f3bdf8d11231907bb7b 100644 --- a/pkg/models/monitoring/monitoring.go +++ b/pkg/models/monitoring/monitoring.go @@ -39,7 +39,6 @@ import ( "kubesphere.io/kubesphere/pkg/server/errors" "kubesphere.io/kubesphere/pkg/server/params" "kubesphere.io/kubesphere/pkg/simple/client/monitoring" - opclient "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" "sigs.k8s.io/application/api/v1beta1" appv1beta1 "sigs.k8s.io/application/api/v1beta1" ) @@ -72,13 +71,12 @@ type monitoringOperator struct { resourceGetter *resourcev1alpha3.ResourceGetter } -func NewMonitoringOperator(monitoringClient monitoring.Interface, metricsClient monitoring.Interface, k8s kubernetes.Interface, factory informers.InformerFactory, opClient opclient.Client, resourceGetter *resourcev1alpha3.ResourceGetter) MonitoringOperator { +func NewMonitoringOperator(monitoringClient monitoring.Interface, metricsClient monitoring.Interface, k8s kubernetes.Interface, factory informers.InformerFactory, resourceGetter *resourcev1alpha3.ResourceGetter) MonitoringOperator { return &monitoringOperator{ prometheus: monitoringClient, metricsserver: metricsClient, k8s: k8s, ks: factory.KubeSphereSharedInformerFactory(), - op: openpitrix.NewOpenpitrixOperator(factory.KubernetesSharedInformerFactory(), opClient), resourceGetter: resourceGetter, } } diff --git a/pkg/models/openpitrix/applications.go b/pkg/models/openpitrix/applications.go index e81f1fb8010d505d60ebb1ac88182ca35fc1d551..9d18aeab2f90d1a67b05b11f6d6ddbe7f5362e3e 100644 --- a/pkg/models/openpitrix/applications.go +++ b/pkg/models/openpitrix/applications.go @@ -14,408 +14,614 @@ limitations under the License. package openpitrix import ( - "encoding/json" - "github.com/golang/protobuf/ptypes/wrappers" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - appsv1 "k8s.io/api/apps/v1" - "k8s.io/api/core/v1" - "k8s.io/api/extensions/v1beta1" - "k8s.io/apimachinery/pkg/api/errors" + "bytes" + "context" + "errors" + "fmt" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/labels" - "k8s.io/client-go/informers" "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + v1alpha13 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + listers_v1alpha1 "kubesphere.io/kubesphere/pkg/client/listers/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/server/params" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" - "openpitrix.io/openpitrix/pkg/pb" - "openpitrix.io/openpitrix/pkg/util/pbutil" + "kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmrepoindex" + "kubesphere.io/kubesphere/pkg/simple/client/s3" + "kubesphere.io/kubesphere/pkg/utils/idutils" + "kubesphere.io/kubesphere/pkg/utils/reposcache" + "kubesphere.io/kubesphere/pkg/utils/stringutils" + "sigs.k8s.io/controller-runtime/pkg/client" + "sort" "strings" + "time" ) type ApplicationInterface interface { - ListApplications(conditions *params.Conditions, limit, offset int, orderBy string, reverse bool) (*models.PageableResponse, error) - DescribeApplication(namespace, applicationId, clusterName string) (*Application, error) - CreateApplication(clusterName, namespace string, request CreateClusterRequest) error - ModifyApplication(request ModifyClusterAttributesRequest) error - DeleteApplication(id string) error - UpgradeApplication(request UpgradeClusterRequest) error + ListApps(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) + DescribeApp(id string) (*App, error) + DeleteApp(id string) error + CreateApp(req *CreateAppRequest) (*CreateAppResponse, error) + ModifyApp(appId string, request *ModifyAppRequest) error + DeleteAppVersion(id string) error + ModifyAppVersion(id string, request *ModifyAppVersionRequest) error + DescribeAppVersion(id string) (*AppVersion, error) + CreateAppVersion(request *CreateAppVersionRequest) (*CreateAppVersionResponse, error) + ValidatePackage(request *ValidatePackageRequest) (*ValidatePackageResponse, error) + GetAppVersionPackage(appId, versionId string) (*GetAppVersionPackageResponse, error) + DoAppAction(appId string, request *ActionRequest) error + DoAppVersionAction(versionId string, request *ActionRequest) error + ListAppVersionAudits(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) + GetAppVersionFiles(versionId string, request *GetAppVersionFilesRequest) (*GetAppVersionPackageFilesResponse, error) + ListAppVersionReviews(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) + ListAppVersions(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) } type applicationOperator struct { - informers informers.SharedInformerFactory - opClient openpitrix.Client -} + backingStoreClient s3.Interface + informers externalversions.SharedInformerFactory -func newApplicationOperator(informers informers.SharedInformerFactory, opClient openpitrix.Client) ApplicationInterface { - return &applicationOperator{informers: informers, opClient: opClient} -} + appClient v1alpha13.HelmApplicationInterface + appVersionClient v1alpha13.HelmApplicationVersionInterface -type Application struct { - Name string `json:"name" description:"application name"` - Cluster *Cluster `json:"cluster,omitempty" description:"application cluster info"` - Version *AppVersion `json:"version,omitempty" description:"application template version info"` - App *App `json:"app,omitempty" description:"application template info"` - WorkLoads *workLoads `json:"workloads,omitempty" description:"application workloads"` - Services []v1.Service `json:"services,omitempty" description:"application services"` - Ingresses []v1beta1.Ingress `json:"ingresses,omitempty" description:"application ingresses"` -} + appLister listers_v1alpha1.HelmApplicationLister + versionLister listers_v1alpha1.HelmApplicationVersionLister -type workLoads struct { - Deployments []appsv1.Deployment `json:"deployments,omitempty" description:"deployment list"` - Statefulsets []appsv1.StatefulSet `json:"statefulsets,omitempty" description:"statefulset list"` - Daemonsets []appsv1.DaemonSet `json:"daemonsets,omitempty" description:"daemonset list"` -} + repoLister listers_v1alpha1.HelmRepoLister + ctgLister listers_v1alpha1.HelmCategoryLister + rlsLister listers_v1alpha1.HelmReleaseLister -type resourceInfo struct { - Deployments []appsv1.Deployment `json:"deployments,omitempty" description:"deployment list"` - Statefulsets []appsv1.StatefulSet `json:"statefulsets,omitempty" description:"statefulset list"` - Daemonsets []appsv1.DaemonSet `json:"daemonsets,omitempty" description:"daemonset list"` - Services []v1.Service `json:"services,omitempty" description:"application services"` - Ingresses []v1beta1.Ingress `json:"ingresses,omitempty" description:"application ingresses"` + cachedRepos reposcache.ReposCache } -func (c *applicationOperator) ListApplications(conditions *params.Conditions, limit, offset int, orderBy string, reverse bool) (*models.PageableResponse, error) { - describeClustersRequest := &pb.DescribeClustersRequest{ - Limit: uint32(limit), - Offset: uint32(offset)} - if keyword := conditions.Match[Keyword]; keyword != "" { - describeClustersRequest.SearchWord = &wrappers.StringValue{Value: keyword} - } - if runtimeId := conditions.Match[RuntimeId]; runtimeId != "" { - describeClustersRequest.RuntimeId = []string{runtimeId} - } - if appId := conditions.Match[AppId]; appId != "" { - describeClustersRequest.AppId = []string{appId} - } - if versionId := conditions.Match[VersionId]; versionId != "" { - describeClustersRequest.VersionId = []string{versionId} - } - if status := conditions.Match[Status]; status != "" { - describeClustersRequest.Status = strings.Split(status, "|") - } - if zone := conditions.Match[Zone]; zone != "" { - describeClustersRequest.Zone = []string{zone} - } - if orderBy != "" { - describeClustersRequest.SortKey = &wrappers.StringValue{Value: orderBy} +func newApplicationOperator(cached reposcache.ReposCache, informers externalversions.SharedInformerFactory, ksClient versioned.Interface, storeClient s3.Interface) ApplicationInterface { + op := &applicationOperator{ + backingStoreClient: storeClient, + informers: informers, + repoLister: informers.Application().V1alpha1().HelmRepos().Lister(), + + appClient: ksClient.ApplicationV1alpha1().HelmApplications(), + appVersionClient: ksClient.ApplicationV1alpha1().HelmApplicationVersions(), + + appLister: informers.Application().V1alpha1().HelmApplications().Lister(), + versionLister: informers.Application().V1alpha1().HelmApplicationVersions().Lister(), + + ctgLister: informers.Application().V1alpha1().HelmCategories().Lister(), + rlsLister: informers.Application().V1alpha1().HelmReleases().Lister(), + cachedRepos: cached, } - describeClustersRequest.Reverse = &wrappers.BoolValue{Value: reverse} - resp, err := c.opClient.DescribeClusters(openpitrix.SystemContext(), describeClustersRequest) + + return op +} + +// save icon data and helm application +func (c *applicationOperator) createApp(app *v1alpha1.HelmApplication, iconData []byte) (*v1alpha1.HelmApplication, error) { + exists, err := c.getHelmAppByName(app.GetWorkspace(), app.GetTrueName()) if err != nil { - klog.Errorln(err) return nil, err } - result := models.PageableResponse{TotalCount: int(resp.TotalCount)} - result.Items = make([]interface{}, 0) - for _, cluster := range resp.ClusterSet { - app, err := c.describeApplication(cluster) + if exists != nil { + return nil, appItemExists + } + + if len(iconData) != 0 { + // save icon attachment + iconId := idutils.GetUuid(v1alpha1.HelmAttachmentPrefix) + err = c.backingStoreClient.Upload(iconId, iconId, bytes.NewBuffer(iconData)) if err != nil { - klog.Errorln(err) + klog.Errorf("save icon attachment failed, error: %s", err) return nil, err } - result.Items = append(result.Items, app) + app.Spec.Icon = iconId } - return &result, nil + app, err = c.appClient.Create(context.TODO(), app, metav1.CreateOptions{}) + return app, err } -func (c *applicationOperator) describeApplication(cluster *pb.Cluster) (*Application, error) { - var app Application - app.Name = cluster.Name.Value - app.Cluster = convertCluster(cluster) - versionInfo, err := c.opClient.DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{VersionId: []string{cluster.GetVersionId().GetValue()}}) - if err != nil { - klog.Errorln(err) +// get helm app by name in workspace +func (c *applicationOperator) getHelmAppByName(workspace, name string) (*v1alpha1.HelmApplication, error) { + ls := map[string]string{ + constants.WorkspaceLabelKey: workspace, + } + + list, err := c.appLister.List(labels.SelectorFromSet(ls)) + + if err != nil && !apierrors.IsNotFound(err) { return nil, err } - if len(versionInfo.AppVersionSet) > 0 { - app.Version = convertAppVersion(versionInfo.AppVersionSet[0]) + + if len(list) > 0 { + for _, a := range list { + if a.GetTrueName() == name { + return a, nil + } + } } - appInfo, err := c.opClient.DescribeApps(openpitrix.SystemContext(), &pb.DescribeAppsRequest{AppId: []string{cluster.GetAppId().GetValue()}, Limit: 1}) + + return nil, nil +} + +func (c *applicationOperator) ValidatePackage(request *ValidatePackageRequest) (*ValidatePackageResponse, error) { + + chrt, err := helmrepoindex.LoadPackage(request.VersionPackage) + + result := &ValidatePackageResponse{} + if err != nil { - klog.Errorln(err) - return nil, err - } - if len(appInfo.AppSet) > 0 { - app.App = convertApp(appInfo.GetAppSet()[0]) + matchPackageFailedError(err, result) + if (result.Error == "EOF" || result.Error == "") && len(result.ErrorDetails) == 0 { + klog.Errorf("package parse failed, error: %s", err.Error()) + return nil, errors.New("package parse failed") + } + } else { + result.Name = chrt.GetName() + result.VersionName = chrt.GetVersionName() + result.Description = chrt.GetDescription() + result.URL = chrt.GetUrls() } - return &app, nil + + return result, nil } -func (c *applicationOperator) DescribeApplication(namespace string, applicationId string, clusterName string) (*Application, error) { - describeClusterRequest := &pb.DescribeClustersRequest{ - ClusterId: []string{applicationId}, - RuntimeId: []string{clusterName}, - Zone: []string{namespace}, - WithDetail: pbutil.ToProtoBool(true), - Limit: 1, +func (c *applicationOperator) DoAppAction(appId string, request *ActionRequest) error { + + app, err := c.appLister.Get(appId) + if err != nil { + return err } - clusters, err := c.opClient.DescribeClusters(openpitrix.SystemContext(), describeClusterRequest) + var filterState string + switch request.Action { + case ActionSuspend: + if app.Status.State != v1alpha1.StateActive { + err = actionNotSupport + } + filterState = v1alpha1.StateActive + case ActionRecover: + if app.Status.State != v1alpha1.StateSuspended { + err = actionNotSupport + } + filterState = v1alpha1.StateSuspended + default: + err = actionNotSupport + } if err != nil { - klog.Errorln(err) - return nil, err + return err } - var cluster *pb.Cluster - if len(clusters.ClusterSet) > 0 { - cluster = clusters.GetClusterSet()[0] - } else { - err := status.New(codes.NotFound, "resource not found").Err() - klog.Errorln(err) - return nil, err + var versions []*v1alpha1.HelmApplicationVersion + ls := map[string]string{ + constants.ChartApplicationIdLabelKey: appId, } - app, err := c.describeApplication(cluster) + versions, err = c.versionLister.List(labels.SelectorFromSet(ls)) if err != nil { - klog.Errorln(err) - return nil, err + klog.Errorf("get helm app %s version failed, error: %s", appId, err) + return err } - resource := new(resourceInfo) - workloads := cluster.AdditionalInfo.GetValue() - if workloads == "" { - err := status.New(codes.NotFound, "cannot get workload").Err() - klog.Errorln(err) + versions = filterAppVersionByState(versions, []string{filterState}) + for _, version := range versions { + err = c.DoAppVersionAction(version.GetHelmApplicationVersionId(), request) + if err != nil { + return err + } + } + + return nil +} + +func (c *applicationOperator) CreateApp(req *CreateAppRequest) (*CreateAppResponse, error) { + if c.backingStoreClient == nil { + return nil, invalidS3Config + } + chrt, err := helmrepoindex.LoadPackage(req.VersionPackage) + if err != nil { + klog.Errorf("load package %s/%s failed, error: %s", req.Isv, req.Name, err) return nil, err } - err = json.Unmarshal([]byte(workloads), resource) + + // create helm application + name := idutils.GetUuid36(v1alpha1.HelmApplicationIdPrefix) + helmApp := &v1alpha1.HelmApplication{ + ObjectMeta: metav1.ObjectMeta{ + Name: name, + Annotations: map[string]string{ + constants.CreatorAnnotationKey: req.Username, + }, + Labels: map[string]string{ + constants.WorkspaceLabelKey: req.Isv, + }, + }, + Spec: v1alpha1.HelmApplicationSpec{ + Name: req.Name, + Description: stringutils.ShortenString(chrt.GetDescription(), v1alpha1.MsgLen), + }, + } + app, err := c.createApp(helmApp, req.Icon) if err != nil { - klog.Errorln(err) + klog.Errorf("create helm application %s/%s failed, error: %s", req.Isv, req.Name, err) + if helmApp.Spec.Icon != "" { + c.backingStoreClient.Delete(helmApp.Spec.Icon) + } return nil, err + } else { + klog.V(4).Infof("helm application %s/%s created, app id: %s", req.Isv, req.Name, app.Name) } - app.WorkLoads = &workLoads{ - Deployments: resource.Deployments, - Statefulsets: resource.Statefulsets, - Daemonsets: resource.Daemonsets, + // create app version + chartPackage := req.VersionPackage.String() + ver := buildApplicationVersion(app, chrt, &chartPackage, req.Username) + ver, err = c.createApplicationVersion(ver) + + if err != nil { + klog.Errorf("create helm application %s/%s versions failed, error: %s", req.Isv, req.Name, err) + return nil, err + } else { + klog.V(4).Infof("helm application version %s/%s created, app version id: %s", req.Isv, req.Name, ver.Name) } - app.Services = resource.Services - app.Ingresses = resource.Ingresses - return app, nil + + return &CreateAppResponse{ + AppID: app.GetHelmApplicationId(), + VersionID: ver.GetHelmApplicationVersionId(), + }, nil } -func (c *applicationOperator) getWorkLoads(namespace string, clusterRoles []*pb.ClusterRole) (*workLoads, error) { +func buildLabelSelector(conditions *params.Conditions) map[string]string { + ls := make(map[string]string) - var works workLoads - for _, clusterRole := range clusterRoles { - workLoadName := clusterRole.Role.Value - if len(workLoadName) > 0 { - if strings.HasSuffix(workLoadName, openpitrix.DeploySuffix) { - name := strings.Split(workLoadName, openpitrix.DeploySuffix)[0] + repoId := conditions.Match[RepoId] + // app store come first + if repoId != "" { + ls[constants.ChartRepoIdLabelKey] = repoId + } else { + if conditions.Match[WorkspaceLabel] != "" { + ls[constants.WorkspaceLabelKey] = conditions.Match[WorkspaceLabel] + } + } + if conditions.Match[CategoryId] != "" { + ls[constants.CategoryIdLabelKey] = conditions.Match[CategoryId] + } - item, err := c.informers.Apps().V1().Deployments().Lister().Deployments(namespace).Get(name) + return ls +} - if err != nil { - // app not ready - if errors.IsNotFound(err) { - continue - } - klog.Errorln(err) - return nil, err - } +func (c *applicationOperator) ListApps(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { + apps, err := c.listApps(conditions) + if err != nil { + klog.Error(err) + return nil, err + } + apps = filterApps(apps, conditions) - works.Deployments = append(works.Deployments, *item) - continue - } + if reverse { + sort.Sort(sort.Reverse(HelmApplicationList(apps))) + } else { + sort.Sort(HelmApplicationList(apps)) + } - if strings.HasSuffix(workLoadName, openpitrix.DaemonSuffix) { - name := strings.Split(workLoadName, openpitrix.DaemonSuffix)[0] - item, err := c.informers.Apps().V1().DaemonSets().Lister().DaemonSets(namespace).Get(name) - if err != nil { - // app not ready - if errors.IsNotFound(err) { - continue - } - klog.Errorln(err) - return nil, err - } - works.Daemonsets = append(works.Daemonsets, *item) - continue - } + items := make([]interface{}, 0, limit) - if strings.HasSuffix(workLoadName, openpitrix.StateSuffix) { - name := strings.Split(workLoadName, openpitrix.StateSuffix)[0] - item, err := c.informers.Apps().V1().StatefulSets().Lister().StatefulSets(namespace).Get(name) - if err != nil { - // app not ready - if errors.IsNotFound(err) { - continue - } - klog.Errorln(err) - return nil, err - } - works.Statefulsets = append(works.Statefulsets, *item) - continue - } + for i, j := offset, 0; i < len(apps) && j < limit; { + versions, err := c.getAppVersionsByAppId(apps[i].GetHelmApplicationId()) + if err != nil && !apierrors.IsNotFound(err) { + return nil, err } + + ctg, _ := c.ctgLister.Get(apps[i].GetHelmCategoryId()) + + items = append(items, convertApp(apps[i], versions, ctg, 0)) + i++ + j++ } - return &works, nil + return &models.PageableResponse{Items: items, TotalCount: len(apps)}, nil } -func (c *applicationOperator) getLabels(namespace string, workloads *workLoads) *[]map[string]string { +func (c *applicationOperator) DeleteApp(id string) error { + app, err := c.appLister.Get(id) + if err != nil { + if apierrors.IsNotFound(err) { + klog.V(4).Infof("app %s has been deleted", id) + return nil + } else { + klog.Error(err) + return nil + } + } - var workloadLabels []map[string]string - if workloads == nil { - return nil + ls := map[string]string{ + constants.ChartApplicationIdLabelKey: app.GetHelmApplicationId(), } + releases, err := c.rlsLister.List(labels.SelectorFromSet(ls)) - for _, workload := range workloads.Deployments { - deploy, err := c.informers.Apps().V1().Deployments().Lister().Deployments(namespace).Get(workload.Name) - if errors.IsNotFound(err) { - continue - } - workloadLabels = append(workloadLabels, deploy.Labels) + if err != nil && !apierrors.IsNotFound(err) { + klog.Error(err) + return err + } else if len(releases) > 0 { + return fmt.Errorf("app %s has releases not deleted", id) } - for _, workload := range workloads.Daemonsets { - daemonset, err := c.informers.Apps().V1().DaemonSets().Lister().DaemonSets(namespace).Get(workload.Name) - if errors.IsNotFound(err) { - continue + list, err := c.versionLister.List(labels.SelectorFromSet(ls)) + if err != nil { + if apierrors.IsNotFound(err) { + klog.V(4).Infof("versions of app %s has been deleted", id) + } else { + klog.Error(err) + return err } - workloadLabels = append(workloadLabels, daemonset.Labels) + } else if len(list) > 0 { + return fmt.Errorf("app %s has some versions not deleted", id) + } + + err = c.appClient.Delete(context.TODO(), id, metav1.DeleteOptions{}) + if err != nil { + klog.Errorf("delete app %s failed, error: %s", id, err) + return err + } else { + c.deleteAppAttachment(app) + klog.V(4).Infof("app %s deleted", app.Name) } - for _, workload := range workloads.Statefulsets { - statefulset, err := c.informers.Apps().V1().StatefulSets().Lister().StatefulSets(namespace).Get(workload.Name) - if errors.IsNotFound(err) { - continue + // delete application in app store + id = fmt.Sprintf("%s%s", id, v1alpha1.HelmApplicationAppStoreSuffix) + app, err = c.appClient.Get(context.TODO(), id, metav1.GetOptions{}) + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } else { + klog.Errorf("get app %s failed, error: %s", id, err) + return err } - workloadLabels = append(workloadLabels, statefulset.Labels) } - return &workloadLabels + // delete application in app store + err = c.appClient.Delete(context.TODO(), id, metav1.DeleteOptions{}) + if err != nil && !apierrors.IsNotFound(err) { + klog.Errorf("delete app %s failed, error: %s", id, err) + return err + } else { + c.deleteAppAttachment(app) + klog.V(4).Infof("app %s deleted", app.Name) + } + + return nil } -func (c *applicationOperator) isExist(svcs []v1.Service, svc *v1.Service) bool { - for _, item := range svcs { - if item.Name == svc.Name && item.Namespace == svc.Namespace { - return true - } +func (c *applicationOperator) ModifyApp(appId string, request *ModifyAppRequest) error { + if c.backingStoreClient == nil { + return invalidS3Config + } + + app, err := c.appLister.Get(appId) + if err != nil { + klog.Error(err) + return err } - return false -} -func (c *applicationOperator) getSvcs(namespace string, workLoadLabels *[]map[string]string) []v1.Service { - if len(*workLoadLabels) == 0 { - return nil + appCopy := app.DeepCopy() + // modify category + if request.CategoryID != nil { + if *request.CategoryID == "" { + delete(appCopy.Labels, constants.CategoryIdLabelKey) + klog.V(4).Infof("delete app %s category", app.Name) + } else { + appCopy.Labels[constants.CategoryIdLabelKey] = *request.CategoryID + klog.V(4).Infof("set app %s category to %s", app.Name, *request.CategoryID) + } } - var services []v1.Service - for _, label := range *workLoadLabels { - labelSelector := labels.Set(label).AsSelector() - svcs, err := c.informers.Core().V1().Services().Lister().Services(namespace).List(labelSelector) + + // modify app name + if request.Name != nil && len(*request.Name) > 0 && app.GetTrueName() != *request.Name { + existsApp, err := c.getHelmAppByName(app.GetWorkspace(), *request.Name) if err != nil { - klog.Errorf("get app's svc failed, reason: %v", err) + return err } - for _, item := range svcs { - if !c.isExist(services, item) { - services = append(services, *item) - } + if existsApp != nil { + return appItemExists } + klog.V(4).Infof("change app %s name from %s to %s", app.Name, app.GetTrueName(), *request.Name) + appCopy.Spec.Name = *request.Name } - return services -} + // save app attachment and icon + add, err := c.modifyAppAttachment(appCopy, request) + if err != nil { + klog.Errorf("add app attachment %s failed, error: %s", appCopy.Name, err) + return err + } -func (c *applicationOperator) getIng(namespace string, services []v1.Service) []v1beta1.Ingress { - if services == nil { - return nil + if request.Description != nil { + appCopy.Spec.Description = *request.Description + } + if request.Abstraction != nil { + appCopy.Spec.Abstraction = *request.Abstraction } - var ings []v1beta1.Ingress - for _, svc := range services { - ingresses, err := c.informers.Extensions().V1beta1().Ingresses().Lister().Ingresses(namespace).List(labels.Everything()) - if err != nil { - klog.Error(err) - return ings + if request.Home != nil { + appCopy.Spec.AppHome = *request.Home + } + appCopy.Status.UpdateTime = &metav1.Time{Time: time.Now()} + + patch := client.MergeFrom(app) + data, err := patch.Data(appCopy) + if err != nil { + klog.Errorf("create patch failed, error: %s", err) + return err + } + + _, err = c.appClient.Patch(context.TODO(), appId, patch.Type(), data, metav1.PatchOptions{}) + if err != nil { + klog.Errorf("patch helm application: %s failed, error: %s", appId, err) + if add != "" { + // if patch failed, delete saved icon or attachment + c.backingStoreClient.Delete(add) } + return err + } + return nil +} - for _, ingress := range ingresses { - if ingress.Spec.Backend.ServiceName != svc.Name { - continue - } +func (c *applicationOperator) deleteAppAttachment(app *v1alpha1.HelmApplication) { + if app.Spec.Icon != "" { + c.backingStoreClient.Delete(app.Spec.Icon) + } - exist := false - var tmpRules []v1beta1.IngressRule - for _, rule := range ingress.Spec.Rules { - for _, p := range rule.HTTP.Paths { - if p.Backend.ServiceName == svc.Name { - exist = true - tmpRules = append(tmpRules, rule) - } + for _, id := range app.Spec.Attachments { + c.backingStoreClient.Delete(id) + } +} + +func (c *applicationOperator) modifyAppAttachment(app *v1alpha1.HelmApplication, request *ModifyAppRequest) (add string, err error) { + if request.Type == nil { + return "", nil + } + switch *request.Type { + case v1alpha1.AttachmentTypeScreenshot: + if request.Sequence == nil { + return "", nil + } + seq := *request.Sequence + attachments := &app.Spec.Attachments + if len(request.AttachmentContent) == 0 { + // delete old attachments + if len(*attachments) > int(seq) { + del := (*attachments)[seq] + err = c.backingStoreClient.Delete(del) + if err != nil { + return "", err + } else { + *attachments = append((*attachments)[:seq], (*attachments)[seq+1:]...) } } - - if exist { - ing := v1beta1.Ingress{} - ing.Name = ingress.Name - ing.Spec.Rules = tmpRules - ings = append(ings, ing) + } else { + if len(*attachments) < 6 { + // add attachment to app + add := idutils.GetUuid("att-") + *attachments = append(*attachments, add) + err = c.backingStoreClient.Upload(add, add, bytes.NewBuffer(request.AttachmentContent)) + if err != nil { + return "", err + } else { + return add, nil + } + } + } + case v1alpha1.AttachmentTypeIcon: // modify app icon + // delete old icon + if app.Spec.Icon != "" { + err = c.backingStoreClient.Delete(app.Spec.Icon) + if err != nil { + return "", err } } } - - return ings + if len(request.AttachmentContent) != 0 { + add := idutils.GetUuid("att-") + err = c.backingStoreClient.Upload(add, add, bytes.NewBuffer(request.AttachmentContent)) + if err != nil { + return "", err + } else { + app.Spec.Icon = add + return add, nil + } + } + return "", nil } -func (c *applicationOperator) CreateApplication(clusterName, namespace string, request CreateClusterRequest) error { - _, err := c.opClient.CreateCluster(openpitrix.ContextWithUsername(request.Username), &pb.CreateClusterRequest{ - AppId: &wrappers.StringValue{Value: request.AppId}, - VersionId: &wrappers.StringValue{Value: request.VersionId}, - RuntimeId: &wrappers.StringValue{Value: clusterName}, - Conf: &wrappers.StringValue{Value: request.Conf}, - Zone: &wrappers.StringValue{Value: namespace}, - }) +// modify icon or attachment of the app +// added: new attachments have been saved to store +// deleted: attachments should be deleted +func (c *applicationOperator) appAttachmentDiff(old, newApp *v1alpha1.HelmApplication) (added, deleted []string) { - if err != nil { - klog.Errorln(err) - return err - } + added = make([]string, 0, 7) + deleted = make([]string, 0, 7) - return nil -} + if old.Spec.Icon != newApp.Spec.Icon { + if old.Spec.Icon != "" && !strings.HasPrefix(old.Spec.Icon, "http://") { + deleted = append(deleted, old.Spec.Icon) + } + added = append(added, newApp.Spec.Icon) + } -func (c *applicationOperator) ModifyApplication(request ModifyClusterAttributesRequest) error { + existsAtt := make(map[string]string, 6) + newAtt := make(map[string]string, 6) - modifyClusterAttributesRequest := &pb.ModifyClusterAttributesRequest{ClusterId: &wrappers.StringValue{Value: request.ClusterID}} - if request.Name != nil { - modifyClusterAttributesRequest.Name = &wrappers.StringValue{Value: *request.Name} + for _, id := range newApp.Spec.Attachments { + newAtt[id] = "" } - if request.Description != nil { - modifyClusterAttributesRequest.Description = &wrappers.StringValue{Value: *request.Description} + + for _, id := range old.Spec.Attachments { + existsAtt[id] = "" } - _, err := c.opClient.ModifyClusterAttributes(openpitrix.SystemContext(), modifyClusterAttributesRequest) + for _, id := range newApp.Spec.Attachments { + if _, exists := existsAtt[id]; !exists { + added = append(added, id) + } + } - if err != nil { - klog.Errorln(err) - return err + for _, id := range old.Spec.Attachments { + if _, exists := newAtt[id]; !exists { + deleted = append(deleted, id) + } } - return nil + return added, deleted } -func (c *applicationOperator) DeleteApplication(applicationId string) error { - _, err := c.opClient.DeleteClusters(openpitrix.SystemContext(), &pb.DeleteClustersRequest{ClusterId: []string{applicationId}, Force: &wrappers.BoolValue{Value: true}}) +func (c *applicationOperator) DescribeApp(id string) (*App, error) { + var helmApp *v1alpha1.HelmApplication + var ctg *v1alpha1.HelmCategory + var err error + helmApp, err = c.getHelmApplication(id) if err != nil { - klog.Errorln(err) - return err + klog.Error(err) + return nil, err } - return nil -} + versions, err := c.getAppVersionsByAppId(helmApp.GetHelmApplicationId()) + if err != nil { + klog.Error(err) + return nil, err + } -func (c *applicationOperator) UpgradeApplication(request UpgradeClusterRequest) error { - _, err := c.opClient.UpgradeCluster(openpitrix.ContextWithUsername(request.Username), &pb.UpgradeClusterRequest{ - ClusterId: &wrappers.StringValue{Value: request.ClusterId}, - VersionId: &wrappers.StringValue{Value: request.VersionId}, - }) + ctg, err = c.ctgLister.Get(helmApp.GetHelmCategoryId()) - if err != nil { - klog.Errorln(err) - return err + if err != nil && !apierrors.IsNotFound(err) { + klog.Error(err) + return nil, err } - return nil + app := convertApp(helmApp, versions, ctg, 0) + return app, nil +} + +func (c *applicationOperator) listApps(conditions *params.Conditions) (ret []*v1alpha1.HelmApplication, err error) { + repoId := conditions.Match[RepoId] + if repoId != "" && repoId != v1alpha1.AppStoreRepoId { + // get helm application from helm repo + if ret, exists := c.cachedRepos.ListApplicationsByRepoId(repoId); !exists { + klog.Warningf("load repo failed, repo id: %s", repoId) + return nil, loadRepoInfoFailed + } else { + return ret, nil + } + } else { + ret, err = c.appLister.List(labels.SelectorFromSet(buildLabelSelector(conditions))) + } + + return +} + +func (c *applicationOperator) getHelmApplication(appId string) (*v1alpha1.HelmApplication, error) { + if app, exists := c.cachedRepos.GetApplication(appId); exists { + return app, nil + } else { + return c.appLister.Get(appId) + } } diff --git a/pkg/models/openpitrix/applications_test.go b/pkg/models/openpitrix/applications_test.go index d3c1882761ea8d4f0facc82ff527f6dfa0b58832..37fa5a3a471e214992f7202108a6a6812f2fd0db 100644 --- a/pkg/models/openpitrix/applications_test.go +++ b/pkg/models/openpitrix/applications_test.go @@ -1,9 +1,12 @@ /* Copyright 2020 The KubeSphere 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. @@ -14,96 +17,158 @@ limitations under the License. package openpitrix import ( - "github.com/golang/mock/gomock" - "github.com/golang/protobuf/ptypes/wrappers" - "k8s.io/api/core/v1" - "k8s.io/apimachinery/pkg/api/errors" + "context" + "encoding/base64" + "github.com/go-openapi/strfmt" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" - "k8s.io/apimachinery/pkg/runtime" - "k8s.io/apimachinery/pkg/runtime/schema" - "k8s.io/client-go/informers" - "k8s.io/client-go/kubernetes/fake" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" - "openpitrix.io/openpitrix/pkg/pb" + "k8s.io/client-go/kubernetes" + fakek8s "k8s.io/client-go/kubernetes/fake" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + fakeks "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake" + "kubesphere.io/kubesphere/pkg/informers" + "kubesphere.io/kubesphere/pkg/server/params" + "kubesphere.io/kubesphere/pkg/simple/client/s3/fake" "testing" ) -func namespacesToRuntimeObjects(namespaces ...*v1.Namespace) []runtime.Object { - var objs []runtime.Object - for _, deploy := range namespaces { - objs = append(objs, deploy) +var rawChartData = "H4sIFAAAAAAA/ykAK2FIUjBjSE02THk5NWIzVjBkUzVpWlM5Nk9WVjZNV2xqYW5keVRRbz1IZWxtAOxYUW/bNhDOM3/FTVmBNltoubEdQEAfirTAim1pMA/ZwzAUtHSS2FAkS1JOvLT77QNJ2XGUZEmxJukw34NEkcfj3fG+41EOrRsc1Mw4umCN2LoPStM0nYxG4Z2maf+dDif7W8NROhyP0v3R/t5WOnw+nAy3IL0XbXrUWsfMVvqv1+ob9x8hpvkxGsuVzGD+nDCtV59DOpzQlBRoc8O1C30v4QcUDeQ+YKBUBn5sZ2gkOrREsgYz8AFF3EJjBkxrwXPmZ5L5UmpKhzQlj232hjoK+J8z0aK9twRwG/6fD8d9/I+GG/w/CBkMGD1QrXQZDAnhDaswIwAGtbLcKbPIQFZcnhEA3QpxpATPFxm8KQ+VOzJoUToC4FiVQZJ0Ao5aIaaYG3Q2g9//CLnh7RyN4QUGtrIV4krnYzvjf0gB/w4bLZhDO3hXo9BoLHX6y6WCW/C/t7c/6eF/NN6c/w9D5+eDHZjzJgOLDkou0J/dLxrvlrzGDHYGnz4Rz0Ven2kmC3A1gkcuqDK0Qy1ASce3CwWWXCIkPrKoZ0xg92KItcIBjQXnoZdCj+Phs54M4CM408ocJnuhyZtpW5b8DJLdBDpZKAvfjKodGGQOga1W8OllAR9aJnjJsfClSFCakt8wyg78zq/gDbAww5y1FsGqBteqmmhqyVEUFphBELzhDgtwClzNLTydLYIbXh1OPS+XFViN+TNK3pRgUCCznb9yJR3j0nbVU+jjDk65EDBDaK3X0wILynfaXu/VZfK88CwvV47sZ9alw24cv4uzhV3J+TYonr24+25e6LhyQRRCf4n+iXOXel7q/EzltOHSlZA8sbtPbNKTFRe9e2xd37wUcWtb6bHRVbl+G8N2drERuQSbobhpSwPLxX727Vh3cWx3ZTp89Ae1YDlC8l0Cybvk88GjmkbJqJ69Qb04GPWrUTTU1oOgcgbn58BlLtqiZwqNi/UGLQrMnTI/dQLpWnR0lr1c3UH8GNOanqzgSLkarK4S5+fXTPkIH1rlsGfpVSkNk6zCYne2iIKWkTJFM+d5f3701LRT/p991Tdx99r1423pin8irOn1OnNpHZM5XtZ4HTzXxWg/YdvOQpbnvurzmay1eKMxgfll5D28KelcZqN5XLmX9p9eNvUii9FnNwmS67at4XwpMukayZ0EXMHyY5++j0+9+i9XsuRVw/SXvAze+v9nnPbqv3E63tR/D0InXBYZHIRt/5lp0qBjBXPM3wBXKWoZH1eBG/PU2i+kIVnO9qwZ+C8CsEHaV0oB/9Qf6bySyuB9rHEb/sd7V/7/7E3GG/w/BG3DEXMOjbS+DogxAKc1Spi1XBT+OqNZfsIqtJRsw6/+ymNbrZVxFmyNQkAl1Awa5vKay+p7f+dhjs8RNHP1Wj+TBdkGiVX4IQxPtcGSn2EBp9zV8M0zCm+lWICSYaZXCTQaEFwiJfTV9N3UKYNkG7p69fhgCgU3ltCKu0F4RvUJnf1pBuG57KirgX8sP+1cDi4EzVh+0upw97Vkh9pTTXbojJ2QHeoa31aGV2TnL7INx8xw1Vp48+q1JVQb9R5zRygvkA0iu1HvCZ3bXBU42CS9DW1oQ18z/R0AAP//GfF7tgAeAAA=" + +func TestOpenPitrixApp(t *testing.T) { + appOperator := prepareAppOperator() + + chartData, _ := base64.RawStdEncoding.DecodeString(rawChartData) + + validateReq := &ValidatePackageRequest{ + VersionPackage: chartData, + } + // validate package + validateResp, err := appOperator.ValidatePackage(validateReq) + if err != nil || validateResp.Error != "" { + klog.Errorf("validate pacakge failed, error: %s", err) + t.FailNow() } - return objs -} + validateReq = &ValidatePackageRequest{ + VersionPackage: strfmt.Base64(""), + } + + // validate corrupted package + validateResp, err = appOperator.ValidatePackage(validateReq) + if err == nil { + klog.Errorf("validate pacakge failed, error: %s", err) + t.FailNow() + } + + appReq := &CreateAppRequest{ + Isv: testWorkspace, + Name: "test-chart", + VersionName: "0.1.0", + VersionPackage: strfmt.Base64(chartData), + } + + // create app + createAppResp, err := appOperator.CreateApp(appReq) + if err != nil { + klog.Errorf("create app failed") + t.Fail() + } -func TestApplicationOperator_CreateApplication(t *testing.T) { - tests := []struct { - description string - existNamespaces []*v1.Namespace - targetNamespace string - createClusterRequest CreateClusterRequest - expected error - }{ - { - description: "create application test", - existNamespaces: []*v1.Namespace{{ - ObjectMeta: metav1.ObjectMeta{Name: "test", Annotations: map[string]string{openpitrix.RuntimeAnnotationKey: "runtime-ncafface"}}, - }}, - targetNamespace: "test", - createClusterRequest: CreateClusterRequest{ - Conf: "app-agwerl", - RuntimeId: "runtime-ncafface", - VersionId: "version-acklmalkds", - Username: "system", - }, - expected: nil, - }, - { - description: "create application test2", - existNamespaces: []*v1.Namespace{}, - targetNamespace: "test2", - createClusterRequest: CreateClusterRequest{ - Conf: "app-agwerl", - RuntimeId: "runtime-ncafface", - VersionId: "version-acklmalkds", - Username: "system", - }, - expected: errors.NewNotFound(schema.GroupResource{Group: "", Resource: "namespace"}, "test2"), - }, + // add app to indexer + apps, err := ksClient.ApplicationV1alpha1().HelmApplications().List(context.TODO(), metav1.ListOptions{}) + for _, app := range apps.Items { + err := fakeInformerFactory.KubeSphereSharedInformerFactory().Application().V1alpha1().HelmApplications(). + Informer().GetIndexer().Add(&app) + if err != nil { + klog.Errorf("failed to add app to indexer") + t.FailNow() + } } - ctrl := gomock.NewController(t) - defer ctrl.Finish() - - for _, test := range tests { - op := openpitrix.NewMockClient(ctrl) - objs := namespacesToRuntimeObjects(test.existNamespaces...) - k8s := fake.NewSimpleClientset(objs...) - informer := informers.NewSharedInformerFactory(k8s, 0) - stopChan := make(chan struct{}, 0) - informer.Core().V1().Namespaces().Lister() - informer.Start(stopChan) - informer.WaitForCacheSync(stopChan) - - applicationOperator := newApplicationOperator(informer, op) - - // setup expect response - // op.EXPECT().CreateCluster(gomock.Any(), gomock.Any()).Return(&pb.CreateClusterResponse{}, nil).AnyTimes() - op.EXPECT().CreateCluster(openpitrix.ContextWithUsername(test.createClusterRequest.Username), &pb.CreateClusterRequest{ - AppId: &wrappers.StringValue{Value: test.createClusterRequest.AppId}, - VersionId: &wrappers.StringValue{Value: test.createClusterRequest.VersionId}, - RuntimeId: &wrappers.StringValue{Value: test.createClusterRequest.RuntimeId}, - Conf: &wrappers.StringValue{Value: test.createClusterRequest.Conf}, - Zone: &wrappers.StringValue{Value: test.targetNamespace}, - }).Return(&pb.CreateClusterResponse{}, nil).AnyTimes() - - t.Run(test.description, func(t *testing.T) { - - err := applicationOperator.CreateApplication(test.createClusterRequest.RuntimeId, test.targetNamespace, test.createClusterRequest) - - if err != nil && err.Error() != test.expected.Error() { - t.Error(err) - } - }) + + // add app version to indexer + appvers, err := ksClient.ApplicationV1alpha1().HelmApplicationVersions().List(context.TODO(), metav1.ListOptions{}) + for _, ver := range appvers.Items { + err := fakeInformerFactory.KubeSphereSharedInformerFactory().Application().V1alpha1().HelmApplicationVersions(). + Informer().GetIndexer().Add(&ver) + if err != nil { + klog.Errorf("failed to add app version to indexer") + t.Fail() + } + } + + // describe app + app, err := appOperator.DescribeApp(createAppResp.AppID) + if err != nil { + klog.Errorf("describe app failed, err: %s", err) + t.FailNow() + } + _ = app + + cond := ¶ms.Conditions{Match: map[string]string{ + WorkspaceLabel: testWorkspace, + }} + // list apps + listApps, err := appOperator.ListApps(cond, "", false, 10, 0) + if err != nil { + klog.Errorf("list app failed") + t.FailNow() } + _ = listApps + + // describe app + describeAppVersion, err := appOperator.DescribeAppVersion(createAppResp.VersionID) + if err != nil { + klog.Errorf("describe app version failed, error: %s", err) + t.FailNow() + } + _ = describeAppVersion + + cond.Match[AppId] = createAppResp.AppID + // list app version + _, err = appOperator.ListAppVersions(cond, "", false, 10, 0) + if err != nil { + klog.Errorf("list app version failed") + t.FailNow() + } + + // get app version file + getAppVersionFilesRequest := &GetAppVersionFilesRequest{} + _, err = appOperator.GetAppVersionFiles(createAppResp.VersionID, getAppVersionFilesRequest) + + if err != nil { + klog.Errorf("get app version files failed") + t.FailNow() + } + + //delete app + err = appOperator.DeleteApp(createAppResp.AppID) + + if err == nil { + klog.Errorf("we should delete application version first") + t.FailNow() + } + + //delete app + err = appOperator.DeleteAppVersion(createAppResp.VersionID) + + if err != nil { + klog.Errorf("delete application version failed, err: %s", err) + t.FailNow() + } + +} + +var ( + ksClient versioned.Interface + k8sClient kubernetes.Interface + fakeInformerFactory informers.InformerFactory + testWorkspace = "test-workspace" +) + +func prepareAppOperator() ApplicationInterface { + ksClient = fakeks.NewSimpleClientset() + k8sClient = fakek8s.NewSimpleClientset() + fakeInformerFactory = informers.NewInformerFactories(k8sClient, ksClient, nil, nil, nil, nil) + + return newApplicationOperator(cachedReposData, fakeInformerFactory.KubeSphereSharedInformerFactory(), ksClient, fake.NewFakeS3()) } diff --git a/pkg/models/openpitrix/applicationversions.go b/pkg/models/openpitrix/applicationversions.go new file mode 100644 index 0000000000000000000000000000000000000000..e0e2bd7d9ecf3e523005da4dce30d839f8764e87 --- /dev/null +++ b/pkg/models/openpitrix/applicationversions.go @@ -0,0 +1,572 @@ +/* +Copyright 2020 The KubeSphere 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 openpitrix + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "context" + "encoding/base64" + "errors" + "fmt" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/s3" + "github.com/go-openapi/strfmt" + "io" + "io/ioutil" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/models" + "kubesphere.io/kubesphere/pkg/server/params" + "kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmrepoindex" + "kubesphere.io/kubesphere/pkg/utils/sliceutil" + "kubesphere.io/kubesphere/pkg/utils/stringutils" + "math" + "reflect" + "sigs.k8s.io/controller-runtime/pkg/client" + "sort" + "strings" +) + +func (c *applicationOperator) GetAppVersionPackage(appId, versionId string) (*GetAppVersionPackageResponse, error) { + var version *v1alpha1.HelmApplicationVersion + var err error + + version, err = c.getAppVersionByVersionIdWithData(versionId) + if err != nil { + return nil, err + } + + return &GetAppVersionPackageResponse{ + AppId: appId, + VersionId: versionId, + Package: version.Spec.Data, + }, nil +} + +// check helm package and create helm app version if not exist +func (c *applicationOperator) CreateAppVersion(request *CreateAppVersionRequest) (*CreateAppVersionResponse, error) { + if c.backingStoreClient == nil { + return nil, invalidS3Config + } + + chrt, err := helmrepoindex.LoadPackage(request.Package) + if err != nil { + klog.Errorf("load package failed, error: %s", err) + return nil, err + } + + app, err := c.appLister.Get(request.AppId) + + if err != nil { + klog.Errorf("get app %s failed, error: %s", request.AppId, err) + return nil, err + } + chartPackage := request.Package.String() + version := buildApplicationVersion(app, chrt, &chartPackage, request.Username) + version, err = c.createApplicationVersion(version) + + if err != nil { + klog.Errorf("create helm app version failed, error: %s", err) + return nil, err + } + + klog.V(4).Infof("create helm app version %s success", request.Name) + + return &CreateAppVersionResponse{ + VersionId: version.GetHelmApplicationVersionId(), + }, nil +} + +func (c *applicationOperator) DeleteAppVersion(id string) error { + appVersion, err := c.versionLister.Get(id) + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } else { + klog.Infof("get app version %s failed, error: %s", id, err) + return err + } + } + + switch appVersion.Status.State { + case v1alpha1.StateActive: + klog.Warningf("delete app version %s/%s not permitted, current state:%s", appVersion.GetWorkspace(), + appVersion.GetTrueName(), appVersion.Status.State) + return actionNotPermitted + } + + // check release + rls, err := c.rlsLister.List(labels.SelectorFromSet(map[string]string{constants.ChartApplicationVersionIdLabelKey: id})) + if err != nil && !apierrors.IsNotFound(err) { + return err + } + if len(rls) > 0 { + klog.V(4).Infof("There are releases use data from app version %s", id) + infoMap := make(map[string]string) + allString := &bytes.Buffer{} + for _, r := range rls { + info := fmt.Sprintf("%s/%s", r.GetWorkspace(), r.GetRlsNamespace()) + if _, exists := infoMap[info]; !exists { + infoMap[info] = "" + allString.WriteString(info) + if len(infoMap) > 1 { + allString.WriteString(",") + } + } + } + return fmt.Errorf("release exists: %s", allString.String()) + } + + // Delete data in storage + err = c.backingStoreClient.Delete(dataKeyInStorage(appVersion.GetWorkspace(), id)) + if err != nil { + if aerr, ok := err.(awserr.Error); ok && aerr.Code() != s3.ErrCodeNoSuchKey { + klog.Errorf("delete app version %s/%s data failed, error: %s", appVersion.GetWorkspace(), appVersion.Name, err) + return deleteDataInStorageFailed + } + } + + // delete app version in etcd + err = c.appVersionClient.Delete(context.TODO(), id, metav1.DeleteOptions{}) + + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + klog.Errorf("delete app version %s failed", err) + return err + } else { + klog.Infof("app version %s deleted", id) + } + + return nil +} + +func (c *applicationOperator) DescribeAppVersion(id string) (*AppVersion, error) { + version, err := c.versionLister.Get(id) + if err != nil { + klog.Errorf("get app version [%s] failed, error: %s", id, err) + return nil, err + } + app := convertAppVersion(version) + return app, nil +} + +func (c *applicationOperator) ModifyAppVersion(id string, request *ModifyAppVersionRequest) error { + + version, err := c.versionLister.Get(id) + if err != nil { + klog.Errorf("get app version [%s] failed, error: %s", id, err) + return err + } + + versionCopy := version.DeepCopy() + spec := &versionCopy.Spec + if request.Name != nil && *request.Name != "" { + spec.Version, spec.AppVersion = parseChartVersionName(*request.Name) + } + + if request.Description != nil && *request.Description != "" { + spec.Description = stringutils.ShortenString(*request.Description, v1alpha1.MsgLen) + } + patch := client.MergeFrom(version) + data, err := patch.Data(versionCopy) + if err != nil { + klog.Error("create patch failed", err) + return err + } + + // data == "{}", need not to patch + if len(data) == 2 { + return nil + } + + _, err = c.appVersionClient.Patch(context.TODO(), id, patch.Type(), data, metav1.PatchOptions{}) + + if err != nil { + klog.Error(err) + return err + } + return nil +} + +func (c *applicationOperator) ListAppVersions(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { + versions, err := c.getAppVersionsByAppId(conditions.Match[AppId]) + + if err != nil { + klog.Error(err) + return nil, err + } + + var status []string + if len(conditions.Match[Status]) > 0 { + status = strings.Split(conditions.Match[Status], "|") + } + versions = filterAppVersionByState(versions, status) + if reverse { + sort.Sort(sort.Reverse(AppVersions(versions))) + } else { + sort.Sort(AppVersions(versions)) + } + + items := make([]interface{}, 0, int(math.Min(float64(limit), float64(len(versions))))) + + for i, j := offset, 0; i < len(versions) && j < limit; { + items = append(items, convertAppVersion(versions[i])) + i++ + j++ + } + return &models.PageableResponse{Items: items, TotalCount: len(versions)}, nil +} + +func (c *applicationOperator) ListAppVersionReviews(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { + + var allStatus []string + if status := conditions.Match[Status]; status != "" { + allStatus = strings.Split(status, "|") + } + + appVersions, err := c.versionLister.List(labels.Everything()) + if err != nil { + klog.Error(err) + return nil, err + } + + filtered := make([]*v1alpha1.HelmApplicationVersion, 0, len(appVersions)/2) + for _, version := range appVersions { + if sliceutil.HasString(allStatus, version.Status.State) { + filtered = append(filtered, version) + } + } + + if reverse { + sort.Sort(sort.Reverse(AppVersions(filtered))) + } else { + sort.Sort(AppVersions(filtered)) + } + + items := make([]interface{}, 0, len(filtered)) + + for i, j := offset, 0; i < len(filtered) && j < limit; { + review := convertAppVersionReview(filtered[i]) + items = append(items, review) + i++ + j++ + } + + return &models.PageableResponse{Items: items, TotalCount: len(filtered)}, nil +} + +func (c *applicationOperator) ListAppVersionAudits(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { + appId := conditions.Match[AppId] + versionId := conditions.Match[VersionId] + + var versions []*v1alpha1.HelmApplicationVersion + var err error + if versionId == "" { + ls := map[string]string{ + constants.ChartApplicationIdLabelKey: appId, + } + versions, err = c.versionLister.List(labels.SelectorFromSet(ls)) + if err != nil { + klog.Errorf("get app %s failed, error: %s", appId, err) + } + } else { + version, err := c.versionLister.Get(versionId) + if err != nil { + klog.Errorf("get app version %s failed, error: %s", versionId, err) + } + versions = []*v1alpha1.HelmApplicationVersion{version} + } + + var allAudits []*AppVersionAudit + for _, item := range versions { + audits := convertAppVersionAudit(item) + allAudits = append(allAudits, audits...) + } + + sort.Sort(AppVersionAuditList(allAudits)) + + items := make([]interface{}, 0, limit) + + for i, j := offset, 0; i < len(allAudits) && j < limit; { + items = append(items, allAudits[i]) + i++ + j++ + } + + return &models.PageableResponse{Items: items, TotalCount: len(allAudits)}, nil +} + +func (c *applicationOperator) DoAppVersionAction(versionId string, request *ActionRequest) error { + var err error + t := metav1.Now() + var audit = v1alpha1.Audit{ + Message: request.Message, + Operator: request.Username, + Time: t, + } + state := v1alpha1.StateDraft + + version, err := c.versionLister.Get(versionId) + if err != nil { + klog.Errorf("get app version %s failed, error: %s", versionId, err) + return err + } + + switch request.Action { + case ActionCancel: + if version.Status.State != v1alpha1.StateSubmitted { + } + state = v1alpha1.StateDraft + audit.State = v1alpha1.StateDraft + case ActionPass: + if version.Status.State != v1alpha1.StateSubmitted { + + } + state = v1alpha1.StatePassed + audit.State = v1alpha1.StatePassed + case ActionRecover: + if version.Status.State != v1alpha1.StateSuspended { + + } + state = v1alpha1.StateActive + audit.State = v1alpha1.StateActive + case ActionReject: + if version.Status.State != v1alpha1.StateSubmitted { + // todo check status + } + state = v1alpha1.StateRejected + audit.State = v1alpha1.StateRejected + case ActionSubmit: + if version.Status.State != v1alpha1.StateDraft { + // todo check status + } + state = v1alpha1.StateSubmitted + audit.State = v1alpha1.StateSubmitted + case ActionSuspend: + if version.Status.State != v1alpha1.StateActive { + // todo check status + } + state = v1alpha1.StateSuspended + audit.State = v1alpha1.StateSuspended + case ActionRelease: + // release to app store + if version.Status.State != v1alpha1.StatePassed { + // todo check status + } + state = v1alpha1.StateActive + audit.State = v1alpha1.StateActive + default: + err = errors.New("action not support") + } + + _ = state + if err != nil { + klog.Error(err) + return err + } + + version, err = c.updateAppVersionStatus(version, state, &audit) + + if err != nil { + klog.Errorf("update app version audit [%s] failed, error: %s", versionId, err) + return err + } + + if request.Action == ActionRelease || request.Action == ActionRecover { + // if we release a new helm application version, we need update the spec in helm application copy + app, err := c.appLister.Get(version.GetHelmApplicationId()) + if err != nil { + return err + } + appInStore, err := c.appLister.Get(fmt.Sprintf("%s%s", version.GetHelmApplicationId(), v1alpha1.HelmApplicationAppStoreSuffix)) + if err != nil { + if apierrors.IsNotFound(err) { + // controller-manager will create application in app store + return nil + } + return err + } + + if !reflect.DeepEqual(&app.Spec, &appInStore.Spec) { + appCopy := appInStore.DeepCopy() + appCopy.Spec = app.Spec + patch := client.MergeFrom(appInStore) + data, _ := patch.Data(appCopy) + _, err = c.appClient.Patch(context.TODO(), appCopy.Name, patch.Type(), data, metav1.PatchOptions{}) + if err != nil { + return err + } + } + } + + return nil +} + +// Create helmApplicationVersion and helmAudit +func (c *applicationOperator) createApplicationVersion(ver *v1alpha1.HelmApplicationVersion) (*v1alpha1.HelmApplicationVersion, error) { + ls := map[string]string{ + constants.ChartApplicationIdLabelKey: ver.GetHelmApplicationId(), + } + + list, err := c.versionLister.List(labels.SelectorFromSet(ls)) + + if err != nil && !apierrors.IsNotFound(err) { + return nil, err + } + + if len(list) > 0 { + verName := ver.GetVersionName() + for _, v := range list { + if verName == v.GetVersionName() { + klog.V(2).Infof("helm application version: %s exist", verName) + return nil, appVersionItemExists + } + } + } + + // save chart data to s3 storage + _, err = base64.StdEncoding.Decode(ver.Spec.Data, ver.Spec.Data) + if err != nil { + klog.Errorf("decode error: %s", err) + return nil, err + } else { + err = c.backingStoreClient.Upload(dataKeyInStorage(ver.GetWorkspace(), ver.Name), ver.Name, bytes.NewReader(ver.Spec.Data)) + if err != nil { + klog.Errorf("upload chart for app version: %s/%s failed, error: %s", ver.GetWorkspace(), + ver.GetTrueName(), err) + return nil, uploadChartDataFailed + } else { + klog.V(4).Infof("chart data uploaded for app version: %s/%s", ver.GetWorkspace(), ver.GetTrueName()) + } + } + + // data will not save to etcd + ver.Spec.Data = nil + ver.Spec.DataKey = ver.Name + version, err := c.appVersionClient.Create(context.TODO(), ver, metav1.CreateOptions{}) + if err == nil { + klog.V(4).Infof("create helm application %s version success", version.Name) + } + + return version, err +} + +func (c *applicationOperator) updateAppVersionStatus(version *v1alpha1.HelmApplicationVersion, state string, status *v1alpha1.Audit) (*v1alpha1.HelmApplicationVersion, error) { + version.Status.State = state + + states := append([]v1alpha1.Audit{*status}, version.Status.Audit...) + if len(version.Status.Audit) >= v1alpha1.HelmRepoSyncStateLen { + // strip the last item + states = states[:v1alpha1.HelmRepoSyncStateLen:v1alpha1.HelmRepoSyncStateLen] + } + + version.Status.Audit = states + version, err := c.appVersionClient.UpdateStatus(context.TODO(), version, metav1.UpdateOptions{}) + + return version, err +} + +func (c *applicationOperator) GetAppVersionFiles(versionId string, request *GetAppVersionFilesRequest) (*GetAppVersionPackageFilesResponse, error) { + var version *v1alpha1.HelmApplicationVersion + var err error + + version, err = c.getAppVersionByVersionIdWithData(versionId) + if err != nil { + return nil, err + } + + gzReader, err := gzip.NewReader(bytes.NewReader(version.Spec.Data)) + if err != nil { + klog.Errorf("read app version %s failed, error: %s", versionId, err) + return nil, err + } + + tarReader := tar.NewReader(gzReader) + + res := &GetAppVersionPackageFilesResponse{Files: map[string]strfmt.Base64{}, VersionId: versionId} + for { + header, err := tarReader.Next() + if err == io.EOF { + break + } + + if err != nil { + klog.Errorf("ExtractTarGz: Next() failed: %s", err.Error()) + return res, err + } + + switch header.Typeflag { + case tar.TypeReg: + curData, _ := ioutil.ReadAll(tarReader) + name := strings.TrimLeft(header.Name, fmt.Sprintf("%s/", version.GetTrueName())) + res.Files[name] = curData + default: + klog.Errorf( + "ExtractTarGz: unknown type: %v in %s", + header.Typeflag, + header.Name) + } + } + return res, nil +} + +func (c *applicationOperator) getAppVersionByVersionIdWithData(versionId string) (*v1alpha1.HelmApplicationVersion, error) { + if version, exists, err := c.cachedRepos.GetAppVersionWithData(versionId); exists { + if err != nil { + return nil, err + } + return version, nil + } + + version, err := c.versionLister.Get(versionId) + if err != nil { + return nil, err + } + + data, err := c.backingStoreClient.Read(dataKeyInStorage(version.GetWorkspace(), versionId)) + if err != nil { + klog.Errorf("load chart data for app version: %s/%s failed, error : %s", version.GetTrueName(), + version.GetTrueName(), err) + return nil, downloadFileFailed + } + version.Spec.Data = data + + return version, nil +} + +func (c *applicationOperator) getAppVersionsByAppId(appId string) (ret []*v1alpha1.HelmApplicationVersion, err error) { + if ret, exists := c.cachedRepos.ListAppVersionsByAppId(appId); exists { + return ret, nil + } + + // list app version from client-go + ret, err = c.versionLister.List(labels.SelectorFromSet(map[string]string{constants.ChartApplicationIdLabelKey: appId})) + if err != nil && !apierrors.IsNotFound(err) { + klog.Error(err) + return nil, err + } + + return +} diff --git a/pkg/models/openpitrix/apps.go b/pkg/models/openpitrix/apps.go deleted file mode 100644 index 342723459c3a6c43be81f81fabc35c0cbaf332b0..0000000000000000000000000000000000000000 --- a/pkg/models/openpitrix/apps.go +++ /dev/null @@ -1,614 +0,0 @@ -/* -Copyright 2020 The KubeSphere 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 openpitrix - -import ( - "github.com/go-openapi/strfmt" - "github.com/golang/protobuf/ptypes/wrappers" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" - "k8s.io/klog" - "kubesphere.io/kubesphere/pkg/models" - "kubesphere.io/kubesphere/pkg/server/params" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" - "openpitrix.io/openpitrix/pkg/pb" - "strings" -) - -type AppTemplateInterface interface { - ListApps(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) - DescribeApp(id string) (*App, error) - DeleteApp(id string) error - CreateApp(request *CreateAppRequest) (*CreateAppResponse, error) - ModifyApp(appId string, request *ModifyAppRequest) error - DeleteAppVersion(id string) error - ModifyAppVersion(id string, request *ModifyAppVersionRequest) error - DescribeAppVersion(id string) (*AppVersion, error) - CreateAppVersion(request *CreateAppVersionRequest) (*CreateAppVersionResponse, error) - ValidatePackage(request *ValidatePackageRequest) (*ValidatePackageResponse, error) - GetAppVersionPackage(appId, versionId string) (*GetAppVersionPackageResponse, error) - DoAppAction(appId string, request *ActionRequest) error - DoAppVersionAction(versionId string, request *ActionRequest) error - GetAppVersionFiles(versionId string, request *GetAppVersionFilesRequest) (*GetAppVersionPackageFilesResponse, error) - ListAppVersionAudits(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) - ListAppVersionReviews(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) - ListAppVersions(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) -} - -type appTemplateOperator struct { - opClient openpitrix.Client -} - -func newAppTemplateOperator(opClient openpitrix.Client) AppTemplateInterface { - return &appTemplateOperator{ - opClient: opClient, - } -} - -func (c *appTemplateOperator) ListApps(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { - - describeAppsRequest := &pb.DescribeAppsRequest{} - if keyword := conditions.Match[Keyword]; keyword != "" { - describeAppsRequest.SearchWord = &wrappers.StringValue{Value: keyword} - } - if appId := conditions.Match[AppId]; appId != "" { - describeAppsRequest.AppId = strings.Split(appId, "|") - } - if isv := conditions.Match[ISV]; isv != "" { - describeAppsRequest.Isv = strings.Split(isv, "|") - } - if categoryId := conditions.Match[CategoryId]; categoryId != "" { - describeAppsRequest.CategoryId = strings.Split(categoryId, "|") - } - if repoId := conditions.Match[RepoId]; repoId != "" { - // hard code, app template in built-in repo has no repo_id attribute - if repoId == BuiltinRepoId { - describeAppsRequest.RepoId = []string{"\u0000"} - } else { - describeAppsRequest.RepoId = strings.Split(repoId, "|") - } - } - if status := conditions.Match[Status]; status != "" { - describeAppsRequest.Status = strings.Split(status, "|") - } - if orderBy != "" { - describeAppsRequest.SortKey = &wrappers.StringValue{Value: orderBy} - } - describeAppsRequest.Reverse = &wrappers.BoolValue{Value: reverse} - describeAppsRequest.Limit = uint32(limit) - describeAppsRequest.Offset = uint32(offset) - resp, err := c.opClient.DescribeApps(openpitrix.SystemContext(), describeAppsRequest) - if err != nil { - klog.Error(err) - return nil, err - } - - items := make([]interface{}, 0) - - for _, item := range resp.AppSet { - items = append(items, convertApp(item)) - } - - return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil -} - -func (c *appTemplateOperator) DescribeApp(id string) (*App, error) { - resp, err := c.opClient.DescribeApps(openpitrix.SystemContext(), &pb.DescribeAppsRequest{ - AppId: []string{id}, - Limit: 1, - }) - if err != nil { - klog.Error(err) - return nil, err - } - - var app *App - - if len(resp.AppSet) > 0 { - app = convertApp(resp.AppSet[0]) - return app, nil - } else { - err := status.New(codes.NotFound, "resource not found").Err() - klog.Error(err) - return nil, err - } -} - -func (c *appTemplateOperator) DeleteApp(id string) error { - _, err := c.opClient.DeleteApps(openpitrix.SystemContext(), &pb.DeleteAppsRequest{ - AppId: []string{id}, - }) - if err != nil { - klog.Error(err) - return err - } - return nil -} - -func (c *appTemplateOperator) CreateApp(request *CreateAppRequest) (*CreateAppResponse, error) { - createAppRequest := &pb.CreateAppRequest{ - Name: &wrappers.StringValue{Value: request.Name}, - VersionType: &wrappers.StringValue{Value: request.VersionType}, - VersionName: &wrappers.StringValue{Value: request.VersionName}, - } - if request.VersionPackage != nil { - createAppRequest.VersionPackage = &wrappers.BytesValue{Value: request.VersionPackage} - } - if request.Icon != nil { - createAppRequest.Icon = &wrappers.BytesValue{Value: request.Icon} - } - if request.Isv != "" { - createAppRequest.Isv = &wrappers.StringValue{Value: request.Isv} - } - resp, err := c.opClient.CreateApp(openpitrix.ContextWithUsername(request.Username), createAppRequest) - if err != nil { - klog.Error(err) - appTemplateCreationCounter.WithLabelValues(request.Isv, request.Name, "failed").Inc() - return nil, err - } else { - appTemplateCreationCounter.WithLabelValues(request.Isv, request.Name, "success").Inc() - } - return &CreateAppResponse{ - AppID: resp.GetAppId().GetValue(), - VersionID: resp.GetVersionId().GetValue(), - }, nil -} - -func (c *appTemplateOperator) ModifyApp(appId string, request *ModifyAppRequest) error { - // upload app attachment - if request.AttachmentContent != nil { - uploadAttachmentRequest := &pb.UploadAppAttachmentRequest{ - AppId: &wrappers.StringValue{Value: appId}, - AttachmentContent: &wrappers.BytesValue{Value: request.AttachmentContent}, - } - if request.Type != nil { - uploadAttachmentRequest.Type = pb.UploadAppAttachmentRequest_Type(pb.UploadAppAttachmentRequest_Type_value[*request.Type]) - } - if request.Sequence != nil { - uploadAttachmentRequest.Sequence = &wrappers.UInt32Value{Value: uint32(*request.Sequence)} - } - - _, err := c.opClient.UploadAppAttachment(openpitrix.SystemContext(), uploadAttachmentRequest) - - if err != nil { - klog.Error(err) - return err - } - // patch app - } else { - patchAppRequest := &pb.ModifyAppRequest{ - AppId: &wrappers.StringValue{Value: appId}, - } - - if request.Abstraction != nil { - patchAppRequest.Abstraction = &wrappers.StringValue{Value: *request.Abstraction} - } - if request.CategoryID != nil { - patchAppRequest.CategoryId = &wrappers.StringValue{Value: *request.CategoryID} - } - if request.Description != nil { - patchAppRequest.Description = &wrappers.StringValue{Value: *request.Description} - } - if request.Home != nil { - patchAppRequest.Home = &wrappers.StringValue{Value: *request.Home} - } - if request.Keywords != nil { - patchAppRequest.Keywords = &wrappers.StringValue{Value: *request.Keywords} - } - if request.Maintainers != nil { - patchAppRequest.Maintainers = &wrappers.StringValue{Value: *request.Maintainers} - } - if request.Name != nil { - patchAppRequest.Name = &wrappers.StringValue{Value: *request.Name} - } - if request.Readme != nil { - patchAppRequest.Readme = &wrappers.StringValue{Value: *request.Readme} - } - if request.Sources != nil { - patchAppRequest.Sources = &wrappers.StringValue{Value: *request.Sources} - } - if request.Tos != nil { - patchAppRequest.Tos = &wrappers.StringValue{Value: *request.Tos} - } - - _, err := c.opClient.ModifyApp(openpitrix.SystemContext(), patchAppRequest) - - if err != nil { - klog.Error(err) - return err - } - } - return nil -} - -func (c *appTemplateOperator) CreateAppVersion(request *CreateAppVersionRequest) (*CreateAppVersionResponse, error) { - createAppVersionRequest := &pb.CreateAppVersionRequest{ - AppId: &wrappers.StringValue{Value: request.AppId}, - Name: &wrappers.StringValue{Value: request.Name}, - Description: &wrappers.StringValue{Value: request.Description}, - Type: &wrappers.StringValue{Value: request.Type}, - } - - if request.Package != nil { - createAppVersionRequest.Package = &wrappers.BytesValue{Value: request.Package} - } - - resp, err := c.opClient.CreateAppVersion(openpitrix.ContextWithUsername(request.Username), createAppVersionRequest) - if err != nil { - klog.Error(err) - return nil, err - } - return &CreateAppVersionResponse{ - VersionId: resp.GetVersionId().GetValue(), - }, nil -} - -func (c *appTemplateOperator) ValidatePackage(request *ValidatePackageRequest) (*ValidatePackageResponse, error) { - r := &pb.ValidatePackageRequest{} - - if request.VersionPackage != nil { - r.VersionPackage = request.VersionPackage - } - if request.VersionType != "" { - r.VersionType = request.VersionType - } - - resp, err := c.opClient.ValidatePackage(openpitrix.SystemContext(), r) - - if err != nil { - klog.Error(err) - return nil, err - } - - result := &ValidatePackageResponse{} - - if resp.Error != nil { - result.Error = resp.Error.Value - } - if resp.Description != nil { - result.Description = resp.Description.Value - } - if resp.Error != nil { - result.Error = resp.Error.Value - } - if resp.ErrorDetails != nil { - result.ErrorDetails = resp.ErrorDetails - } - if resp.Name != nil { - result.Name = resp.Name.Value - } - if resp.Url != nil { - result.URL = resp.Url.Value - } - if resp.VersionName != nil { - result.VersionName = resp.VersionName.Value - } - return result, nil -} - -func (c *appTemplateOperator) DeleteAppVersion(id string) error { - _, err := c.opClient.DeleteAppVersion(openpitrix.SystemContext(), &pb.DeleteAppVersionRequest{ - VersionId: &wrappers.StringValue{Value: id}, - }) - if err != nil { - klog.Error(err) - return err - } - return nil -} - -func (c *appTemplateOperator) ModifyAppVersion(id string, request *ModifyAppVersionRequest) error { - modifyAppVersionRequest := &pb.ModifyAppVersionRequest{ - VersionId: &wrappers.StringValue{Value: id}, - } - - if request.Name != nil { - modifyAppVersionRequest.Name = &wrappers.StringValue{Value: *request.Name} - } - if request.Description != nil { - modifyAppVersionRequest.Description = &wrappers.StringValue{Value: *request.Description} - } - if request.Package != nil { - modifyAppVersionRequest.Package = &wrappers.BytesValue{Value: request.Package} - } - if request.PackageFiles != nil { - modifyAppVersionRequest.PackageFiles = request.PackageFiles - } - - _, err := c.opClient.ModifyAppVersion(openpitrix.SystemContext(), modifyAppVersionRequest) - if err != nil { - klog.Error(err) - return err - } - return nil -} - -func (c *appTemplateOperator) DescribeAppVersion(id string) (*AppVersion, error) { - resp, err := c.opClient.DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{ - VersionId: []string{id}, - Limit: 1, - }) - if err != nil { - klog.Error(err) - return nil, err - } - - var app *AppVersion - - if len(resp.AppVersionSet) > 0 { - app = convertAppVersion(resp.AppVersionSet[0]) - return app, nil - } else { - err := status.New(codes.NotFound, "resource not found").Err() - klog.Error(err) - return nil, err - } -} - -func (c *appTemplateOperator) GetAppVersionPackage(appId, versionId string) (*GetAppVersionPackageResponse, error) { - resp, err := c.opClient.GetAppVersionPackage(openpitrix.SystemContext(), &pb.GetAppVersionPackageRequest{ - VersionId: &wrappers.StringValue{Value: versionId}, - }) - if err != nil { - klog.Error(err) - return nil, err - } - - app := &GetAppVersionPackageResponse{ - AppId: appId, - VersionId: versionId, - } - - if resp.Package != nil { - app.Package = resp.Package - } - - return app, nil -} - -func (c *appTemplateOperator) DoAppAction(appId string, request *ActionRequest) error { - switch request.Action { - - case ActionRecover: - // TODO openpitrix need to implement app recover interface - resp, err := c.opClient.DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{ - AppId: []string{appId}, - Status: []string{StatusSuspended}, - Limit: 200, - Offset: 0, - }) - if err != nil { - klog.Error(err) - return err - } - for _, version := range resp.AppVersionSet { - - _, err = c.opClient.RecoverAppVersion(openpitrix.SystemContext(), &pb.RecoverAppVersionRequest{ - VersionId: version.VersionId, - }) - if err != nil { - klog.Error(err) - return err - } - } - - case ActionSuspend: - // TODO openpitrix need to implement app suspend interface - resp, err := c.opClient.DescribeAppVersions(openpitrix.SystemContext(), &pb.DescribeAppVersionsRequest{ - AppId: []string{appId}, - Status: []string{StatusActive}, - Limit: 200, - Offset: 0, - }) - if err != nil { - klog.Error(err) - return err - } - for _, version := range resp.AppVersionSet { - _, err = c.opClient.SuspendAppVersion(openpitrix.SystemContext(), &pb.SuspendAppVersionRequest{ - VersionId: version.VersionId, - }) - - if err != nil { - klog.Error(err) - return err - } - } - - default: - err := status.New(codes.InvalidArgument, "action not support").Err() - klog.Error(err) - return err - } - - return nil -} - -func (c *appTemplateOperator) DoAppVersionAction(versionId string, request *ActionRequest) error { - var err error - switch request.Action { - case ActionCancel: - _, err = c.opClient.CancelAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.CancelAppVersionRequest{ - VersionId: &wrappers.StringValue{Value: versionId}, - }) - case ActionPass: - _, err = c.opClient.AdminPassAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.PassAppVersionRequest{ - VersionId: &wrappers.StringValue{Value: versionId}, - }) - case ActionRecover: - _, err = c.opClient.RecoverAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.RecoverAppVersionRequest{ - VersionId: &wrappers.StringValue{Value: versionId}, - }) - case ActionReject: - _, err = c.opClient.AdminRejectAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.RejectAppVersionRequest{ - VersionId: &wrappers.StringValue{Value: versionId}, - Message: &wrappers.StringValue{Value: request.Message}, - }) - case ActionSubmit: - _, err = c.opClient.SubmitAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.SubmitAppVersionRequest{ - VersionId: &wrappers.StringValue{Value: versionId}, - }) - case ActionSuspend: - _, err = c.opClient.SuspendAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.SuspendAppVersionRequest{ - VersionId: &wrappers.StringValue{Value: versionId}, - }) - case ActionRelease: - _, err = c.opClient.ReleaseAppVersion(openpitrix.ContextWithUsername(request.Username), &pb.ReleaseAppVersionRequest{ - VersionId: &wrappers.StringValue{Value: versionId}, - }) - default: - err = status.New(codes.InvalidArgument, "action not support").Err() - } - - if err != nil { - klog.Error(err) - return err - } - - return nil -} - -func (c *appTemplateOperator) GetAppVersionFiles(versionId string, request *GetAppVersionFilesRequest) (*GetAppVersionPackageFilesResponse, error) { - getAppVersionPackageFilesRequest := &pb.GetAppVersionPackageFilesRequest{ - VersionId: &wrappers.StringValue{Value: versionId}, - } - if request.Files != nil { - getAppVersionPackageFilesRequest.Files = request.Files - } - - resp, err := c.opClient.GetAppVersionPackageFiles(openpitrix.SystemContext(), getAppVersionPackageFilesRequest) - if err != nil { - klog.Error(err) - return nil, err - } - - version := &GetAppVersionPackageFilesResponse{ - VersionId: versionId, - } - - if resp.Files != nil { - version.Files = make(map[string]strfmt.Base64) - for k, v := range resp.Files { - version.Files[k] = v - } - } - - return version, nil -} - -func (c *appTemplateOperator) ListAppVersionAudits(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { - describeAppVersionAudits := &pb.DescribeAppVersionAuditsRequest{} - - if keyword := conditions.Match[Keyword]; keyword != "" { - describeAppVersionAudits.SearchWord = &wrappers.StringValue{Value: keyword} - } - if appId := conditions.Match[AppId]; appId != "" { - describeAppVersionAudits.AppId = []string{appId} - } - if versionId := conditions.Match[VersionId]; versionId != "" { - describeAppVersionAudits.VersionId = []string{versionId} - } - if status := conditions.Match[Status]; status != "" { - describeAppVersionAudits.Status = strings.Split(status, "|") - } - if orderBy != "" { - describeAppVersionAudits.SortKey = &wrappers.StringValue{Value: orderBy} - } - describeAppVersionAudits.Reverse = &wrappers.BoolValue{Value: reverse} - describeAppVersionAudits.Limit = uint32(limit) - describeAppVersionAudits.Offset = uint32(offset) - resp, err := c.opClient.DescribeAppVersionAudits(openpitrix.SystemContext(), describeAppVersionAudits) - - if err != nil { - klog.Error(err) - return nil, err - } - - items := make([]interface{}, 0) - - for _, item := range resp.AppVersionAuditSet { - appVersion := convertAppVersionAudit(item) - items = append(items, appVersion) - } - - return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil -} - -func (c *appTemplateOperator) ListAppVersionReviews(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { - describeAppVersionReviews := &pb.DescribeAppVersionReviewsRequest{} - - if keyword := conditions.Match[Keyword]; keyword != "" { - describeAppVersionReviews.SearchWord = &wrappers.StringValue{Value: keyword} - } - if status := conditions.Match[Status]; status != "" { - describeAppVersionReviews.Status = strings.Split(status, "|") - } - if orderBy != "" { - describeAppVersionReviews.SortKey = &wrappers.StringValue{Value: orderBy} - } - describeAppVersionReviews.Reverse = &wrappers.BoolValue{Value: reverse} - describeAppVersionReviews.Limit = uint32(limit) - describeAppVersionReviews.Offset = uint32(offset) - // TODO icon is needed - resp, err := c.opClient.DescribeAppVersionReviews(openpitrix.SystemContext(), describeAppVersionReviews) - - if err != nil { - klog.Error(err) - return nil, err - } - - items := make([]interface{}, 0) - - for _, item := range resp.AppVersionReviewSet { - appVersion := convertAppVersionReview(item) - items = append(items, appVersion) - } - - return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil -} - -func (c *appTemplateOperator) ListAppVersions(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { - describeAppVersionsRequest := &pb.DescribeAppVersionsRequest{} - - if keyword := conditions.Match[Keyword]; keyword != "" { - describeAppVersionsRequest.SearchWord = &wrappers.StringValue{Value: keyword} - } - if appId := conditions.Match[AppId]; appId != "" { - describeAppVersionsRequest.AppId = []string{appId} - } - if status := conditions.Match[Status]; status != "" { - describeAppVersionsRequest.Status = strings.Split(status, "|") - } - if orderBy != "" { - describeAppVersionsRequest.SortKey = &wrappers.StringValue{Value: orderBy} - } - describeAppVersionsRequest.Reverse = &wrappers.BoolValue{Value: reverse} - describeAppVersionsRequest.Limit = uint32(limit) - describeAppVersionsRequest.Offset = uint32(offset) - resp, err := c.opClient.DescribeAppVersions(openpitrix.SystemContext(), describeAppVersionsRequest) - - if err != nil { - klog.Error(err) - return nil, err - } - - items := make([]interface{}, 0) - - for _, item := range resp.AppVersionSet { - appVersion := convertAppVersion(item) - items = append(items, appVersion) - } - - return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil -} diff --git a/pkg/models/openpitrix/attachments.go b/pkg/models/openpitrix/attachments.go index 7b77c5b24f3d6da8e0909af4101d0e7f3ea2a7c5..1a43cac221a25b45ae6e402974cc050c94a5bf0d 100644 --- a/pkg/models/openpitrix/attachments.go +++ b/pkg/models/openpitrix/attachments.go @@ -1,53 +1,82 @@ -/* -Copyright 2020 The KubeSphere 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. -*/ - +///* +//Copyright 2020 The KubeSphere 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 openpitrix import ( - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" + "bytes" + "github.com/go-openapi/strfmt" "k8s.io/klog" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" - "openpitrix.io/openpitrix/pkg/pb" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/simple/client/s3" + "kubesphere.io/kubesphere/pkg/utils/idutils" ) type AttachmentInterface interface { DescribeAttachment(id string) (*Attachment, error) + CreateAttachment(data []byte) (*Attachment, error) + DeleteAttachments(ids []string) error } type attachmentOperator struct { - opClient openpitrix.Client + backingStoreClient s3.Interface } -func newAttachmentOperator(opClient openpitrix.Client) AttachmentInterface { +func newAttachmentOperator(storeClient s3.Interface) AttachmentInterface { return &attachmentOperator{ - opClient: opClient, + backingStoreClient: storeClient, } } func (c *attachmentOperator) DescribeAttachment(id string) (*Attachment, error) { - resp, err := c.opClient.GetAttachments(openpitrix.SystemContext(), &pb.GetAttachmentsRequest{ - AttachmentId: []string{id}, - }) + data, err := c.backingStoreClient.Read(id) + if err != nil { - klog.Error(err) - return nil, err + klog.Errorf("read attachment %s failed, error: %s", id, err) + return nil, downloadFileFailed } - if len(resp.Attachments) > 0 { - return convertAttachment(resp.Attachments[id]), nil + att := &Attachment{AttachmentID: id} + + if err != nil { + return nil, err } else { - err := status.New(codes.NotFound, "resource not found").Err() - klog.Error(err) + att.AttachmentContent = map[string]strfmt.Base64{ + "raw": data, + } + } + + return att, nil +} +func (c *attachmentOperator) CreateAttachment(data []byte) (*Attachment, error) { + id := idutils.GetUuid36(v1alpha1.HelmAttachmentPrefix) + + err := c.backingStoreClient.Upload(id, id, bytes.NewBuffer(data)) + if err != nil { + klog.Errorf("upload attachment failed, err: %s", err) return nil, err } + klog.V(4).Infof("upload attachment success") + + att := &Attachment{AttachmentID: id} + return att, nil +} + +func (c *attachmentOperator) DeleteAttachments(ids []string) error { + for _, id := range ids { + err := c.backingStoreClient.Delete(id) + if err != nil { + return err + } + } + return nil } diff --git a/pkg/models/openpitrix/categories.go b/pkg/models/openpitrix/categories.go index 74992ba8fca6d8e1b9e7a7f4ccc9b8aef16bcf89..0728c03708ded44607ab377dbf384bd0ec2c9355 100644 --- a/pkg/models/openpitrix/categories.go +++ b/pkg/models/openpitrix/categories.go @@ -14,14 +14,22 @@ limitations under the License. package openpitrix import ( - "github.com/golang/protobuf/ptypes/wrappers" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" + "context" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + typed_v1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + listers_v1alpha1 "kubesphere.io/kubesphere/pkg/client/listers/application/v1alpha1" "kubesphere.io/kubesphere/pkg/models" + "kubesphere.io/kubesphere/pkg/server/errors" "kubesphere.io/kubesphere/pkg/server/params" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" - "openpitrix.io/openpitrix/pkg/pb" + "kubesphere.io/kubesphere/pkg/utils/idutils" + "sigs.k8s.io/controller-runtime/pkg/client" + "sort" ) type CategoryInterface interface { @@ -33,39 +41,85 @@ type CategoryInterface interface { } type categoryOperator struct { - opClient openpitrix.Client + ctgClient typed_v1alpha1.ApplicationV1alpha1Interface + ctgLister listers_v1alpha1.HelmCategoryLister } -func newCategoryOperator(opClient openpitrix.Client) CategoryInterface { - return &categoryOperator{ - opClient: opClient, +func newCategoryOperator(ksFactory externalversions.SharedInformerFactory, ksClient versioned.Interface) CategoryInterface { + c := &categoryOperator{ + ctgClient: ksClient.ApplicationV1alpha1(), + ctgLister: ksFactory.Application().V1alpha1().HelmCategories().Lister(), } + + return c +} + +func (c *categoryOperator) getCategoryByName(name string) (*v1alpha1.HelmCategory, error) { + ctgs, err := c.ctgLister.List(labels.Everything()) + if err != nil { + return nil, err + } + for _, ctg := range ctgs { + if name == ctg.Spec.Name { + return ctg, nil + } + } + return nil, nil +} + +func (c *categoryOperator) createCategory(name, desc string) (*v1alpha1.HelmCategory, error) { + ctg := &v1alpha1.HelmCategory{ + ObjectMeta: metav1.ObjectMeta{ + Name: idutils.GetUuid36(v1alpha1.HelmCategoryIdPrefix), + }, + Spec: v1alpha1.HelmCategorySpec{ + Description: desc, + Name: name, + }, + } + + return c.ctgClient.HelmCategories().Create(context.TODO(), ctg, metav1.CreateOptions{}) } func (c *categoryOperator) CreateCategory(request *CreateCategoryRequest) (*CreateCategoryResponse, error) { - r := &pb.CreateCategoryRequest{ - Name: &wrappers.StringValue{Value: request.Name}, - Locale: &wrappers.StringValue{Value: request.Locale}, - Description: &wrappers.StringValue{Value: request.Description}, + + ctg, err := c.getCategoryByName(request.Name) + if err != nil { + return nil, err } - if request.Icon != nil { - r.Icon = &wrappers.BytesValue{Value: request.Icon} + + if ctg != nil { + return nil, errors.New("category %s exists", ctg.Spec.Name) } - resp, err := c.opClient.CreateCategory(openpitrix.SystemContext(), r) + ctg, err = c.createCategory(request.Name, request.Description) + if err != nil { klog.Error(err) return nil, err } + return &CreateCategoryResponse{ - CategoryId: resp.GetCategoryId().GetValue(), + CategoryId: ctg.Name, }, nil } func (c *categoryOperator) DeleteCategory(id string) error { - _, err := c.opClient.DeleteCategories(openpitrix.SystemContext(), &pb.DeleteCategoriesRequest{ - CategoryId: []string{id}, - }) + ctg, err := c.ctgClient.HelmCategories().Get(context.TODO(), id, metav1.GetOptions{}) + + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + return err + } + + if ctg.Status.Total > 0 { + return errors.New("category %s owns application", ctg.Spec.Name) + } + + err = c.ctgClient.HelmCategories().Delete(context.TODO(), id, metav1.DeleteOptions{}) + if err != nil { klog.Error(err) return err @@ -74,23 +128,30 @@ func (c *categoryOperator) DeleteCategory(id string) error { } func (c *categoryOperator) ModifyCategory(id string, request *ModifyCategoryRequest) error { - modifyCategoryRequest := &pb.ModifyCategoryRequest{ - CategoryId: &wrappers.StringValue{Value: id}, + + ctg, err := c.ctgClient.HelmCategories().Get(context.TODO(), id, metav1.GetOptions{}) + if err != nil { + return errors.New("category %s not found", id) } + ctgCopy := ctg.DeepCopy() + if request.Name != nil { - modifyCategoryRequest.Name = &wrappers.StringValue{Value: *request.Name} - } - if request.Locale != nil { - modifyCategoryRequest.Locale = &wrappers.StringValue{Value: *request.Locale} + ctgCopy.Spec.Name = *request.Name } + if request.Description != nil { - modifyCategoryRequest.Description = &wrappers.StringValue{Value: *request.Description} + ctgCopy.Spec.Description = *request.Description } - if request.Icon != nil { - modifyCategoryRequest.Icon = &wrappers.BytesValue{Value: request.Icon} + + patch := client.MergeFrom(ctg) + data, err := patch.Data(ctgCopy) + if err != nil { + klog.Error("create patch failed", err) + return err } - _, err := c.opClient.ModifyCategory(openpitrix.SystemContext(), modifyCategoryRequest) + _, err = c.ctgClient.HelmCategories().Patch(context.TODO(), id, patch.Type(), data, metav1.PatchOptions{}) + if err != nil { klog.Error(err) return err @@ -99,50 +160,33 @@ func (c *categoryOperator) ModifyCategory(id string, request *ModifyCategoryRequ } func (c *categoryOperator) DescribeCategory(id string) (*Category, error) { - resp, err := c.opClient.DescribeCategories(openpitrix.SystemContext(), &pb.DescribeCategoriesRequest{ - CategoryId: []string{id}, - Limit: 1, - }) + var err error + ctg := &v1alpha1.HelmCategory{} + ctg, err = c.ctgClient.HelmCategories().Get(context.TODO(), id, metav1.GetOptions{}) if err != nil { klog.Error(err) return nil, err } - var category *Category - - if len(resp.CategorySet) > 0 { - category = convertCategory(resp.CategorySet[0]) - return category, nil - } else { - err := status.New(codes.NotFound, "resource not found").Err() - klog.Error(err) - return nil, err - } + return convertCategory(ctg), nil } func (c *categoryOperator) ListCategories(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { - req := &pb.DescribeCategoriesRequest{} - if keyword := conditions.Match[Keyword]; keyword != "" { - req.SearchWord = &wrappers.StringValue{Value: keyword} - } - if orderBy != "" { - req.SortKey = &wrappers.StringValue{Value: orderBy} - } - req.Reverse = &wrappers.BoolValue{Value: reverse} - req.Limit = uint32(limit) - req.Offset = uint32(offset) - resp, err := c.opClient.DescribeCategories(openpitrix.SystemContext(), req) + ctgs, err := c.ctgLister.List(labels.Everything()) + if err != nil { - klog.Error(err) return nil, err } - items := make([]interface{}, 0) + sort.Sort(HelmCategoryList(ctgs)) - for _, item := range resp.CategorySet { - items = append(items, convertCategory(item)) + items := make([]interface{}, 0, limit) + for i, j := offset, 0; i < len(ctgs) && j < limit; { + items = append(items, convertCategory(ctgs[i])) + i++ + j++ } - return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil + return &models.PageableResponse{Items: items, TotalCount: len(ctgs)}, nil } diff --git a/pkg/models/openpitrix/category_test.go b/pkg/models/openpitrix/category_test.go new file mode 100644 index 0000000000000000000000000000000000000000..0a0a46abf0c36fa258f521534cc938f9b65685f8 --- /dev/null +++ b/pkg/models/openpitrix/category_test.go @@ -0,0 +1,84 @@ +/* +Copyright 2020 The KubeSphere 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 openpitrix + +import ( + "context" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + fakek8s "k8s.io/client-go/kubernetes/fake" + "k8s.io/klog" + fakeks "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake" + "kubesphere.io/kubesphere/pkg/informers" + "kubesphere.io/kubesphere/pkg/server/params" + "testing" +) + +func TestOpenPitrixCategory(t *testing.T) { + ctgOperator := prepareCategoryOperator() + + ctgReq := &CreateCategoryRequest{ + Name: "test-ctg", + } + + // create category + ctgResp, err := ctgOperator.CreateCategory(ctgReq) + if err != nil { + klog.Errorf("create category failed") + t.Fail() + } + + // add category to indexer + ctgs, err := ksClient.ApplicationV1alpha1().HelmCategories().List(context.TODO(), metav1.ListOptions{}) + for _, ctg := range ctgs.Items { + err := fakeInformerFactory.KubeSphereSharedInformerFactory().Application().V1alpha1().HelmCategories(). + Informer().GetIndexer().Add(&ctg) + if err != nil { + klog.Errorf("failed to add category to indexer") + t.FailNow() + } + } + + // describe category + cond := ¶ms.Conditions{} + ctgList, err := ctgOperator.ListCategories(cond, "", false, 10, 0) + if err != nil { + klog.Errorf("list app failed, err: %s", err) + t.FailNow() + } + + if len(ctgList.Items) != 1 { + klog.Errorf("list app failed") + t.FailNow() + } + + // describe category + ctg, err := ctgOperator.DescribeCategory(ctgResp.CategoryId) + if err != nil { + klog.Errorf("describe app failed, err: %s", err) + t.FailNow() + } + _ = ctg + +} + +func prepareCategoryOperator() CategoryInterface { + ksClient = fakeks.NewSimpleClientset() + k8sClient = fakek8s.NewSimpleClientset() + fakeInformerFactory = informers.NewInformerFactories(k8sClient, ksClient, nil, nil, nil, nil) + + return newCategoryOperator(fakeInformerFactory.KubeSphereSharedInformerFactory(), ksClient) +} diff --git a/pkg/models/openpitrix/errors.go b/pkg/models/openpitrix/errors.go new file mode 100644 index 0000000000000000000000000000000000000000..1c42f3eb671b608b3775379510bb06c129aca164 --- /dev/null +++ b/pkg/models/openpitrix/errors.go @@ -0,0 +1,35 @@ +/* +Copyright 2020 The KubeSphere 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 openpitrix + +import "errors" + +var ( + uploadChartDataFailed = errors.New("upload chart data failed") + invalidS3Config = errors.New("invalid storage config") + deleteDataInStorageFailed = errors.New("delete data in storage failed") + repoItemExists = errors.New("repo exists") + appItemExists = errors.New("application exists") + appVersionItemExists = errors.New("application version exists") + actionNotSupport = errors.New("action not support") + actionNotPermitted = errors.New("action not permitted") + + loadRepoInfoFailed = errors.New("load repo info failed") + downloadFileFailed = errors.New("download file failed") + readFileFailed = errors.New("read file failed") + releaseExists = errors.New("release exists") +) diff --git a/pkg/models/openpitrix/interface.go b/pkg/models/openpitrix/interface.go index 174637838923fb5b9dba35d820ee08fbc4586e51..53d23b940c6de948e9aaaaef7dfd26603ec3ae61 100644 --- a/pkg/models/openpitrix/interface.go +++ b/pkg/models/openpitrix/interface.go @@ -1,9 +1,12 @@ /* Copyright 2020 The KubeSphere 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. @@ -14,35 +17,70 @@ limitations under the License. package openpitrix import ( - "k8s.io/client-go/informers" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" + "k8s.io/apimachinery/pkg/util/wait" + "k8s.io/client-go/tools/cache" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + ks_informers "kubesphere.io/kubesphere/pkg/informers" + "kubesphere.io/kubesphere/pkg/simple/client/s3" + "kubesphere.io/kubesphere/pkg/utils/reposcache" + "sync" ) type Interface interface { - ApplicationInterface - AppTemplateInterface AttachmentInterface - CategoryInterface + ApplicationInterface RepoInterface + ReleaseInterface + CategoryInterface } + type openpitrixOperator struct { - ApplicationInterface - AppTemplateInterface AttachmentInterface - CategoryInterface + ApplicationInterface RepoInterface + ReleaseInterface + CategoryInterface } -func NewOpenpitrixOperator(informers informers.SharedInformerFactory, opClient openpitrix.Client) Interface { - if opClient == nil { - return nil - } +var cachedReposData reposcache.ReposCache +var helmReposInformer cache.SharedIndexInformer +var once sync.Once + +func init() { + cachedReposData = reposcache.NewReposCache() +} + +func NewOpenpitrixOperator(ksInformers ks_informers.InformerFactory, ksClient versioned.Interface, s3Client s3.Interface) Interface { + + once.Do(func() { + klog.Infof("start helm repo informer") + helmReposInformer = ksInformers.KubeSphereSharedInformerFactory().Application().V1alpha1().HelmRepos().Informer() + helmReposInformer.AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + r := obj.(*v1alpha1.HelmRepo) + cachedReposData.AddRepo(r) + }, + UpdateFunc: func(oldObj, newObj interface{}) { + oldR := oldObj.(*v1alpha1.HelmRepo) + cachedReposData.DeleteRepo(oldR) + r := newObj.(*v1alpha1.HelmRepo) + cachedReposData.AddRepo(r) + }, + DeleteFunc: func(obj interface{}) { + r := obj.(*v1alpha1.HelmRepo) + cachedReposData.DeleteRepo(r) + }, + }) + go helmReposInformer.Run(wait.NeverStop) + }) return &openpitrixOperator{ - ApplicationInterface: newApplicationOperator(informers, opClient), - AppTemplateInterface: newAppTemplateOperator(opClient), - AttachmentInterface: newAttachmentOperator(opClient), - CategoryInterface: newCategoryOperator(opClient), - RepoInterface: newRepoOperator(opClient), + AttachmentInterface: newAttachmentOperator(s3Client), + ApplicationInterface: newApplicationOperator(cachedReposData, ksInformers.KubeSphereSharedInformerFactory(), ksClient, s3Client), + RepoInterface: newRepoOperator(cachedReposData, ksInformers.KubeSphereSharedInformerFactory(), ksClient), + ReleaseInterface: newReleaseOperator(cachedReposData, ksInformers.KubernetesSharedInformerFactory(), ksInformers.KubeSphereSharedInformerFactory(), ksClient), + CategoryInterface: newCategoryOperator(ksInformers.KubeSphereSharedInformerFactory(), ksClient), } } diff --git a/pkg/models/openpitrix/metric.go b/pkg/models/openpitrix/metric.go index 794668f09e31c52d14dab4c1ab490df7ccaa47a9..506d520114b56154f6de90434147727a879b5bfa 100644 --- a/pkg/models/openpitrix/metric.go +++ b/pkg/models/openpitrix/metric.go @@ -1,3 +1,19 @@ +/* +Copyright 2020 The KubeSphere 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 openpitrix import ( diff --git a/pkg/models/openpitrix/release.go b/pkg/models/openpitrix/release.go new file mode 100644 index 0000000000000000000000000000000000000000..491cc9b74f0ffe88709f4236eb3f672feb63e34b --- /dev/null +++ b/pkg/models/openpitrix/release.go @@ -0,0 +1,417 @@ +/* +Copyright 2020 The KubeSphere 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 openpitrix + +import ( + "bytes" + "context" + "errors" + "fmt" + "github.com/go-openapi/strfmt" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/client-go/informers" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + typed_v1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + listers_v1alpha1 "kubesphere.io/kubesphere/pkg/client/listers/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/models" + "kubesphere.io/kubesphere/pkg/server/params" + "kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmwrapper" + "kubesphere.io/kubesphere/pkg/utils/clusterclient" + "kubesphere.io/kubesphere/pkg/utils/idutils" + "kubesphere.io/kubesphere/pkg/utils/reposcache" + "kubesphere.io/kubesphere/pkg/utils/resourceparse" + "kubesphere.io/kubesphere/pkg/utils/stringutils" + "math" + "sigs.k8s.io/controller-runtime/pkg/client" + "sort" + "strings" +) + +type ReleaseInterface interface { + ListApplications(workspace, clusterName, namespace string, conditions *params.Conditions, limit, offset int, orderBy string, reverse bool) (*models.PageableResponse, error) + DescribeApplication(workspace, clusterName, namespace, applicationId string) (*Application, error) + CreateApplication(workspace, clusterName, namespace string, request CreateClusterRequest) error + ModifyApplication(request ModifyClusterAttributesRequest) error + DeleteApplication(workspace, clusterName, namespace, id string) error + UpgradeApplication(request UpgradeClusterRequest) error +} + +type releaseOperator struct { + informers informers.SharedInformerFactory + rlsClient typed_v1alpha1.HelmReleaseInterface + rlsLister listers_v1alpha1.HelmReleaseLister + appVersionLister listers_v1alpha1.HelmApplicationVersionLister + cachedRepos reposcache.ReposCache + clusterClients clusterclient.ClusterClients +} + +func newReleaseOperator(cached reposcache.ReposCache, k8sFactory informers.SharedInformerFactory, ksFactory externalversions.SharedInformerFactory, ksClient versioned.Interface) ReleaseInterface { + c := &releaseOperator{ + informers: k8sFactory, + rlsClient: ksClient.ApplicationV1alpha1().HelmReleases(), + rlsLister: ksFactory.Application().V1alpha1().HelmReleases().Lister(), + cachedRepos: cached, + clusterClients: clusterclient.NewClusterClient(ksFactory.Cluster().V1alpha1().Clusters()), + appVersionLister: ksFactory.Application().V1alpha1().HelmApplicationVersions().Lister(), + } + + return c +} + +type Application struct { + Name string `json:"name" description:"application name"` + Cluster *Cluster `json:"cluster,omitempty" description:"application cluster info"` + Version *AppVersion `json:"version,omitempty" description:"application template version info"` + App *App `json:"app,omitempty" description:"application template info"` + + ReleaseInfo []runtime.Object `json:"releaseInfo,omitempty" description:"release info"` +} + +func (c *releaseOperator) UpgradeApplication(request UpgradeClusterRequest) error { + oldRls, err := c.rlsLister.Get(request.ClusterId) + + // todo check namespace + if err != nil { + klog.Errorf("get release %s/%s failed, error: %s", request.Namespace, request.ClusterId, err) + return err + } + + if oldRls.Status.State != v1alpha1.HelmStatusActive { + return errors.New("application is not active now") + } + + version, err := c.getAppVersion("", request.VersionId) + if err != nil { + klog.Errorf("get helm application version %s/%s failed, error: %s", request.AppId, request.VersionId, err) + return err + } + + newRls := oldRls.DeepCopy() + newRls.Spec.ApplicationId = request.AppId + newRls.Spec.ApplicationVersionId = request.VersionId + + newRls.Spec.Version += 1 + newRls.Spec.RepoId = version.GetHelmRepoId() + newRls.Spec.ChartVersion = version.GetChartVersion() + newRls.Spec.ChartAppVersion = version.GetChartAppVersion() + // Use the new conf if the client has one, or server will just use the old conf. + if request.Conf != "" { + newRls.Spec.Values = strfmt.Base64(request.Conf) + } + + patch := client.MergeFrom(oldRls) + data, err := patch.Data(newRls) + + newRls, err = c.rlsClient.Patch(context.TODO(), request.ClusterId, patch.Type(), data, metav1.PatchOptions{}) + if err != nil { + klog.Errorf("patch release %s/%s failed, error: %s", request.Namespace, request.ClusterId, err) + return err + } else { + klog.V(2).Infof("patch release %s/%s success", request.Namespace, request.ClusterId) + } + + return nil +} + +// create all helm release in host cluster +func (c *releaseOperator) CreateApplication(workspace, clusterName, namespace string, request CreateClusterRequest) error { + version, err := c.getAppVersion("", request.VersionId) + + if err != nil { + klog.Errorf("get helm application version %s failed, error: %v", request.Name, err) + return err + } + + exists, err := c.releaseExists(workspace, clusterName, namespace, request.Name) + + if err != nil && !apierrors.IsNotFound(err) { + klog.Errorf("get helm release %s failed, error: %v", request.Name, err) + return err + } + + if exists { + err = fmt.Errorf("release %s exists", request.Name) + klog.Error(err) + return err + } + + rls := &v1alpha1.HelmRelease{ + ObjectMeta: metav1.ObjectMeta{ + Name: idutils.GetUuid36(v1alpha1.HelmReleasePrefix), + Annotations: map[string]string{ + constants.CreatorAnnotationKey: request.Username, + }, + Labels: map[string]string{ + constants.ChartApplicationVersionIdLabelKey: request.VersionId, + constants.ChartApplicationIdLabelKey: strings.TrimSuffix(request.AppId, v1alpha1.HelmApplicationAppStoreSuffix), + constants.WorkspaceLabelKey: request.Workspace, + constants.NamespaceLabelKey: namespace, + }, + }, + Spec: v1alpha1.HelmReleaseSpec{ + Name: request.Name, + Version: 1, + Values: strfmt.Base64(request.Conf), + ApplicationId: strings.TrimSuffix(request.AppId, v1alpha1.HelmApplicationAppStoreSuffix), + ApplicationVersionId: request.VersionId, + ChartName: version.GetTrueName(), + RepoId: version.GetHelmRepoId(), + ChartVersion: version.GetChartVersion(), + ChartAppVersion: version.GetChartAppVersion(), + }, + } + + if clusterName != "" { + rls.Labels[constants.ClusterNameLabelKey] = clusterName + } + + if repoId := version.GetHelmRepoId(); repoId != "" { + rls.Labels[constants.ChartRepoIdLabelKey] = repoId + } + + rls, err = c.rlsClient.Create(context.TODO(), rls, metav1.CreateOptions{}) + + if err != nil { + klog.Errorln(err) + return err + } else { + klog.Infof("create helm release %s success in %s", request.Name, namespace) + } + + return nil +} + +func (c *releaseOperator) releaseExists(workspace, clusterName, namespace, name string) (bool, error) { + set := map[string]string{ + constants.WorkspaceLabelKey: workspace, + constants.NamespaceLabelKey: namespace, + } + if clusterName != "" { + set[constants.ClusterNameLabelKey] = clusterName + } + + list, err := c.rlsLister.List(labels.SelectorFromSet(set)) + if err != nil { + return false, err + } + for _, rls := range list { + if rls.Spec.Name == name { + return true, nil + } + } + return false, nil +} + +func (c *releaseOperator) ModifyApplication(request ModifyClusterAttributesRequest) error { + + if request.Description == nil || len(*request.Description) == 0 { + return nil + } + + rls, err := c.rlsLister.Get(request.ClusterID) + if err != nil { + klog.Errorf("get release failed, error: %s", err) + return err + } + + rlsCopy := rls.DeepCopy() + rlsCopy.Spec.Description = stringutils.ShortenString(strings.TrimSpace(*request.Description), v1alpha1.MsgLen) + + pt := client.MergeFrom(rls) + + data, err := pt.Data(rlsCopy) + if err != nil { + klog.Errorf("create patch failed, error: %s", err) + return err + } + + _, err = c.rlsClient.Patch(context.TODO(), request.ClusterID, pt.Type(), data, metav1.PatchOptions{}) + if err != nil { + klog.Errorln(err) + return err + } + + return nil +} + +func (c *releaseOperator) ListApplications(workspace, clusterName, namespace string, conditions *params.Conditions, limit, offset int, orderBy string, reverse bool) (*models.PageableResponse, error) { + appId := conditions.Match[AppId] + versionId := conditions.Match[VersionId] + ls := map[string]string{} + if appId != "" { + ls[constants.ChartApplicationIdLabelKey] = strings.TrimSuffix(appId, v1alpha1.HelmApplicationAppStoreSuffix) + } + + if versionId != "" { + ls[constants.ChartApplicationVersionIdLabelKey] = versionId + } + + if workspace != "" { + ls[constants.WorkspaceLabelKey] = workspace + } + if namespace != "" { + ls[constants.NamespaceLabelKey] = namespace + } + if clusterName != "" { + ls[constants.ClusterNameLabelKey] = clusterName + } + + releases, err := c.rlsLister.List(labels.SelectorFromSet(ls)) + if err != nil && !apierrors.IsNotFound(err) { + klog.Errorf("list app release failed, error: %v", err) + return nil, err + } + + releases = filterReleases(releases, conditions) + + // only show release whose app versions are active or suspended + if versionId == "" && strings.HasSuffix(appId, v1alpha1.HelmApplicationAppStoreSuffix) { + stripId := strings.TrimSuffix(appId, v1alpha1.HelmApplicationAppStoreSuffix) + versions, err := c.appVersionLister.List(labels.SelectorFromSet(map[string]string{constants.ChartApplicationIdLabelKey: stripId})) + if err != nil { + klog.Errorf("list app version failed, error: %s", err) + return nil, err + } + versions = filterAppVersionByState(versions, []string{v1alpha1.StateActive, v1alpha1.StateSuspended}) + versionMap := make(map[string]*v1alpha1.HelmApplicationVersion) + for _, version := range versions { + versionMap[version.Name] = version + } + releases = filterReleasesWithAppVersions(releases, versionMap) + } + + if reverse { + sort.Sort(sort.Reverse(HelmReleaseList(releases))) + } else { + sort.Sort(HelmReleaseList(releases)) + } + + result := models.PageableResponse{TotalCount: len(releases)} + result.Items = make([]interface{}, 0, int(math.Min(float64(limit), float64(len(releases))))) + + for i, j := offset, 0; i < len(releases) && j < limit; { + app := convertApplication(releases[i], nil) + result.Items = append(result.Items, app) + i++ + j++ + } + + return &result, nil +} + +func (c *releaseOperator) DescribeApplication(workspace, clusterName, namespace, applicationId string) (*Application, error) { + + rls, err := c.rlsLister.Get(applicationId) + + if err != nil && !apierrors.IsNotFound(err) { + klog.Errorf("list helm release failed, error: %v", err) + return nil, err + } + + app := &Application{} + if rls != nil && rls.GetRlsCluster() != "" { + // TODO check clusterName, workspace, namespace + clusterConfig, err := c.clusterClients.GetClusterKubeconfig(rls.GetRlsCluster()) + if err != nil { + klog.Errorf("get cluster config failed, error: %s", err) + return nil, err + } + // If clusterConfig is empty, this application will be installed in current host. + hw := helmwrapper.NewHelmWrapper(clusterConfig, namespace, rls.Spec.Name) + manifest, err := hw.Manifest() + if err != nil { + klog.Errorf("get manifest failed, error: %s", err) + } + infos, err := resourceparse.Parse(bytes.NewBufferString(manifest), namespace, rls.Spec.Name, true) + if err != nil { + klog.Errorf("parse resource failed, error: %s", err) + } + app = convertApplication(rls, infos) + } + + return app, nil +} + +func (c *releaseOperator) DeleteApplication(workspace, clusterName, namespace, id string) error { + + rls, err := c.rlsLister.Get(id) + if err != nil { + if apierrors.IsNotFound(err) { + return nil + } + klog.Errorf("get release %s/%s failed, err: %s", namespace, id, err) + return err + } + + // TODO, check workspace, cluster and namespace + if rls.GetWorkspace() != workspace || rls.GetRlsCluster() != clusterName || rls.GetRlsNamespace() != namespace { + } + + err = c.rlsClient.Delete(context.TODO(), id, metav1.DeleteOptions{}) + + if err != nil { + klog.Errorf("delete release %s/%s failed, error: %s", namespace, id, err) + return err + } else { + klog.V(2).Infof("delete release %s/%s", namespace, id) + } + + return nil +} + +// get app version from repo and helm application +func (c *releaseOperator) getAppVersion(repoId, id string) (ret *v1alpha1.HelmApplicationVersion, err error) { + if ver, exists, _ := c.cachedRepos.GetAppVersion(id); exists { + return ver, nil + } + + if repoId != "" && repoId != v1alpha1.AppStoreRepoId { + return nil, fmt.Errorf("app version not found") + } + ret, err = c.appVersionLister.Get(id) + + if err != nil && !apierrors.IsNotFound(err) { + klog.Error(err) + return nil, err + } + return +} + +// get app version from repo and helm application +func (c *releaseOperator) getAppVersionWithData(repoId, id string) (ret *v1alpha1.HelmApplicationVersion, err error) { + if ver, exists, _ := c.cachedRepos.GetAppVersionWithData(id); exists { + return ver, nil + } + + if repoId != "" && repoId != v1alpha1.AppStoreRepoId { + return nil, fmt.Errorf("not found") + } + ret, err = c.appVersionLister.Get(id) + + if err != nil && !apierrors.IsNotFound(err) { + klog.Error(err) + return nil, err + } + return +} diff --git a/pkg/models/openpitrix/release_test.go b/pkg/models/openpitrix/release_test.go new file mode 100644 index 0000000000000000000000000000000000000000..7bc7e3f5b7d8a928a3d5169f5878ea5361ebed1c --- /dev/null +++ b/pkg/models/openpitrix/release_test.go @@ -0,0 +1,127 @@ +/* +Copyright 2020 The KubeSphere 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 openpitrix + +import ( + "context" + "encoding/base64" + "github.com/go-openapi/strfmt" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/server/params" + "testing" +) + +func TestOpenPitrixRelease(t *testing.T) { + appOperator := prepareAppOperator() + + chartData, _ := base64.RawStdEncoding.DecodeString(rawChartData) + + appReq := &CreateAppRequest{ + Isv: testWorkspace, + Name: "test-chart", + VersionName: "0.1.0", + VersionPackage: strfmt.Base64(chartData), + } + + // create app + createAppResp, err := appOperator.CreateApp(appReq) + if err != nil { + klog.Errorf("create app failed") + t.Fail() + } + + // add app to indexer + apps, err := ksClient.ApplicationV1alpha1().HelmApplications().List(context.TODO(), metav1.ListOptions{}) + for _, app := range apps.Items { + err := fakeInformerFactory.KubeSphereSharedInformerFactory().Application().V1alpha1().HelmApplications(). + Informer().GetIndexer().Add(&app) + if err != nil { + klog.Errorf("failed to add app to indexer") + t.FailNow() + } + } + + // add app version to indexer + appvers, err := ksClient.ApplicationV1alpha1().HelmApplicationVersions().List(context.TODO(), metav1.ListOptions{}) + for _, ver := range appvers.Items { + err := fakeInformerFactory.KubeSphereSharedInformerFactory().Application().V1alpha1().HelmApplicationVersions(). + Informer().GetIndexer().Add(&ver) + if err != nil { + klog.Errorf("failed to add app version to indexer") + t.Fail() + } + } + + rlsOperator := newReleaseOperator(cachedReposData, fakeInformerFactory.KubernetesSharedInformerFactory(), fakeInformerFactory.KubeSphereSharedInformerFactory(), ksClient) + + req := CreateClusterRequest{ + Name: "test-rls", + AppId: createAppResp.AppID, + VersionId: createAppResp.VersionID, + Workspace: testWorkspace, + } + err = rlsOperator.CreateApplication(testWorkspace, "", "default", req) + + if err != nil { + klog.Errorf("create release failed, error: %s", err) + t.FailNow() + } + + // add app version to indexer + rls, err := ksClient.ApplicationV1alpha1().HelmReleases().List(context.TODO(), metav1.ListOptions{}) + for _, item := range rls.Items { + err := fakeInformerFactory.KubeSphereSharedInformerFactory().Application().V1alpha1().HelmReleases(). + Informer().GetIndexer().Add(&item) + if err != nil { + klog.Errorf("failed to add release to indexer") + t.FailNow() + } + } + + cond := ¶ms.Conditions{Match: map[string]string{ + WorkspaceLabel: testWorkspace, + }} + rlsList, err := rlsOperator.ListApplications(testWorkspace, "", "default", cond, 10, 0, "", false) + + if err != nil { + klog.Errorf("failed to list release, error: %s", err) + t.FailNow() + } + + var rlsId string + for _, item := range rlsList.Items { + app := item.(*Application) + rlsId = app.Cluster.ClusterId + break + } + + //describe release + describeRls, err := rlsOperator.DescribeApplication(testWorkspace, "", "default", rlsId) + if err != nil { + klog.Errorf("failed to describe release, error: %s", err) + t.FailNow() + } + _ = describeRls + + //delete release + err = rlsOperator.DeleteApplication(testWorkspace, "", "default", rlsId) + if err != nil { + klog.Errorf("failed to delete release, error: %s", err) + t.FailNow() + } +} diff --git a/pkg/models/openpitrix/repo_test.go b/pkg/models/openpitrix/repo_test.go new file mode 100644 index 0000000000000000000000000000000000000000..0720431b80220c51afba2fdee657cdf8fd0f3632 --- /dev/null +++ b/pkg/models/openpitrix/repo_test.go @@ -0,0 +1,112 @@ +/* +Copyright 2020 The KubeSphere 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 openpitrix + +import ( + "context" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + fakek8s "k8s.io/client-go/kubernetes/fake" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + fakeks "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/informers" + "kubesphere.io/kubesphere/pkg/server/params" + "kubesphere.io/kubesphere/pkg/utils/idutils" + "testing" +) + +func TestOpenPitrixRepo(t *testing.T) { + repoOperator := prepareRepoOperator() + + repo := v1alpha1.HelmRepo{ + ObjectMeta: metav1.ObjectMeta{ + Name: idutils.GetUuid36(v1alpha1.HelmRepoIdPrefix), + + Labels: map[string]string{ + constants.WorkspaceLabelKey: testWorkspace, + }, + }, + Spec: v1alpha1.HelmRepoSpec{ + Name: "test-repo", + Url: "https://charts.kubesphere.io/main", + SyncPeriod: 0, + }, + } + + // validate repo + validateRes, err := repoOperator.ValidateRepo(repo.Spec.Url, &repo.Spec.Credential) + if err != nil || validateRes.Ok == false { + klog.Errorf("validate category failed, error: %s", err) + t.Fail() + } + + // validate the corrupt repo + validateRes, err = repoOperator.ValidateRepo("http://www.baidu.com", &repo.Spec.Credential) + if err == nil { + klog.Errorf("validate category failed") + t.Fail() + } + + // create repo + repoResp, err := repoOperator.CreateRepo(&repo) + if err != nil { + klog.Errorf("create category failed") + t.Fail() + } + + // add category to indexer + repos, err := ksClient.ApplicationV1alpha1().HelmRepos().List(context.TODO(), metav1.ListOptions{}) + for _, repo := range repos.Items { + err := fakeInformerFactory.KubeSphereSharedInformerFactory().Application().V1alpha1().HelmRepos(). + Informer().GetIndexer().Add(&repo) + if err != nil { + klog.Errorf("failed to add repo to indexer") + t.FailNow() + } + } + + // list repo + cond := ¶ms.Conditions{Match: map[string]string{WorkspaceLabel: testWorkspace}} + repoList, err := repoOperator.ListRepos(cond, "", false, 10, 0) + if err != nil { + klog.Errorf("list repo failed, err: %s", err) + t.FailNow() + } + + if len(repoList.Items) != 1 { + klog.Errorf("list repo failed") + t.FailNow() + } + + // describe repo + describeRepo, err := repoOperator.DescribeRepo(repoResp.RepoID) + if err != nil { + klog.Errorf("describe app failed, err: %s", err) + t.FailNow() + } + _ = describeRepo + +} + +func prepareRepoOperator() RepoInterface { + ksClient = fakeks.NewSimpleClientset() + k8sClient = fakek8s.NewSimpleClientset() + fakeInformerFactory = informers.NewInformerFactories(k8sClient, ksClient, nil, nil, nil, nil) + + return newRepoOperator(cachedReposData, fakeInformerFactory.KubeSphereSharedInformerFactory(), ksClient) +} diff --git a/pkg/models/openpitrix/repos.go b/pkg/models/openpitrix/repos.go index e8d169d45c5b3a97bbdc267ddb74855de96c2448..68339ec05c98323828aefcf9aa32cb438546b629 100644 --- a/pkg/models/openpitrix/repos.go +++ b/pkg/models/openpitrix/repos.go @@ -14,118 +14,185 @@ limitations under the License. package openpitrix import ( + "context" "fmt" - "github.com/golang/protobuf/ptypes/wrappers" - "google.golang.org/grpc/codes" - "google.golang.org/grpc/status" + "github.com/go-openapi/strfmt" + apierrors "k8s.io/apimachinery/pkg/api/errors" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/selection" + "k8s.io/apimachinery/pkg/types" "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned" + typed_v1alpha1 "kubesphere.io/kubesphere/pkg/client/clientset/versioned/typed/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + listers_v1alpha1 "kubesphere.io/kubesphere/pkg/client/listers/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/server/params" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" - "openpitrix.io/openpitrix/pkg/pb" + "kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmrepoindex" + "kubesphere.io/kubesphere/pkg/utils/reposcache" + "kubesphere.io/kubesphere/pkg/utils/stringutils" + "sigs.k8s.io/controller-runtime/pkg/client" + "sort" "strings" ) +const DescriptionLen = 512 + type RepoInterface interface { - CreateRepo(request *CreateRepoRequest) (*CreateRepoResponse, error) + CreateRepo(repo *v1alpha1.HelmRepo) (*CreateRepoResponse, error) DeleteRepo(id string) error + ValidateRepo(u string, request *v1alpha1.HelmRepoCredential) (*ValidateRepoResponse, error) ModifyRepo(id string, request *ModifyRepoRequest) error DescribeRepo(id string) (*Repo, error) ListRepos(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) - ValidateRepo(request *ValidateRepoRequest) (*ValidateRepoResponse, error) DoRepoAction(repoId string, request *RepoActionRequest) error - ListEvents(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) ListRepoEvents(repoId string, conditions *params.Conditions, limit, offset int) (*models.PageableResponse, error) } type repoOperator struct { - opClient openpitrix.Client + cachedRepos reposcache.ReposCache + informers externalversions.SharedInformerFactory + repoClient typed_v1alpha1.ApplicationV1alpha1Interface + repoLister listers_v1alpha1.HelmRepoLister + rlsLister listers_v1alpha1.HelmReleaseLister } -func newRepoOperator(opClient openpitrix.Client) RepoInterface { +func newRepoOperator(cachedRepos reposcache.ReposCache, informers externalversions.SharedInformerFactory, ksClient versioned.Interface) RepoInterface { return &repoOperator{ - opClient: opClient, + cachedRepos: cachedRepos, + informers: informers, + repoClient: ksClient.ApplicationV1alpha1(), + repoLister: informers.Application().V1alpha1().HelmRepos().Lister(), + rlsLister: informers.Application().V1alpha1().HelmReleases().Lister(), } } -func (c *repoOperator) CreateRepo(request *CreateRepoRequest) (*CreateRepoResponse, error) { - createRepoRequest := &pb.CreateRepoRequest{ - Name: &wrappers.StringValue{Value: request.Name}, - Description: &wrappers.StringValue{Value: request.Description}, - Type: &wrappers.StringValue{Value: request.Type}, - Url: &wrappers.StringValue{Value: request.URL}, - Credential: &wrappers.StringValue{Value: request.Credential}, - Visibility: &wrappers.StringValue{Value: request.Visibility}, - CategoryId: &wrappers.StringValue{Value: request.CategoryId}, - AppDefaultStatus: &wrappers.StringValue{Value: request.AppDefaultStatus}, +// TODO implement DoRepoAction +func (c *repoOperator) DoRepoAction(repoId string, request *RepoActionRequest) error { + repo, err := c.repoLister.Get(repoId) + if err != nil { + return err + } + if request.Workspace != repo.GetWorkspace() { + return nil } - if request.Providers != nil { - createRepoRequest.Providers = request.Providers + patch := client.MergeFrom(repo) + copyRepo := repo.DeepCopy() + copyRepo.Spec.Version += 1 + data, err := patch.Data(copyRepo) + if err != nil { + klog.Errorf("create patch [%s] failed, error: %s", repoId, err) + return err } - if request.Workspace != nil { - createRepoRequest.Labels = &wrappers.StringValue{Value: fmt.Sprintf("workspace=%s", *request.Workspace)} + repo, err = c.repoClient.HelmRepos().Patch(context.TODO(), repoId, types.MergePatchType, data, metav1.PatchOptions{}) + if err != nil { + klog.Errorf("patch repo [%s] failed, error: %s", repoId, err) + return err } + return nil +} + +func (c *repoOperator) ValidateRepo(u string, cred *v1alpha1.HelmRepoCredential) (*ValidateRepoResponse, error) { + _, err := helmrepoindex.LoadRepoIndex(context.TODO(), u, cred) - resp, err := c.opClient.CreateRepo(openpitrix.SystemContext(), createRepoRequest) if err != nil { - klog.Error(err) return nil, err } - return &CreateRepoResponse{ - RepoID: resp.GetRepoId().GetValue(), - }, nil + return &ValidateRepoResponse{Ok: true}, nil } -func (c *repoOperator) DeleteRepo(id string) error { - _, err := c.opClient.DeleteRepos(openpitrix.SystemContext(), &pb.DeleteReposRequest{ - RepoId: []string{id}, - }) +func (c *repoOperator) CreateRepo(repo *v1alpha1.HelmRepo) (*CreateRepoResponse, error) { + name := repo.GetTrueName() + + items, err := c.repoLister.List(labels.SelectorFromSet(map[string]string{constants.WorkspaceLabelKey: repo.GetWorkspace()})) + if err != nil && !apierrors.IsNotFound(err) { + klog.Errorf("list helm repo failed: %s", err) + return nil, err + } + + for _, exists := range items { + if exists.GetTrueName() == name { + klog.Error(repoItemExists, "name: ", name) + return nil, repoItemExists + } + } + + repo.Spec.Description = stringutils.ShortenString(repo.Spec.Description, DescriptionLen) + _, err = c.repoClient.HelmRepos().Create(context.TODO(), repo, metav1.CreateOptions{}) if err != nil { + klog.Errorf("create helm repo failed, repod_id: %s, error: %s", repo.GetHelmRepoId(), err) + return nil, err + } else { + klog.V(4).Infof("create helm repo success, repo_id: %s", repo.GetHelmRepoId()) + } + + return &CreateRepoResponse{repo.GetHelmRepoId()}, nil +} + +func (c *repoOperator) DeleteRepo(id string) error { + ls := map[string]string{ + constants.ChartRepoIdLabelKey: id, + } + releases, err := c.rlsLister.List(labels.SelectorFromSet(ls)) + + if err != nil && apierrors.IsNotFound(err) { + return err + } else if len(releases) > 0 { + return fmt.Errorf("repo %s has releases not deleted", id) + } + + err = c.repoClient.HelmRepos().Delete(context.TODO(), id, metav1.DeleteOptions{}) + if err != nil && apierrors.IsNotFound(err) { klog.Error(err) return err } + klog.V(4).Infof("repo %s deleted", id) return nil } func (c *repoOperator) ModifyRepo(id string, request *ModifyRepoRequest) error { - modifyRepoRequest := &pb.ModifyRepoRequest{ - RepoId: &wrappers.StringValue{Value: id}, - } + repo, err := c.repoClient.HelmRepos().Get(context.TODO(), id, metav1.GetOptions{}) - if request.Name != nil { - modifyRepoRequest.Name = &wrappers.StringValue{Value: *request.Name} + if err != nil { + klog.Error("get repo failed", err) + return err } + + repoCopy := repo.DeepCopy() if request.Description != nil { - modifyRepoRequest.Description = &wrappers.StringValue{Value: *request.Description} - } - if request.Type != nil { - modifyRepoRequest.Type = &wrappers.StringValue{Value: *request.Type} + repoCopy.Spec.Description = stringutils.ShortenString(*request.Description, DescriptionLen) } if request.URL != nil { - modifyRepoRequest.Url = &wrappers.StringValue{Value: *request.URL} - } - if request.Credential != nil { - modifyRepoRequest.Credential = &wrappers.StringValue{Value: *request.Credential} - } - if request.Visibility != nil { - modifyRepoRequest.Visibility = &wrappers.StringValue{Value: *request.Visibility} + repoCopy.Spec.Url = *request.URL } - if request.CategoryID != nil { - modifyRepoRequest.CategoryId = &wrappers.StringValue{Value: *request.CategoryID} + // TODO modify credential + if request.Name != nil { + repoCopy.Labels[constants.NameLabelKey] = *request.Name } - if request.AppDefaultStatus != nil { - modifyRepoRequest.AppDefaultStatus = &wrappers.StringValue{Value: *request.AppDefaultStatus} + if request.Workspace != nil { + repoCopy.Labels[constants.WorkspaceLabelKey] = *request.Workspace } - if request.Providers != nil { - modifyRepoRequest.Providers = request.Providers + + patch := client.MergeFrom(repo) + repoCopy.Spec.Version += 1 + data, err := patch.Data(repoCopy) + if err != nil { + klog.Error("create patch failed", err) + return err } - if request.Workspace != nil { - modifyRepoRequest.Labels = &wrappers.StringValue{Value: fmt.Sprintf("workspace=%s", *request.Workspace)} + + // data == "{}", need not to patch + if len(data) == 2 { + return nil } - _, err := c.opClient.ModifyRepo(openpitrix.SystemContext(), modifyRepoRequest) + repo, err = c.repoClient.HelmRepos().Patch(context.TODO(), id, patch.Type(), data, metav1.PatchOptions{}) + if err != nil { klog.Error(err) return err @@ -134,164 +201,98 @@ func (c *repoOperator) ModifyRepo(id string, request *ModifyRepoRequest) error { } func (c *repoOperator) DescribeRepo(id string) (*Repo, error) { - resp, err := c.opClient.DescribeRepos(openpitrix.SystemContext(), &pb.DescribeReposRequest{ - RepoId: []string{id}, - Limit: 1, - }) + repo, err := c.repoClient.HelmRepos().Get(context.TODO(), id, metav1.GetOptions{}) if err != nil { klog.Error(err) return nil, err } - var repo *Repo + var desRepo Repo - if len(resp.RepoSet) > 0 { - repo = convertRepo(resp.RepoSet[0]) - return repo, nil - } else { - err := status.New(codes.NotFound, "resource not found").Err() - klog.Error(err) - return nil, err - } + desRepo.URL = repo.Spec.Url + desRepo.Description = repo.Spec.Description + desRepo.Name = repo.GetTrueName() + desRepo.RepoId = repo.Name + dt, _ := strfmt.ParseDateTime(repo.CreationTimestamp.String()) + desRepo.CreateTime = &dt + + return &desRepo, nil } func (c *repoOperator) ListRepos(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { - req := &pb.DescribeReposRequest{} - if keyword := conditions.Match[Keyword]; keyword != "" { - req.SearchWord = &wrappers.StringValue{Value: keyword} - } - if status := conditions.Match[Status]; status != "" { - req.Status = strings.Split(status, "|") - } - if typeStr := conditions.Match[Type]; typeStr != "" { - req.Type = strings.Split(typeStr, "|") - } - if visibility := conditions.Match[Visibility]; visibility != "" { - req.Visibility = strings.Split(visibility, "|") - } - if status := conditions.Match[Status]; status != "" { - req.Status = strings.Split(status, "|") - } - if workspace := conditions.Match[WorkspaceLabel]; workspace != "" { - req.Label = &wrappers.StringValue{Value: fmt.Sprintf("workspace=%s", workspace)} - } - if orderBy != "" { - req.SortKey = &wrappers.StringValue{Value: orderBy} - } - req.Reverse = &wrappers.BoolValue{Value: reverse} - req.Limit = uint32(limit) - req.Offset = uint32(offset) - resp, err := c.opClient.DescribeRepos(openpitrix.SystemContext(), req) + ls := labels.NewSelector() + r, _ := labels.NewRequirement(constants.WorkspaceLabelKey, selection.Equals, []string{conditions.Match[WorkspaceLabel]}) + ls = ls.Add([]labels.Requirement{*r}...) + + repos, err := c.repoLister.List(ls) + if err != nil { klog.Error(err) return nil, err } - - items := make([]interface{}, 0) - - for _, item := range resp.RepoSet { - items = append(items, convertRepo(item)) + if conditions.Match[Keyword] != "" { + repos = helmRepoFilter(conditions.Match[Keyword], repos) } - return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil -} - -func (c *repoOperator) ValidateRepo(request *ValidateRepoRequest) (*ValidateRepoResponse, error) { - resp, err := c.opClient.ValidateRepo(openpitrix.SystemContext(), &pb.ValidateRepoRequest{ - Type: &wrappers.StringValue{Value: request.Type}, - Credential: &wrappers.StringValue{Value: request.Credential}, - Url: &wrappers.StringValue{Value: request.Url}, - }) - - if err != nil { - klog.Error(err) - return nil, err + if reverse { + sort.Sort(sort.Reverse(HelmRepoList(repos))) + } else { + sort.Sort(HelmRepoList(repos)) } - return &ValidateRepoResponse{ - ErrorCode: int64(resp.ErrorCode), - Ok: resp.Ok.Value, - }, nil + items := make([]interface{}, 0, limit) + for i, j := offset, 0; i < len(repos) && j < limit; { + items = append(items, convertRepo(repos[i])) + i++ + j++ + } + return &models.PageableResponse{Items: items, TotalCount: len(repos)}, nil } -func (c *repoOperator) DoRepoAction(repoId string, request *RepoActionRequest) error { - var err error - switch request.Action { - case ActionIndex: - indexRepoRequest := &pb.IndexRepoRequest{ - RepoId: &wrappers.StringValue{Value: repoId}, +func helmRepoFilter(namePrefix string, list []*v1alpha1.HelmRepo) (res []*v1alpha1.HelmRepo) { + for _, repo := range list { + name := repo.GetTrueName() + if strings.HasPrefix(name, namePrefix) { + res = append(res, repo) } - _, err := c.opClient.IndexRepo(openpitrix.SystemContext(), indexRepoRequest) - - if err != nil { - klog.Error(err) - return err - } - - return nil - default: - err = status.New(codes.InvalidArgument, "action not support").Err() - klog.Error(err) - return err } + return } -func (c *repoOperator) ListRepoEvents(repoId string, conditions *params.Conditions, limit, offset int) (*models.PageableResponse, error) { - describeRepoEventsRequest := &pb.DescribeRepoEventsRequest{ - RepoId: []string{repoId}, - } - if eventId := conditions.Match["repo_event_id"]; eventId != "" { - describeRepoEventsRequest.RepoEventId = strings.Split(eventId, "|") - } - if status := conditions.Match["status"]; status != "" { - describeRepoEventsRequest.Status = strings.Split(status, "|") - } - describeRepoEventsRequest.Limit = uint32(limit) - describeRepoEventsRequest.Offset = uint32(offset) - - resp, err := c.opClient.DescribeRepoEvents(openpitrix.SystemContext(), describeRepoEventsRequest) - - if err != nil { - klog.Error(err) - return nil, err - } - - items := make([]interface{}, 0) - - for _, item := range resp.RepoEventSet { - items = append(items, convertRepoEvent(item)) +type HelmRepoList []*v1alpha1.HelmRepo + +func (l HelmRepoList) Len() int { return len(l) } +func (l HelmRepoList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l HelmRepoList) Less(i, j int) bool { + t1 := l[i].CreationTimestamp.UnixNano() + t2 := l[j].CreationTimestamp.UnixNano() + if t1 < t2 { + return true + } else if t1 > t2 { + return false + } else { + n1 := l[i].GetTrueName() + n2 := l[j].GetTrueName() + return n1 < n2 } - - return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil } -func (c *repoOperator) ListEvents(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { - describeRepoEventsRequest := &pb.DescribeRepoEventsRequest{} - if repoId := conditions.Match["repo_id"]; repoId != "" { - describeRepoEventsRequest.RepoId = strings.Split(repoId, "|") - } - if eventId := conditions.Match["repo_event_id"]; eventId != "" { - describeRepoEventsRequest.RepoEventId = strings.Split(eventId, "|") - } - if status := conditions.Match["status"]; status != "" { - describeRepoEventsRequest.Status = strings.Split(status, "|") - } - describeRepoEventsRequest.Limit = uint32(limit) - describeRepoEventsRequest.Offset = uint32(offset) +func (c *repoOperator) ListRepoEvents(repoId string, conditions *params.Conditions, limit, offset int) (*models.PageableResponse, error) { - resp, err := c.opClient.DescribeRepoEvents(openpitrix.SystemContext(), describeRepoEventsRequest) + repo, err := c.repoClient.HelmRepos().Get(context.TODO(), repoId, metav1.GetOptions{}) if err != nil { klog.Error(err) return nil, err } - items := make([]interface{}, 0) - - for _, item := range resp.RepoEventSet { - items = append(items, convertRepoEvent(item)) + items := make([]interface{}, 0, limit) + for i, j := offset, 0; i < len(repo.Status.SyncState) && j < limit; { + items = append(items, convertRepoEvent(&repo.ObjectMeta, &repo.Status.SyncState[j])) + i++ + j++ } - return &models.PageableResponse{Items: items, TotalCount: int(resp.TotalCount)}, nil + return &models.PageableResponse{Items: items, TotalCount: len(repo.Status.SyncState)}, nil } diff --git a/pkg/models/openpitrix/types.go b/pkg/models/openpitrix/types.go index 8c6608796bc3074df69346f62d3d3f7ebaa9da21..a3bf6a8ded846b754c976ed98cb5254adf7cc334 100644 --- a/pkg/models/openpitrix/types.go +++ b/pkg/models/openpitrix/types.go @@ -576,7 +576,7 @@ type CreateRepoRequest struct { // repository description Description string `json:"description,omitempty"` - // workspace + // If workspace is empty, then it's a global repo Workspace *string `json:"workspace,omitempty"` // required, repository name @@ -629,7 +629,8 @@ type ModifyRepoRequest struct { } type RepoActionRequest struct { - Action string `json:"action"` + Action string `json:"action"` + Workspace string `json:"workspace"` } type ValidateRepoRequest struct { @@ -663,6 +664,8 @@ type RepoLabels []*RepoLabel type RepoSelectors []*RepoSelector type Repo struct { + ChartCount int `json:"chart_count,omitempty"` + // app default status eg[active|draft] AppDefaultStatus string `json:"app_default_status,omitempty"` @@ -732,6 +735,9 @@ type ValidateRepoResponse struct { type CreateClusterRequest struct { + // release name + Name string `json:"name"` + // advanced param AdvancedParam []string `json:"advanced_param"` @@ -748,19 +754,28 @@ type CreateClusterRequest struct { VersionId string `json:"version_id,omitempty"` Username string `json:"-"` + + // current workspace + Workspace string `json:"workspace,omitempty"` } type UpgradeClusterRequest struct { + // release namespace + Namespace string `json:"namespace,omitempty"` + // cluster id ClusterId string `json:"cluster_id"` + // helm app id + AppId string `json:"app_id"` + // advanced param AdvancedParam []string `json:"advanced_param"` // required, conf a json string, include cpu, memory info of cluster Conf string `json:"conf,omitempty"` - // required, id of runtime + // Deprecated: required, id of runtime RuntimeId string `json:"runtime_id,omitempty"` // required, id of app version @@ -777,9 +792,6 @@ type Cluster struct { // id of app run in cluster AppId string `json:"app_id,omitempty"` - //// cluster common set - //ClusterCommonSet OpenpitrixClusterClusterCommonSet `json:"cluster_common_set"` - // cluster id ClusterId string `json:"cluster_id,omitempty"` @@ -857,9 +869,11 @@ type Runtime struct { } type ModifyClusterAttributesRequest struct { + ClusterName string `json:"clusterName,omitempty"` + Namespace string `json:"namespace,omitempty"` // required, id of cluster to modify - ClusterID string `json:"cluster_id,omitempty"` + ClusterID string `json:"cluster_id"` // cluster description Description *string `json:"description,omitempty"` @@ -869,10 +883,9 @@ type ModifyClusterAttributesRequest struct { } const ( - CreateTime = "create_time" - StatusTime = "status_time" - RuntimeId = "runtime_id" - Zone = "zone" + CreateTime = "create_time" + StatusTime = "status_time" + VersionId = "version_id" RepoId = "repo_id" CategoryId = "category_id" diff --git a/pkg/models/openpitrix/utils.go b/pkg/models/openpitrix/utils.go index 848c70f26af1a6cda6daa2f546245fd676473253..2c442c2b3c39ce60e266620ad8e62527e4f257a1 100644 --- a/pkg/models/openpitrix/utils.go +++ b/pkg/models/openpitrix/utils.go @@ -1,9 +1,12 @@ /* Copyright 2020 The KubeSphere 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. @@ -14,629 +17,676 @@ limitations under the License. package openpitrix import ( + "fmt" + "github.com/Masterminds/semver/v3" "github.com/go-openapi/strfmt" - "openpitrix.io/openpitrix/pkg/pb" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/cli-runtime/pkg/resource" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/server/params" + "kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmrepoindex" + "kubesphere.io/kubesphere/pkg/utils/idutils" + "kubesphere.io/kubesphere/pkg/utils/sliceutil" + "kubesphere.io/kubesphere/pkg/utils/stringutils" + "path" + "regexp" + "sort" + "strings" "time" ) -func convertApp(in *pb.App) *App { - - if in == nil { +func convertRepoEvent(meta *metav1.ObjectMeta, state *v1alpha1.HelmRepoSyncState) *RepoEvent { + if meta == nil || state == nil { return nil } + out := RepoEvent{} + date := strfmt.DateTime(time.Unix(state.SyncTime.Unix(), 0)) + out.CreateTime = &date + out.RepoId = meta.Name + out.RepoEventId = "" + out.Result = state.Message + out.Status = state.State + out.StatusTime = out.CreateTime - categorySet := make(AppCategorySet, 0) + return &out +} - for _, item := range in.CategorySet { - category := convertResourceCategory(item) - categorySet = append(categorySet, category) +func convertAppVersionAudit(appVersion *v1alpha1.HelmApplicationVersion) []*AppVersionAudit { + if appVersion == nil { + return nil } + var audits []*AppVersionAudit + for _, helmAudit := range appVersion.Status.Audit { + var audit AppVersionAudit + audit.AppId = appVersion.GetHelmApplicationId() + audit.Operator = helmAudit.Operator + audit.Message = helmAudit.Message + audit.Status = helmAudit.State + date := strfmt.DateTime(time.Unix(helmAudit.Time.Unix(), 0)) + audit.StatusTime = &date + audit.VersionId = appVersion.Name + audit.VersionType = "helm" + audit.VersionName = appVersion.GetVersionName() + audit.Operator = helmAudit.Operator + audit.OperatorType = helmAudit.OperatorType + + audits = append(audits, &audit) + } + + return audits +} - out := App{ - CategorySet: categorySet, - } +type HelmReleaseList []*v1alpha1.HelmRelease - if in.Abstraction != nil { - out.Abstraction = in.Abstraction.Value - } - if in.Active != nil { - out.Active = in.Active.Value - } - if in.AppId != nil { - out.AppId = in.AppId.Value - } - if in.AppVersionTypes != nil { - out.AppVersionTypes = in.AppVersionTypes.Value - } - if in.ChartName != nil { - out.ChartName = in.ChartName.Value - } - if in.CompanyJoinTime != nil { - date := strfmt.DateTime(time.Unix(in.CompanyJoinTime.Seconds, 0)) - out.CompanyJoinTime = &date - } - if in.CompanyName != nil { - out.CompanyName = in.CompanyName.Value - } - if in.CompanyProfile != nil { - out.CompanyProfile = in.CompanyProfile.Value - } - if in.CompanyWebsite != nil { - out.CompanyWebsite = in.CompanyWebsite.Value - } - if in.CreateTime != nil { - date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0)) - out.CreateTime = &date - } - if in.CompanyWebsite != nil { - out.CompanyWebsite = in.CompanyWebsite.Value - } - if in.Description != nil { - out.Description = in.Description.Value - } - if in.Home != nil { - out.Home = in.Home.Value - } - if in.Icon != nil { - out.Icon = in.Icon.Value - } - if in.Isv != nil { - out.Isv = in.Isv.Value - } - if in.Keywords != nil { - out.Keywords = in.Keywords.Value - } - if in.LatestAppVersion != nil { - out.LatestAppVersion = convertAppVersion(in.LatestAppVersion) - } - if in.Name != nil { - out.Name = in.Name.Value - } - if in.Owner != nil { - out.Owner = in.Owner.Value - } - if in.Readme != nil { - out.Readme = in.Readme.Value +func (l HelmReleaseList) Len() int { return len(l) } +func (l HelmReleaseList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l HelmReleaseList) Less(i, j int) bool { + var t1, t2 time.Time + if l[i].Status.LastUpdate.IsZero() { + t1 = l[i].CreationTimestamp.Time + } else { + t1 = l[i].Status.LastUpdate.Time } - if in.RepoId != nil { - out.RepoId = in.RepoId.Value - } - if in.StatusTime != nil { - date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0)) - out.StatusTime = &date + + if l[j].Status.LastUpdate.IsZero() { + t2 = l[j].CreationTimestamp.Time + } else { + t2 = l[j].Status.LastUpdate.Time } - if in.Status != nil { - out.Status = in.Status.Value + + if t1.After(t2) { + return true + } else if t1.Before(t2) { + return false + } else { + return l[i].Name > l[j].Name } - if in.Sources != nil { - out.Sources = in.Sources.Value +} + +type AppVersionAuditList []*AppVersionAudit + +func (l AppVersionAuditList) Len() int { return len(l) } +func (l AppVersionAuditList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l AppVersionAuditList) Less(i, j int) bool { + t1 := l[i].StatusTime.String() + t2 := l[j].StatusTime.String() + if t1 > t2 { + return true + } else if t1 < t2 { + return false + } else { + n1 := l[i].VersionName + n2 := l[j].VersionName + return n1 < n2 } - if in.Screenshots != nil { - out.Screenshots = in.Screenshots.Value +} + +// copy from openpitrix +func matchPackageFailedError(err error, res *ValidatePackageResponse) { + var errStr = err.Error() + var matchedError = "" + var errorDetails = make(map[string]string) + switch { + // Helm errors + case strings.HasPrefix(errStr, "no files in chart archive"), + strings.HasPrefix(errStr, "no files in app archive"): + + matchedError = "no files in package" + + case strings.HasPrefix(errStr, "chart yaml not in base directory"), + strings.HasPrefix(errStr, "chart metadata (Chart.yaml) missing"): + + errorDetails["Chart.yaml"] = "not found" + + case strings.HasPrefix(errStr, "invalid chart (Chart.yaml): name must not be empty"): + + errorDetails["Chart.yaml"] = "package name must not be empty" + + case strings.HasPrefix(errStr, "values.toml is illegal"): + + errorDetails["values.toml"] = errStr + + case strings.HasPrefix(errStr, "error reading"): + + matched := regexp.MustCompile("error reading (.+): (.+)").FindStringSubmatch(errStr) + if len(matched) > 0 { + errorDetails[matched[1]] = matched[2] + } + + // Devkit errors + case strings.HasPrefix(errStr, "[package.json] not in base directory"): + + errorDetails["package.json"] = "not found" + + case strings.HasPrefix(errStr, "missing file ["): + + matched := regexp.MustCompile("missing file \\[(.+)]").FindStringSubmatch(errStr) + if len(matched) > 0 { + errorDetails[matched[1]] = "not found" + } + + case strings.HasPrefix(errStr, "failed to parse"), + strings.HasPrefix(errStr, "failed to render"), + strings.HasPrefix(errStr, "failed to load"), + strings.HasPrefix(errStr, "failed to decode"): + + matched := regexp.MustCompile("failed to (.+) (.+): (.+)").FindStringSubmatch(errStr) + if len(matched) > 0 { + errorDetails[matched[2]] = fmt.Sprintf("%s failed, %s", matched[1], matched[3]) + } + + default: + matchedError = errStr } - if in.Tos != nil { - out.Tos = in.Tos.Value + if len(errorDetails) > 0 { + res.ErrorDetails = errorDetails } - if in.UpdateTime != nil { - date := strfmt.DateTime(time.Unix(in.UpdateTime.Seconds, 0)) - out.UpdateTime = &date + if len(matchedError) > 0 { + res.Error = matchedError } - - return &out } -func convertAppVersion(in *pb.AppVersion) *AppVersion { +func convertCategory(in *v1alpha1.HelmCategory) *Category { if in == nil { return nil } - out := AppVersion{} - if in.AppId != nil { - out.AppId = in.AppId.Value - } - if in.Active != nil { - out.Active = in.Active.Value - } - if in.CreateTime != nil { - date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0)) - out.CreateTime = &date - } - if in.Description != nil { - out.Description = in.Description.Value - } - if in.Home != nil { - out.Home = in.Home.Value - } - if in.Icon != nil { - out.Icon = in.Icon.Value - } - if in.Maintainers != nil { - out.Maintainers = in.Maintainers.Value - } - if in.Message != nil { - out.Message = in.Message.Value - } - if in.Keywords != nil { - out.Keywords = in.Keywords.Value - } - if in.Name != nil { - out.Name = in.Name.Value - } - if in.Owner != nil { - out.Owner = in.Owner.Value - } - if in.PackageName != nil { - out.PackageName = in.PackageName.Value - } - if in.Readme != nil { - out.Readme = in.Readme.Value - } - if in.ReviewId != nil { - out.ReviewId = in.ReviewId.Value - } - if in.Screenshots != nil { - out.Screenshots = in.Screenshots.Value - } - if in.Sources != nil { - out.Sources = in.Sources.Value - } - if in.Status != nil { - out.Status = in.Status.Value - } - if in.Sequence != nil { - out.Sequence = int64(in.Sequence.Value) - } - if in.StatusTime != nil { - date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0)) - out.StatusTime = &date - } - if in.Type != nil { - out.Type = in.Type.Value - } - if in.UpdateTime != nil { - date := strfmt.DateTime(time.Unix(in.UpdateTime.Seconds, 0)) - out.UpdateTime = &date - } - if in.VersionId != nil { - out.VersionId = in.VersionId.Value - } + out := &Category{} + out.Description = in.Spec.Description + out.Name = in.Spec.Name + out.CategoryID = in.Name + t := strfmt.DateTime(in.CreationTimestamp.Time) + out.CreateTime = &t + if in.Spec.Locale == "" { + out.Locale = "{}" + } else { + out.Locale = in.Spec.Locale + } + total := in.Status.Total + out.AppTotal = &total + + return out +} - return &out +func convertApplication(rls *v1alpha1.HelmRelease, rlsInfos []*resource.Info) *Application { + app := &Application{} + app.Name = rls.Spec.ChartName + cluster := &Cluster{} + cluster.ClusterId = rls.Name + cluster.Owner = rls.GetCreator() + cluster.Zone = rls.GetRlsNamespace() + cluster.Status = rls.Status.State + cluster.Env = string(rls.Spec.Values) + if cluster.Status == "" { + cluster.Status = v1alpha1.HelmStatusPending + } + cluster.AdditionalInfo = rls.Status.Message + cluster.Description = rls.Spec.Description + dt := strfmt.DateTime(rls.CreationTimestamp.Time) + cluster.CreateTime = &dt + if !rls.Status.LastUpdate.Time.IsZero() { + ut := strfmt.DateTime(rls.Status.LastUpdate.Time) + cluster.StatusTime = &ut + } else { + cluster.StatusTime = &dt + } + cluster.AppId = rls.Spec.ApplicationId + cluster.VersionId = rls.Spec.ApplicationVersionId + cluster.Name = rls.GetTrueName() + + if rls.GetRlsCluster() != "" { + cluster.RuntimeId = rls.GetRlsCluster() + } else { + cluster.RuntimeId = "default" + } + + app.Cluster = cluster + app.Version = &AppVersion{ + AppId: rls.Spec.ApplicationId, + VersionId: rls.Spec.ApplicationVersionId, + Name: rls.GetChartVersionName(), + } + app.App = &App{ + AppId: rls.Spec.ApplicationId, + ChartName: rls.Spec.ChartName, + Name: rls.Spec.ChartName, + } + + app.ReleaseInfo = make([]runtime.Object, 0, len(rlsInfos)) + if rlsInfos != nil { + for _, info := range rlsInfos { + app.ReleaseInfo = append(app.ReleaseInfo, info.Object) + } + } + return app } -func convertResourceCategory(in *pb.ResourceCategory) *ResourceCategory { - if in == nil { +func convertApp(app *v1alpha1.HelmApplication, versions []*v1alpha1.HelmApplicationVersion, ctg *v1alpha1.HelmCategory, rlsCount int) *App { + if app == nil { return nil } - out := ResourceCategory{} + out := &App{} + + out.AppId = app.Name + out.Name = app.GetTrueName() - if in.CategoryId != nil { - out.CategoryId = in.CategoryId.Value + date := strfmt.DateTime(app.CreationTimestamp.Time) + out.CreateTime = &date + if app.Status.StatusTime != nil { + s := strfmt.DateTime(app.Status.StatusTime.Time) + out.StatusTime = &s + } else { + out.StatusTime = out.CreateTime } - if in.CreateTime != nil { - date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0)) - out.CreateTime = &date + + if app.Status.UpdateTime == nil { + out.UpdateTime = out.CreateTime + } else { + u := strfmt.DateTime(app.Status.UpdateTime.Time) + out.UpdateTime = &u } - if in.Locale != nil { - out.Locale = in.Locale.Value + + out.Status = app.Status.State + if out.Status == "" { + out.Status = v1alpha1.StateDraft } - if in.Name != nil { - out.Name = in.Name.Value + out.Abstraction = app.Spec.Abstraction + out.Description = app.Spec.Description + + if len(app.Spec.Attachments) > 0 { + out.Screenshots = strings.Join(app.Spec.Attachments, ",") } - if in.Status != nil { - out.Status = in.Status.Value + out.Home = app.Spec.AppHome + out.Icon = app.Spec.Icon + + if ctg != nil { + ct := strfmt.DateTime(ctg.CreationTimestamp.Time) + rc := ResourceCategory{ + CategoryId: ctg.Name, + Name: ctg.GetTrueName(), + CreateTime: &ct, + Locale: ctg.Spec.Locale, + } + if ctg.Spec.Locale == "" { + rc.Locale = "{}" + } else { + rc.Locale = ctg.Spec.Locale + } + rc.Status = "enabled" + + out.CategorySet = AppCategorySet{&rc} + } else { + out.CategorySet = AppCategorySet{} } - if in.StatusTime != nil { - date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0)) - out.StatusTime = &date + if versions != nil && len(versions) > 0 { + sort.Sort(AppVersions(versions)) + out.LatestAppVersion = convertAppVersion(versions[0]) + } else { + out.LatestAppVersion = &AppVersion{} } - return &out + out.AppVersionTypes = "helm" + out.Isv = app.GetWorkspace() + + out.ClusterTotal = &rlsCount + + return out } -func convertCategory(in *pb.Category) *Category { - if in == nil { - return nil +func filterAppVersionByState(versions []*v1alpha1.HelmApplicationVersion, states []string) []*v1alpha1.HelmApplicationVersion { + if len(states) == 0 { + return versions } - out := Category{} - if in.CategoryId != nil { - out.CategoryID = in.CategoryId.Value - } - if in.CreateTime != nil { - date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0)) - out.CreateTime = &date - } - if in.Locale != nil { - out.Locale = in.Locale.Value - } - if in.Name != nil { - out.Name = in.Name.Value - } - if in.Description != nil { - out.Description = in.Description.Value - } - if in.Icon != nil { - out.Icon = in.Icon.Value - } - if in.Owner != nil { - out.Owner = in.Owner.Value - } - if in.UpdateTime != nil { - date := strfmt.DateTime(time.Unix(in.UpdateTime.Seconds, 0)) - out.UpdateTime = &date + var j = 0 + for i := 0; i < len(versions); i++ { + state := versions[i].State() + if sliceutil.HasString(states, state) { + if i != j { + versions[j] = versions[i] + } + j++ + } } - return &out + versions = versions[:j:j] + return versions } -func convertAttachment(in *pb.Attachment) *Attachment { +func convertAppVersion(in *v1alpha1.HelmApplicationVersion) *AppVersion { if in == nil { return nil } - out := Attachment{} - - out.AttachmentID = in.AttachmentId - - if in.CreateTime != nil { - date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0)) - out.CreateTime = &date + out := AppVersion{} + out.AppId = in.GetHelmApplicationId() + out.Active = true + t := in.CreationTimestamp.Time + date := strfmt.DateTime(t) + out.CreateTime = &date + if len(in.Status.Audit) > 0 { + t = in.Status.Audit[0].Time.Time + updateDate := strfmt.DateTime(t) + out.UpdateTime = &updateDate + } else { + out.UpdateTime = &date } - if in.AttachmentContent != nil { - out.AttachmentContent = make(map[string]strfmt.Base64) - for k, v := range in.AttachmentContent { - out.AttachmentContent[k] = v - } + if in.Spec.Metadata != nil { + out.Description = in.Spec.Description + out.Icon = in.Spec.Icon } + out.Status = in.State() + out.Owner = in.GetCreator() + out.Name = in.GetVersionName() + out.VersionId = in.GetHelmApplicationVersionId() return &out } -func convertRepo(in *pb.Repo) *Repo { +func convertRepo(in *v1alpha1.HelmRepo) *Repo { if in == nil { return nil } out := Repo{} - if in.RepoId != nil { - out.RepoId = in.RepoId.Value - } - if in.Name != nil { - out.Name = in.Name.Value - } - if in.AppDefaultStatus != nil { - out.AppDefaultStatus = in.AppDefaultStatus.Value - } - if in.Credential != nil { - out.Credential = in.Credential.Value - } - - categorySet := make(RepoCategorySet, 0) + out.RepoId = in.GetHelmRepoId() + out.Name = in.GetTrueName() - for _, item := range in.CategorySet { - category := convertResourceCategory(item) - categorySet = append(categorySet, category) - } + out.Status = "active" + date := strfmt.DateTime(time.Unix(in.CreationTimestamp.Unix(), 0)) + out.CreateTime = &date - out.CategorySet = categorySet + out.Description = in.Spec.Description - if in.Controller != nil { - out.Credential = in.Credential.Value - } + out.URL = in.Spec.Url + return &out +} - if in.CreateTime != nil { - date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0)) - out.CreateTime = &date +type HelmCategoryList []*v1alpha1.HelmCategory + +func (l HelmCategoryList) Len() int { return len(l) } +func (l HelmCategoryList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l HelmCategoryList) Less(i, j int) bool { + t1 := l[i].CreationTimestamp.UnixNano() + t2 := l[j].CreationTimestamp.UnixNano() + if t1 > t2 { + return true + } else if t1 < t2 { + return false + } else { + n1 := l[i].Spec.Name + n2 := l[j].Spec.Name + return n1 < n2 } +} - if in.Description != nil { - out.Description = in.Description.Value +type HelmApplicationList []*v1alpha1.HelmApplication + +func (l HelmApplicationList) Len() int { return len(l) } +func (l HelmApplicationList) Swap(i, j int) { l[i], l[j] = l[j], l[i] } +func (l HelmApplicationList) Less(i, j int) bool { + t1 := l[i].CreationTimestamp.UnixNano() + t2 := l[j].CreationTimestamp.UnixNano() + if t1 < t2 { + return true + } else if t1 > t2 { + return false + } else { + n1 := l[i].GetTrueName() + n2 := l[j].GetTrueName() + return n1 < n2 } +} - labelSet := make(RepoLabels, 0) +type AppVersions []*v1alpha1.HelmApplicationVersion - for _, item := range in.Labels { - label := convertRepoLabel(item) - labelSet = append(labelSet, label) - } +// Len returns the length. +func (c AppVersions) Len() int { return len(c) } - out.Labels = labelSet +// Swap swaps the position of two items in the versions slice. +func (c AppVersions) Swap(i, j int) { c[i], c[j] = c[j], c[i] } - if in.Owner != nil { - out.Owner = in.Owner.Value +// Less returns true if the version of entry a is less than the version of entry b. +func (c AppVersions) Less(a, b int) bool { + // Failed parse pushes to the back. + aVersion := c[a] + bVersion := c[b] + i, err := semver.NewVersion(aVersion.GetSemver()) + if err != nil { + return true } - if in.Providers != nil { - out.Providers = in.Providers + j, err := semver.NewVersion(bVersion.GetSemver()) + if err != nil { + return false } - if in.RepoId != nil { - out.RepoId = in.RepoId.Value + if i.Equal(j) { + return aVersion.CreationTimestamp.Before(&bVersion.CreationTimestamp) } + return j.LessThan(i) +} - selectorSet := make(RepoSelectors, 0) +// buildApplicationVersion build an application version +// packageData base64 encoded package data +func buildApplicationVersion(app *v1alpha1.HelmApplication, chrt helmrepoindex.VersionInterface, chartPackage *string, creator string) *v1alpha1.HelmApplicationVersion { + // create helm application version resource + t := metav1.Now() + ver := &v1alpha1.HelmApplicationVersion{ + ObjectMeta: metav1.ObjectMeta{ + Annotations: map[string]string{ + constants.CreatorAnnotationKey: creator, + }, + Name: idutils.GetUuid36(v1alpha1.HelmApplicationVersionIdPrefix), + Labels: map[string]string{ + constants.ChartApplicationIdLabelKey: app.GetHelmApplicationId(), + constants.WorkspaceLabelKey: app.GetWorkspace(), + }, + OwnerReferences: []metav1.OwnerReference{ + { + UID: app.GetUID(), + APIVersion: v1alpha1.SchemeGroupVersion.String(), + Kind: "HelmApplication", + Name: app.Name, + }, + }, + }, + Spec: v1alpha1.HelmApplicationVersionSpec{ + Metadata: &v1alpha1.Metadata{ + Version: chrt.GetVersion(), + AppVersion: chrt.GetAppVersion(), + Name: chrt.GetName(), + Icon: chrt.GetIcon(), + Home: chrt.GetHome(), + Description: stringutils.ShortenString(chrt.GetDescription(), v1alpha1.MsgLen), + }, + Created: &t, + // set data to nil before save app version to etcd + Data: []byte(*chartPackage), + }, + Status: v1alpha1.HelmApplicationVersionStatus{ + State: v1alpha1.StateDraft, + Audit: []v1alpha1.Audit{ + { + State: v1alpha1.StateDraft, + Time: t, + Operator: creator, + }, + }, + }, + } + + return ver +} - for _, item := range in.Selectors { - selector := convertRepoSelector(item) - selectorSet = append(selectorSet, selector) +func filterAppByName(app *v1alpha1.HelmApplication, namePart string) bool { + if len(namePart) == 0 { + return true } - out.Selectors = selectorSet - - if in.Status != nil { - out.Status = in.Status.Value - } - if in.StatusTime != nil { - out.StatusTime = strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0)) - } - if in.Type != nil { - out.Type = in.Type.Value + name := app.GetTrueName() + if strings.HasSuffix(name, namePart) || strings.HasPrefix(name, namePart) { + return true } - if in.Url != nil { - out.URL = in.Url.Value - } - if in.Visibility != nil { - out.Visibility = in.Visibility.Value - } - return &out + return false } -func convertRepoLabel(in *pb.RepoLabel) *RepoLabel { - if in == nil { - return nil - } - out := RepoLabel{} - if in.CreateTime != nil { - date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0)) - out.CreateTime = &date +func filterAppByStates(app *v1alpha1.HelmApplication, state []string) bool { + if len(state) == 0 { + return true } - if in.LabelKey != nil { - out.LabelKey = in.LabelKey.Value + st := app.Status.State + // default value is draft + if st == "" { + st = v1alpha1.StateDraft } - if in.LabelValue != nil { - out.LabelValue = in.LabelValue.Value + if sliceutil.HasString(state, st) { + return true } - return &out + return false } -func convertRepoSelector(in *pb.RepoSelector) *RepoSelector { - if in == nil { - return nil - } - out := RepoSelector{} - if in.CreateTime != nil { - date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0)) - out.CreateTime = &date +func filterApps(apps []*v1alpha1.HelmApplication, conditions *params.Conditions) []*v1alpha1.HelmApplication { + if conditions == nil || len(conditions.Match) == 0 || len(apps) == 0 { + return apps } - if in.SelectorKey != nil { - out.SelectorKey = in.SelectorKey.Value - } - if in.SelectorValue != nil { - out.SelectorValue = in.SelectorValue.Value + + curr := 0 + for i := 0; i < len(apps); i++ { + if conditions.Match[Keyword] != "" { + fv := filterAppByName(apps[i], conditions.Match[Keyword]) + if !fv { + continue + } + } + + if conditions.Match[Status] != "" { + states := strings.Split(conditions.Match[Status], "|") + fv := filterAppByStates(apps[i], states) + if !fv { + continue + } + } + if curr != i { + apps[curr] = apps[i] + } + curr++ } - return &out + + return apps[:curr:curr] } -func convertAppVersionAudit(in *pb.AppVersionAudit) *AppVersionAudit { - if in == nil { - return nil - } - out := AppVersionAudit{} - if in.AppId != nil { - out.AppId = in.AppId.Value - } - if in.AppName != nil { - out.AppName = in.AppName.Value - } - if in.Message != nil { - out.Message = in.Message.Value +func filterReleaseByName(rls *v1alpha1.HelmRelease, namePart string) bool { + if len(namePart) == 0 { + return true } - if in.Operator != nil { - out.Operator = in.Operator.Value - } - if in.OperatorType != nil { - out.OperatorType = in.OperatorType.Value - } - if in.ReviewId != nil { - out.ReviewId = in.ReviewId.Value - } - if in.Status != nil { - out.Status = in.Status.Value - } - if in.StatusTime != nil { - date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0)) - out.StatusTime = &date + + name := rls.GetTrueName() + if strings.HasSuffix(name, namePart) || strings.HasPrefix(name, namePart) { + return true } - if in.VersionId != nil { - out.VersionId = in.VersionId.Value + return false +} + +func filterReleaseByStates(rls *v1alpha1.HelmRelease, state []string) bool { + if len(state) == 0 { + return true } - if in.VersionName != nil { - out.VersionName = in.VersionName.Value + st := rls.Status.State + if st == "" { + st = v1alpha1.HelmStatusCreating } - if in.VersionType != nil { - out.VersionType = in.VersionType.Value + if sliceutil.HasString(state, st) { + return true } - return &out + return false } -func convertAppVersionReview(in *pb.AppVersionReview) *AppVersionReview { - if in == nil { - return nil - } - out := AppVersionReview{} - if in.AppId != nil { - out.AppId = in.AppId.Value +func filterReleasesWithAppVersions(releases []*v1alpha1.HelmRelease, appVersions map[string]*v1alpha1.HelmApplicationVersion) []*v1alpha1.HelmRelease { + if appVersions == nil || len(appVersions) == 0 || len(releases) == 0 { + return []*v1alpha1.HelmRelease{} } - if in.AppName != nil { - out.AppName = in.AppName.Value - } - if in.Phase != nil { - out.Phase = make(AppVersionReviewPhaseOAIGen) - for k, v := range in.Phase { - out.Phase[k] = *convertAppVersionReviewPhase(v) + + curr := 0 + for i := 0; i < len(releases); i++ { + if _, exists := appVersions[releases[i].Spec.ApplicationVersionId]; exists { + if curr != i { + releases[curr] = releases[i] + } + curr++ } } - if in.ReviewId != nil { - out.ReviewId = in.ReviewId.Value - } - if in.Reviewer != nil { - out.Reviewer = in.Reviewer.Value - } - if in.Status != nil { - out.Status = in.Status.Value - } - if in.StatusTime != nil { - out.StatusTime = strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0)) - } - if in.VersionId != nil { - out.VersionID = in.VersionId.Value - } - if in.VersionName != nil { - out.VersionName = in.VersionName.Value - } - if in.VersionType != nil { - out.VersionType = in.VersionType.Value - } - return &out + + return releases[:curr:curr] } -func convertAppVersionReviewPhase(in *pb.AppVersionReviewPhase) *AppVersionReviewPhase { - if in == nil { - return nil - } - out := AppVersionReviewPhase{} - if in.Message != nil { - out.Message = in.Message.Value - } - if in.OperatorType != nil { - out.OperatorType = in.OperatorType.Value - } - if in.ReviewTime != nil { - date := strfmt.DateTime(time.Unix(in.ReviewTime.Seconds, 0)) - out.ReviewTime = &date - } - if in.Operator != nil { - out.Operator = in.Operator.Value - } - if in.Status != nil { - out.Status = in.Status.Value +func filterReleases(releases []*v1alpha1.HelmRelease, conditions *params.Conditions) []*v1alpha1.HelmRelease { + if conditions == nil || len(conditions.Match) == 0 || len(releases) == 0 { + return releases } - if in.StatusTime != nil { - date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0)) - out.StatusTime = &date + + curr := 0 + for i := 0; i < len(releases); i++ { + if conditions.Match[Keyword] != "" { + fv := filterReleaseByName(releases[i], conditions.Match[Keyword]) + if !fv { + continue + } + } + + if conditions.Match[Status] != "" { + states := strings.Split(conditions.Match[Status], "|") + fv := filterReleaseByStates(releases[i], states) + if !fv { + continue + } + } + if curr != i { + releases[curr] = releases[i] + } + curr++ } - return &out + + return releases[:curr:curr] } -func convertRepoEvent(in *pb.RepoEvent) *RepoEvent { - if in == nil { - return nil - } - out := RepoEvent{} - if in.CreateTime != nil { - date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0)) - out.CreateTime = &date - } - if in.Owner != nil { - out.Owner = in.Owner.Value - } - if in.RepoEventId != nil { - out.RepoEventId = in.RepoEventId.Value - } - if in.RepoId != nil { - out.RepoId = in.RepoId.Value - } - if in.Result != nil { - out.Result = in.Result.Value - } - if in.Status != nil { - out.Status = in.Status.Value - } - if in.StatusTime != nil { - date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0)) - out.StatusTime = &date - } +func dataKeyInStorage(workspace, id string) string { + return path.Join(workspace, id) +} - return &out +func attachmentKeyInStorage(ws, id string) string { + return path.Join(ws, id) } -func convertCluster(in *pb.Cluster) *Cluster { - if in == nil { - return nil - } - out := Cluster{} - if in.AdditionalInfo != nil { - out.AdditionalInfo = in.AdditionalInfo.Value - } - if in.AppId != nil { - out.AppId = in.AppId.Value - } - if in.ClusterId != nil { - out.ClusterId = in.ClusterId.Value - } - if in.ClusterType != nil { - out.ClusterType = int64(in.ClusterType.Value) - } - if in.CreateTime != nil { - date := strfmt.DateTime(time.Unix(in.CreateTime.Seconds, 0)) - out.CreateTime = &date - } - if in.Debug != nil { - out.Debug = in.Debug.Value - } - if in.Description != nil { - out.Description = in.Description.Value - } - if in.Endpoints != nil { - out.Endpoints = in.Endpoints.Value - } - if in.Env != nil { - out.Env = in.Env.Value - } - if in.FrontgateId != nil { - out.FrontgateId = in.FrontgateId.Value - } - if in.GlobalUuid != nil { - out.GlobalUUID = in.GlobalUuid.Value - } - if in.MetadataRootAccess != nil { - out.MetadataRootAccess = in.MetadataRootAccess.Value - } - if in.Name != nil { - out.Name = in.Name.Value - } - if in.Owner != nil { - out.Owner = in.Owner.Value - } - if in.RuntimeId != nil { - out.RuntimeId = in.RuntimeId.Value - } - if in.Status != nil { - out.Status = in.Status.Value - } - if in.StatusTime != nil { - date := strfmt.DateTime(time.Unix(in.StatusTime.Seconds, 0)) - out.StatusTime = &date - } - if in.SubnetId != nil { - out.SubnetId = in.SubnetId.Value - } - if in.TransitionStatus != nil { - out.TransitionStatus = in.TransitionStatus.Value - } - if in.UpgradeStatus != nil { - out.UpgradeStatus = in.UpgradeStatus.Value - } - if in.UpgradeTime != nil { - date := strfmt.DateTime(time.Unix(in.UpgradeTime.Seconds, 0)) - out.UpgradeTime = &date - } - if in.VersionId != nil { - out.VersionId = in.VersionId.Value - } - if in.VpcId != nil { - out.VpcId = in.VpcId.Value +func convertAppVersionReview(appVersion *v1alpha1.HelmApplicationVersion) *AppVersionReview { + review := &AppVersionReview{} + status := appVersion.Status + review.Reviewer = status.Audit[0].Operator + review.ReviewId = status.Audit[0].Operator + review.Status = appVersion.Status.State + review.AppId = appVersion.GetHelmApplicationId() + review.VersionID = appVersion.GetHelmApplicationVersionId() + review.Phase = AppVersionReviewPhaseOAIGen{} + review.VersionName = appVersion.GetVersionName() + + review.StatusTime = strfmt.DateTime(status.Audit[0].Time.Time) + review.AppName = appVersion.GetTrueName() + return review +} + +func parseChartVersionName(name string) (version, appVersion string) { + name = strings.TrimSpace(name) + if name == "" { + return "", "" } - if in.Zone != nil { - out.Zone = in.Zone.Value + + parts := strings.Split(name, "[") + if len(parts) == 1 { + return parts[0], "" } - return &out + + version = strings.TrimSpace(parts[0]) + + appVersion = strings.Trim(parts[1], "]") + appVersion = strings.TrimSpace(appVersion) + return } diff --git a/pkg/models/openpitrix/v2alpha1/applications.go b/pkg/models/openpitrix/v2alpha1/applications.go new file mode 100644 index 0000000000000000000000000000000000000000..43fd1cee3a701f115a8229f36486e8704eb6d7be --- /dev/null +++ b/pkg/models/openpitrix/v2alpha1/applications.go @@ -0,0 +1,86 @@ +/* +Copyright 2020 The KubeSphere 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 v2alpha1 + +import ( + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/constants" + resources "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/openpitrix/application" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/openpitrix/applicationversion" +) + +type ApplicationInterface interface { + DescribeAppVersion(id string) (*v1alpha1.HelmApplicationVersion, error) + DescribeApp(id string) (*v1alpha1.HelmApplication, error) + + ListApps(workspace string, q *query.Query) (*api.ListResult, error) + ListAppVersions(workspace, appId string, q *query.Query) (*api.ListResult, error) +} + +type applicationOperator struct { + appsGetter resources.Interface + appVersionGetter resources.Interface +} + +func newApplicationOperator(informers externalversions.SharedInformerFactory) ApplicationInterface { + op := &applicationOperator{ + appsGetter: application.New(informers), + appVersionGetter: applicationversion.New(informers), + } + + return op +} + +func (c *applicationOperator) ListApps(workspace string, q *query.Query) (*api.ListResult, error) { + + labelSelector, err := labels.ConvertSelectorToLabelsMap(q.LabelSelector) + if err != nil { + klog.Error(err) + return nil, err + } + + extra := labels.Set{} + if workspace != "" { + extra[constants.WorkspaceLabelKey] = workspace + } + + if len(extra) > 0 { + q.LabelSelector = labels.Merge(labelSelector, extra).String() + } + + releases, err := c.appsGetter.List("", q) + if err != nil && !apierrors.IsNotFound(err) { + klog.Errorf("list app failed, error: %v", err) + return nil, err + } + + return releases, nil +} + +func (c *applicationOperator) DescribeApp(verId string) (*v1alpha1.HelmApplication, error) { + ret, err := c.appsGetter.Get("", verId) + if err != nil { + klog.Errorf("get app failed, error: %v", err) + return nil, err + } + + return ret.(*v1alpha1.HelmApplication), nil +} diff --git a/pkg/models/openpitrix/v2alpha1/applicationsversions.go b/pkg/models/openpitrix/v2alpha1/applicationsversions.go new file mode 100644 index 0000000000000000000000000000000000000000..db47db079d1d01679f8e6ab6f606569d505e8cc2 --- /dev/null +++ b/pkg/models/openpitrix/v2alpha1/applicationsversions.go @@ -0,0 +1,64 @@ +/* +Copyright 2020 The KubeSphere 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 v2alpha1 + +import ( + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/constants" +) + +func (c *applicationOperator) ListAppVersions(workspace, appId string, q *query.Query) (*api.ListResult, error) { + + labelSelector, err := labels.ConvertSelectorToLabelsMap(q.LabelSelector) + if err != nil { + klog.Error(err) + return nil, err + } + + extra := labels.Set{} + if workspace != "" { + extra[constants.WorkspaceLabelKey] = workspace + } + + if appId != "" { + extra[constants.ChartApplicationIdLabelKey] = appId + } + + if len(extra) > 0 { + q.LabelSelector = labels.Merge(labelSelector, extra).String() + } + + releases, err := c.appVersionGetter.List("", q) + if err != nil && !apierrors.IsNotFound(err) { + klog.Errorf("list app version failed, error: %v", err) + return nil, err + } + + return releases, nil +} + +func (c *applicationOperator) DescribeAppVersion(verId string) (*v1alpha1.HelmApplicationVersion, error) { + ret, err := c.appVersionGetter.Get("", verId) + if err != nil { + klog.Errorf("get app version failed, error: %v", err) + return nil, err + } + + return ret.(*v1alpha1.HelmApplicationVersion), nil +} diff --git a/pkg/models/openpitrix/v2alpha1/categories.go b/pkg/models/openpitrix/v2alpha1/categories.go new file mode 100644 index 0000000000000000000000000000000000000000..0b8270c8f265734ae2269be118ebc591d2521b97 --- /dev/null +++ b/pkg/models/openpitrix/v2alpha1/categories.go @@ -0,0 +1,64 @@ +/* +Copyright 2020 The KubeSphere 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 v2alpha1 + +import ( + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + resources "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/openpitrix/category" +) + +type CategoryInterface interface { + ListCategories(q *query.Query) (*api.ListResult, error) + DescribeCategory(id string) (*v1alpha1.HelmCategory, error) +} + +type categoryOperator struct { + ctgGetter resources.Interface +} + +func newCategoryOperator(ksFactory externalversions.SharedInformerFactory) CategoryInterface { + c := &categoryOperator{ + ctgGetter: category.New(ksFactory), + } + + return c +} + +func (c *categoryOperator) DescribeCategory(id string) (*v1alpha1.HelmCategory, error) { + ret, err := c.ctgGetter.Get("", id) + + if err != nil { + klog.Error(err) + return nil, err + } + + ctg := ret.(*v1alpha1.HelmCategory) + return ctg, nil +} + +func (c *categoryOperator) ListCategories(q *query.Query) (*api.ListResult, error) { + + result, err := c.ctgGetter.List("", q) + if err != nil { + klog.Error(err) + return nil, err + } + + return result, nil +} diff --git a/pkg/models/openpitrix/v2alpha1/interface.go b/pkg/models/openpitrix/v2alpha1/interface.go new file mode 100644 index 0000000000000000000000000000000000000000..1190b8300345a2e41a2fc7bdc95d62f61e78db19 --- /dev/null +++ b/pkg/models/openpitrix/v2alpha1/interface.go @@ -0,0 +1,44 @@ +/* +Copyright 2020 The KubeSphere 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 v2alpha1 + +import ( + "kubesphere.io/kubesphere/pkg/informers" +) + +type Interface interface { + ApplicationInterface + RepoInterface + HelmReleaseInterface + CategoryInterface +} + +type openpitrixOperator struct { + ApplicationInterface + RepoInterface + HelmReleaseInterface + CategoryInterface +} + +func NewOpenPitrixOperator(ksInformers informers.InformerFactory) Interface { + return &openpitrixOperator{ + ApplicationInterface: newApplicationOperator(ksInformers.KubeSphereSharedInformerFactory()), + RepoInterface: newRepoOperator(ksInformers.KubeSphereSharedInformerFactory()), + HelmReleaseInterface: newReleaseOperator(ksInformers.KubeSphereSharedInformerFactory()), + CategoryInterface: newCategoryOperator(ksInformers.KubeSphereSharedInformerFactory()), + } +} diff --git a/pkg/models/openpitrix/v2alpha1/release.go b/pkg/models/openpitrix/v2alpha1/release.go new file mode 100644 index 0000000000000000000000000000000000000000..e79ec3c3893f422644a108d79fae36a5a97f9e7a --- /dev/null +++ b/pkg/models/openpitrix/v2alpha1/release.go @@ -0,0 +1,90 @@ +/* +Copyright 2020 The KubeSphere 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 v2alpha1 + +import ( + apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/constants" + resources "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/openpitrix/helmrelease" +) + +type HelmReleaseInterface interface { + DescribeApplication(workspace, clusterName, namespace, applicationId string) (*v1alpha1.HelmRelease, error) + ListApplications(workspace, cluster, namespace string, q *query.Query) (*api.ListResult, error) +} +type releaseOperator struct { + rlsGetter resources.Interface +} + +func newReleaseOperator(ksFactory externalversions.SharedInformerFactory) HelmReleaseInterface { + c := &releaseOperator{ + rlsGetter: helmrelease.New(ksFactory), + } + + return c +} +func (c *releaseOperator) DescribeApplication(workspace, clusterName, namespace, applicationId string) (*v1alpha1.HelmRelease, error) { + ret, err := c.rlsGetter.Get("", applicationId) + + if err != nil { + klog.Error(err) + return nil, err + } + + rls := ret.(*v1alpha1.HelmRelease) + return rls, nil +} + +func (c *releaseOperator) ListApplications(workspace, cluster, namespace string, q *query.Query) (*api.ListResult, error) { + + labelSelector, err := labels.ConvertSelectorToLabelsMap(q.LabelSelector) + if err != nil { + klog.Error(err) + return nil, err + } + + extra := labels.Set{} + if workspace != "" { + extra[constants.WorkspaceLabelKey] = workspace + } + + // cluster must used with namespace + if cluster != "" { + extra[constants.ClusterNameLabelKey] = cluster + } + if namespace != "" { + extra[constants.NamespaceLabelKey] = namespace + } + if len(extra) > 0 { + q.LabelSelector = labels.Merge(labelSelector, extra).String() + } + + releases, err := c.rlsGetter.List("", q) + if err != nil && !apierrors.IsNotFound(err) { + klog.Errorf("list app release failed, error: %v", err) + return nil, err + } + + return releases, nil +} diff --git a/pkg/models/openpitrix/v2alpha1/repos.go b/pkg/models/openpitrix/v2alpha1/repos.go new file mode 100644 index 0000000000000000000000000000000000000000..9fa647d33956efa35f27e8fc01c138af7a3a2a26 --- /dev/null +++ b/pkg/models/openpitrix/v2alpha1/repos.go @@ -0,0 +1,82 @@ +/* +Copyright 2020 The KubeSphere 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 v2alpha1 + +import ( + "k8s.io/apimachinery/pkg/labels" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/constants" + resources "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/openpitrix/repo" +) + +type RepoInterface interface { + ListRepos(workspace string, q *query.Query) (*api.ListResult, error) + DescribeRepo(id string) (*v1alpha1.HelmRepo, error) +} + +type repoOperator struct { + reposGetter resources.Interface +} + +func newRepoOperator(factory externalversions.SharedInformerFactory) RepoInterface { + return &repoOperator{ + reposGetter: repo.New(factory), + } +} + +func (c *repoOperator) DescribeRepo(id string) (*v1alpha1.HelmRepo, error) { + result, err := c.reposGetter.Get("", id) + if err != nil { + klog.Error(err) + return nil, err + } + + repo := result.(*v1alpha1.HelmRepo) + repo.Status.Data = "" + + return repo, nil +} + +func (c *repoOperator) ListRepos(workspace string, qry *query.Query) (result *api.ListResult, err error) { + if workspace != "" { + labelSelector, err := labels.ConvertSelectorToLabelsMap(qry.LabelSelector) + if err != nil { + klog.Error(err) + return nil, err + } + qry.LabelSelector = labels.Merge(labelSelector, labels.Set{constants.WorkspaceLabelKey: workspace}).String() + } + result, err = c.reposGetter.List("", qry) + if err != nil { + klog.Error(err) + return nil, err + } + + // remove status data and credential + for i := range result.Items { + d := result.Items[i].(*v1alpha1.HelmRepo) + d.Status.Data = "" + d.Spec.Credential = v1alpha1.HelmRepoCredential{} + } + + return result, nil +} diff --git a/pkg/models/resources/v1alpha3/openpitrix/application/applications.go b/pkg/models/resources/v1alpha3/openpitrix/application/applications.go new file mode 100644 index 0000000000000000000000000000000000000000..18e9e699acbd214669e214dd5c5f1253e23c5017 --- /dev/null +++ b/pkg/models/resources/v1alpha3/openpitrix/application/applications.go @@ -0,0 +1,99 @@ +/* +Copyright 2019 The KubeSphere 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 application + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" + "strings" +) + +type helmApplicationsGetter struct { + informers externalversions.SharedInformerFactory +} + +func New(informers externalversions.SharedInformerFactory) v1alpha3.Interface { + return &helmApplicationsGetter{ + informers: informers, + } +} + +func (r *helmApplicationsGetter) Get(_, name string) (runtime.Object, error) { + app, err := r.informers.Application().V1alpha1().HelmApplications().Lister().Get(name) + if err != nil { + klog.Error(err) + return nil, err + } + return app, nil +} + +func (r *helmApplicationsGetter) List(_ string, query *query.Query) (*api.ListResult, error) { + var apps []*v1alpha1.HelmApplication + var err error + + apps, err = r.informers.Application().V1alpha1().HelmApplications().Lister().List(query.Selector()) + + if err != nil { + klog.Error(err) + return nil, err + } + var result []runtime.Object + for i := range apps { + result = append(result, apps[i]) + } + + return v1alpha3.DefaultList(result, query, r.compare, r.filter), nil +} + +func (r *helmApplicationsGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool { + + leftApp, ok := left.(*v1alpha1.HelmApplication) + if !ok { + return false + } + + rightApp, ok := right.(*v1alpha1.HelmApplication) + if !ok { + return false + } + switch field { + case query.FieldName: + return strings.Compare(leftApp.Spec.Name, rightApp.Spec.Name) > 0 + default: + return v1alpha3.DefaultObjectMetaCompare(leftApp.ObjectMeta, rightApp.ObjectMeta, field) + } +} + +func (r *helmApplicationsGetter) filter(object runtime.Object, filter query.Filter) bool { + application, ok := object.(*v1alpha1.HelmApplication) + if !ok { + return false + } + + switch filter.Field { + case query.FieldName: + return strings.Contains(application.Spec.Name, string(filter.Value)) + case query.FieldStatus: + return strings.Contains(application.Status.State, string(filter.Value)) + default: + return v1alpha3.DefaultObjectMetaFilter(application.ObjectMeta, filter) + } +} diff --git a/pkg/models/resources/v1alpha3/openpitrix/applicationversion/applicationsversions.go b/pkg/models/resources/v1alpha3/openpitrix/applicationversion/applicationsversions.go new file mode 100644 index 0000000000000000000000000000000000000000..96ca0f9d88aec446639cd82bda0bfb95f3615788 --- /dev/null +++ b/pkg/models/resources/v1alpha3/openpitrix/applicationversion/applicationsversions.go @@ -0,0 +1,99 @@ +/* +Copyright 2019 The KubeSphere 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 applicationversion + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" + "strings" +) + +type applicationVersionsGetter struct { + informers externalversions.SharedInformerFactory +} + +func New(informers externalversions.SharedInformerFactory) v1alpha3.Interface { + return &applicationVersionsGetter{ + informers: informers, + } +} + +func (r *applicationVersionsGetter) Get(_, name string) (runtime.Object, error) { + app, err := r.informers.Application().V1alpha1().HelmApplicationVersions().Lister().Get(name) + if err != nil { + klog.Error(err) + return nil, err + } + return app, nil +} + +func (r *applicationVersionsGetter) List(_ string, query *query.Query) (*api.ListResult, error) { + var apps []*v1alpha1.HelmApplicationVersion + var err error + + apps, err = r.informers.Application().V1alpha1().HelmApplicationVersions().Lister().List(query.Selector()) + + if err != nil { + klog.Error(err) + return nil, err + } + var result []runtime.Object + for i := range apps { + result = append(result, apps[i]) + } + + return v1alpha3.DefaultList(result, query, r.compare, r.filter), nil +} + +func (r *applicationVersionsGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool { + + leftAppVer, ok := left.(*v1alpha1.HelmApplicationVersion) + if !ok { + return false + } + + rightAppVer, ok := right.(*v1alpha1.HelmApplicationVersion) + if !ok { + return false + } + switch field { + case query.FieldName: + return strings.Compare(leftAppVer.Spec.Name, rightAppVer.Spec.Name) > 0 + default: + return v1alpha3.DefaultObjectMetaCompare(leftAppVer.ObjectMeta, rightAppVer.ObjectMeta, field) + } +} + +func (r *applicationVersionsGetter) filter(object runtime.Object, filter query.Filter) bool { + appVer, ok := object.(*v1alpha1.HelmApplicationVersion) + if !ok { + return false + } + + switch filter.Field { + case query.FieldName: + return strings.Contains(appVer.Spec.Name, string(filter.Value)) + case query.FieldStatus: + return strings.Contains(appVer.Status.State, string(filter.Value)) + default: + return v1alpha3.DefaultObjectMetaFilter(appVer.ObjectMeta, filter) + } +} diff --git a/pkg/models/resources/v1alpha3/openpitrix/category/category.go b/pkg/models/resources/v1alpha3/openpitrix/category/category.go new file mode 100644 index 0000000000000000000000000000000000000000..7bb748b2828c31b26ee25a29d3a122b784257327 --- /dev/null +++ b/pkg/models/resources/v1alpha3/openpitrix/category/category.go @@ -0,0 +1,97 @@ +/* +Copyright 2019 The KubeSphere 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 category + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" + "strings" +) + +type helmCategoriesGetter struct { + informers externalversions.SharedInformerFactory +} + +func New(informers externalversions.SharedInformerFactory) v1alpha3.Interface { + return &helmCategoriesGetter{ + informers: informers, + } +} + +func (r *helmCategoriesGetter) Get(_, name string) (runtime.Object, error) { + app, err := r.informers.Application().V1alpha1().HelmCategories().Lister().Get(name) + if err != nil { + klog.Error(err) + return nil, err + } + return app, nil +} + +func (r *helmCategoriesGetter) List(_ string, query *query.Query) (*api.ListResult, error) { + var ctg []*v1alpha1.HelmCategory + var err error + + ctg, err = r.informers.Application().V1alpha1().HelmCategories().Lister().List(query.Selector()) + + if err != nil { + klog.Error(err) + return nil, err + } + var result []runtime.Object + for i := range ctg { + result = append(result, ctg[i]) + } + + return v1alpha3.DefaultList(result, query, r.compare, r.filter), nil +} + +func (r *helmCategoriesGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool { + + ctg1, ok := left.(*v1alpha1.HelmCategory) + if !ok { + return false + } + + ctg2, ok := right.(*v1alpha1.HelmCategory) + if !ok { + return false + } + switch field { + case query.FieldName: + return strings.Compare(ctg1.Spec.Name, ctg2.Spec.Name) > 0 + default: + return v1alpha3.DefaultObjectMetaCompare(ctg1.ObjectMeta, ctg2.ObjectMeta, field) + } +} + +func (r *helmCategoriesGetter) filter(object runtime.Object, filter query.Filter) bool { + application, ok := object.(*v1alpha1.HelmCategory) + if !ok { + return false + } + + switch filter.Field { + case query.FieldName: + return strings.Contains(application.Spec.Name, string(filter.Value)) + default: + return v1alpha3.DefaultObjectMetaFilter(application.ObjectMeta, filter) + } +} diff --git a/pkg/models/resources/v1alpha3/openpitrix/helmrelease/releases.go b/pkg/models/resources/v1alpha3/openpitrix/helmrelease/releases.go new file mode 100644 index 0000000000000000000000000000000000000000..2c23240ddf748286f0927f458b07bdc9cebc1fc3 --- /dev/null +++ b/pkg/models/resources/v1alpha3/openpitrix/helmrelease/releases.go @@ -0,0 +1,99 @@ +/* +Copyright 2019 The KubeSphere 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 helmrelease + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" + "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" + "strings" +) + +type helmReleasesGetter struct { + informers externalversions.SharedInformerFactory +} + +func New(informers externalversions.SharedInformerFactory) v1alpha3.Interface { + return &helmReleasesGetter{ + informers: informers, + } +} + +func (r *helmReleasesGetter) Get(_, name string) (runtime.Object, error) { + app, err := r.informers.Application().V1alpha1().HelmReleases().Lister().Get(name) + if err != nil { + klog.Error(err) + return nil, err + } + return app, nil +} + +func (r *helmReleasesGetter) List(_ string, query *query.Query) (*api.ListResult, error) { + var rls []*v1alpha1.HelmRelease + var err error + + rls, err = r.informers.Application().V1alpha1().HelmReleases().Lister().List(query.Selector()) + + if err != nil { + klog.Error(err) + return nil, err + } + var result []runtime.Object + for i := range rls { + result = append(result, rls[i]) + } + + return v1alpha3.DefaultList(result, query, r.compare, r.filter), nil +} + +func (r *helmReleasesGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool { + + leftRls, ok := left.(*v1alpha1.HelmRelease) + if !ok { + return false + } + + rightRls, ok := right.(*v1alpha1.HelmRelease) + if !ok { + return false + } + switch field { + case query.FieldName: + return strings.Compare(leftRls.Spec.Name, rightRls.Spec.Name) > 0 + default: + return v1alpha3.DefaultObjectMetaCompare(leftRls.ObjectMeta, rightRls.ObjectMeta, field) + } +} + +func (r *helmReleasesGetter) filter(object runtime.Object, filter query.Filter) bool { + rls, ok := object.(*v1alpha1.HelmRelease) + if !ok { + return false + } + + switch filter.Field { + case query.FieldName: + return strings.Contains(rls.Spec.Name, string(filter.Value)) + case query.FieldStatus: + return strings.Contains(rls.Status.State, string(filter.Value)) + default: + return v1alpha3.DefaultObjectMetaFilter(rls.ObjectMeta, filter) + } +} diff --git a/pkg/models/resources/v1alpha3/openpitrix/repo/repo.go b/pkg/models/resources/v1alpha3/openpitrix/repo/repo.go new file mode 100644 index 0000000000000000000000000000000000000000..3fa140e319be69ffa00f3b1422484894d139d18b --- /dev/null +++ b/pkg/models/resources/v1alpha3/openpitrix/repo/repo.go @@ -0,0 +1,91 @@ +/* +Copyright 2019 The KubeSphere 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 repo + +import ( + "k8s.io/apimachinery/pkg/runtime" + "kubesphere.io/kubesphere/pkg/api" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/apiserver/query" + ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions" + "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3" + "strings" +) + +type reposGetter struct { + ksInformer ksinformers.SharedInformerFactory +} + +func New(ksinformer ksinformers.SharedInformerFactory) v1alpha3.Interface { + return &reposGetter{ksInformer: ksinformer} +} + +func (d *reposGetter) Get(_, name string) (runtime.Object, error) { + return d.ksInformer.Application().V1alpha1().HelmRepos().Lister().Get(name) +} + +func (d *reposGetter) List(_ string, query *query.Query) (*api.ListResult, error) { + var repos []*v1alpha1.HelmRepo + var err error + repos, err = d.ksInformer.Application().V1alpha1().HelmRepos().Lister().List(query.Selector()) + + if err != nil { + return nil, err + } + + result := make([]runtime.Object, 0, len(repos)) + for _, user := range repos { + result = append(result, user) + } + + return v1alpha3.DefaultList(result, query, d.compare, d.filter), nil +} + +func (d *reposGetter) compare(left runtime.Object, right runtime.Object, field query.Field) bool { + + repo1, ok := left.(*v1alpha1.HelmRepo) + if !ok { + return false + } + + repo2, ok := right.(*v1alpha1.HelmRepo) + if !ok { + return false + } + + switch field { + case query.FieldName: + return strings.Compare(repo1.Spec.Name, repo2.Spec.Name) > 0 + default: + return v1alpha3.DefaultObjectMetaCompare(repo1.ObjectMeta, repo2.ObjectMeta, field) + } +} + +func (d *reposGetter) filter(object runtime.Object, filter query.Filter) bool { + repo, ok := object.(*v1alpha1.HelmRepo) + + if !ok { + return false + } + + switch filter.Field { + case query.FieldName: + return strings.Contains(repo.Spec.Name, string(filter.Value)) + default: + return v1alpha3.DefaultObjectMetaFilter(repo.ObjectMeta, filter) + } +} diff --git a/pkg/models/resources/v1alpha3/resource/resource.go b/pkg/models/resources/v1alpha3/resource/resource.go index 14bb881ca620ec61b456b64eed4462ee3731a06b..6590ba07a2dde5840a4fce81d89c55001b45f89d 100644 --- a/pkg/models/resources/v1alpha3/resource/resource.go +++ b/pkg/models/resources/v1alpha3/resource/resource.go @@ -18,7 +18,6 @@ package resource import ( "errors" - snapshotv1beta1 "github.com/kubernetes-csi/external-snapshotter/client/v3/apis/volumesnapshot/v1beta1" rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/runtime" diff --git a/pkg/models/tenant/tenant.go b/pkg/models/tenant/tenant.go index 0b782b17b39bad9fd9e320ba2f7490833eb02184..731d3492cfea1e6d08b2d196b105fe60899fb21f 100644 --- a/pkg/models/tenant/tenant.go +++ b/pkg/models/tenant/tenant.go @@ -61,7 +61,6 @@ import ( eventsclient "kubesphere.io/kubesphere/pkg/simple/client/events" loggingclient "kubesphere.io/kubesphere/pkg/simple/client/logging" monitoringclient "kubesphere.io/kubesphere/pkg/simple/client/monitoring" - opclient "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" "kubesphere.io/kubesphere/pkg/utils/stringutils" ) @@ -106,7 +105,7 @@ type tenantOperator struct { mo monitoring.MonitoringOperator } -func New(informers informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface, evtsClient eventsclient.Client, loggingClient loggingclient.Client, auditingclient auditingclient.Client, am am.AccessManagementInterface, authorizer authorizer.Authorizer, monitoringclient monitoringclient.Interface, opClient opclient.Client, resourceGetter *resourcev1alpha3.ResourceGetter) Interface { +func New(informers informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface, evtsClient eventsclient.Client, loggingClient loggingclient.Client, auditingclient auditingclient.Client, am am.AccessManagementInterface, authorizer authorizer.Authorizer, monitoringclient monitoringclient.Interface, resourceGetter *resourcev1alpha3.ResourceGetter) Interface { return &tenantOperator{ am: am, authorizer: authorizer, @@ -116,7 +115,7 @@ func New(informers informers.InformerFactory, k8sclient kubernetes.Interface, ks events: events.NewEventsOperator(evtsClient), lo: logging.NewLoggingOperator(loggingClient), auditing: auditing.NewEventsOperator(auditingclient), - mo: monitoring.NewMonitoringOperator(monitoringclient, nil, k8sclient, informers, opClient, resourceGetter), + mo: monitoring.NewMonitoringOperator(monitoringclient, nil, k8sclient, informers, resourceGetter), } } diff --git a/pkg/models/tenant/tenent_test.go b/pkg/models/tenant/tenent_test.go index a9fad144ad4a9e28ceeb80da334f7ae1e6343ba8..2f31eecc4daa5632399df7cea9191f4d50d0613f 100644 --- a/pkg/models/tenant/tenent_test.go +++ b/pkg/models/tenant/tenent_test.go @@ -541,5 +541,5 @@ func prepare() Interface { amOperator := am.NewOperator(ksClient, k8sClient, fakeInformerFactory) authorizer := rbac.NewRBACAuthorizer(amOperator) - return New(fakeInformerFactory, k8sClient, ksClient, nil, nil, nil, amOperator, authorizer, nil, nil, nil) + return New(fakeInformerFactory, k8sClient, ksClient, nil, nil, nil, amOperator, authorizer, nil, nil) } diff --git a/pkg/simple/client/openpitrix/helmrepoindex/interface.go b/pkg/simple/client/openpitrix/helmrepoindex/interface.go new file mode 100644 index 0000000000000000000000000000000000000000..14d3aceb720daff98331f77b917dc653ec5b26da --- /dev/null +++ b/pkg/simple/client/openpitrix/helmrepoindex/interface.go @@ -0,0 +1,36 @@ +/* +Copyright 2020 The KubeSphere 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 helmrepoindex + +import "time" + +type VersionInterface interface { + GetName() string + GetVersion() string + GetAppVersion() string + GetDescription() string + GetUrls() string + GetVersionName() string + GetIcon() string + GetHome() string + GetSources() string + GetKeywords() string + GetMaintainers() string + GetScreenshots() string + GetPackageName() string + GetCreateTime() time.Time +} diff --git a/pkg/simple/client/openpitrix/helmrepoindex/load_chart.go b/pkg/simple/client/openpitrix/helmrepoindex/load_chart.go new file mode 100644 index 0000000000000000000000000000000000000000..229db9fc338e55e5e5ece3e4a303c6eacf7d1abf --- /dev/null +++ b/pkg/simple/client/openpitrix/helmrepoindex/load_chart.go @@ -0,0 +1,104 @@ +/* +Copyright 2020 The KubeSphere 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 helmrepoindex + +import ( + "bytes" + "context" + "fmt" + "helm.sh/helm/v3/pkg/getter" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/simple/client/s3" + "net/url" + "strings" + "time" +) + +func parseS3Url(parse *url.URL) (region, endpoint, bucket, path string) { + if strings.HasPrefix(parse.Host, "s3.") { + region = strings.Split(parse.Host, ".")[1] + endpoint = fmt.Sprintf("https://%s", parse.Host) + } else { + region = "us-east-1" + endpoint = fmt.Sprintf("http://%s", parse.Host) + } + parts := strings.Split(strings.TrimPrefix(parse.Path, "/"), "/") + if len(parts) > 0 { + bucket = parts[0] + path = strings.Join(parts[1:], "/") + } else { + bucket = parse.Path + } + + return region, endpoint, bucket, path +} + +func loadData(ctx context.Context, u string, cred *v1alpha1.HelmRepoCredential) (*bytes.Buffer, error) { + parsedURL, err := url.Parse(u) + if err != nil { + return nil, err + } + var resp *bytes.Buffer + if strings.HasPrefix(u, "s3://") { + region, endpoint, bucket, p := parseS3Url(parsedURL) + client, err := s3.NewS3Client(&s3.Options{ + Endpoint: endpoint, + Bucket: bucket, + Region: region, + AccessKeyID: cred.AccessKeyID, + SecretAccessKey: cred.SecretAccessKey, + DisableSSL: !strings.HasPrefix(region, "https://"), + ForcePathStyle: true, + }) + + if err != nil { + return nil, err + } + + data, err := client.Read(p) + if err != nil { + return nil, err + } + + resp = bytes.NewBuffer(data) + } else { + skipTLS := true + if cred.InsecureSkipTLSVerify != nil && !*cred.InsecureSkipTLSVerify { + skipTLS = false + } + + indexURL := parsedURL.String() + // TODO add user-agent + g, _ := getter.NewHTTPGetter() + resp, err = g.Get(indexURL, + getter.WithTimeout(5*time.Minute), + getter.WithURL(u), + getter.WithInsecureSkipVerifyTLS(skipTLS), + getter.WithTLSClientConfig(cred.CertFile, cred.KeyFile, cred.CAFile), + getter.WithBasicAuth(cred.Username, cred.Password), + ) + if err != nil { + return nil, err + } + } + + return resp, nil +} + +func LoadChart(ctx context.Context, u string, cred *v1alpha1.HelmRepoCredential) (*bytes.Buffer, error) { + return loadData(ctx, u, cred) +} diff --git a/pkg/simple/client/openpitrix/helmrepoindex/load_package.go b/pkg/simple/client/openpitrix/helmrepoindex/load_package.go new file mode 100644 index 0000000000000000000000000000000000000000..6df3f860604d6c0a00a47180a550d40279032fba --- /dev/null +++ b/pkg/simple/client/openpitrix/helmrepoindex/load_package.go @@ -0,0 +1,96 @@ +/* +Copyright 2020 The KubeSphere 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 helmrepoindex + +import ( + "bytes" + "encoding/json" + "fmt" + "helm.sh/helm/v3/pkg/repo" + "k8s.io/klog" + "strings" + "time" + + "helm.sh/helm/v3/pkg/chart/loader" +) + +func LoadPackage(pkg []byte) (VersionInterface, error) { + p, err := loader.LoadArchive(bytes.NewReader(pkg)) + if err != nil { + klog.Errorf("Failed to load package, error: %+v", err) + return nil, err + } + return HelmVersionWrapper{ChartVersion: &repo.ChartVersion{Metadata: p.Metadata}}, nil +} + +type HelmVersionWrapper struct { + *repo.ChartVersion +} + +func (h HelmVersionWrapper) GetIcon() string { return h.ChartVersion.Icon } +func (h HelmVersionWrapper) GetName() string { return h.ChartVersion.Name } +func (h HelmVersionWrapper) GetHome() string { return h.ChartVersion.Home } +func (h HelmVersionWrapper) GetVersion() string { return h.ChartVersion.Version } +func (h HelmVersionWrapper) GetAppVersion() string { return h.ChartVersion.AppVersion } +func (h HelmVersionWrapper) GetDescription() string { return h.ChartVersion.Description } +func (h HelmVersionWrapper) GetCreateTime() time.Time { return h.ChartVersion.Created } +func (h HelmVersionWrapper) GetUrls() string { + if len(h.ChartVersion.URLs) == 0 { + return "" + } + return h.ChartVersion.URLs[0] +} + +func (h HelmVersionWrapper) GetSources() string { + if len(h.ChartVersion.Sources) == 0 { + return "" + } + s, _ := json.Marshal(h.ChartVersion.Sources) + return string(s) +} + +func (h HelmVersionWrapper) GetKeywords() string { + return strings.Join(h.ChartVersion.Keywords, ",") +} + +func (h HelmVersionWrapper) GetMaintainers() string { + if len(h.ChartVersion.Maintainers) == 0 { + return "" + } + s, _ := json.Marshal(h.ChartVersion.Maintainers) + return string(s) +} + +func (h HelmVersionWrapper) GetScreenshots() string { + return "" +} + +func (h HelmVersionWrapper) GetVersionName() string { + versionName := h.GetVersion() + if h.GetAppVersion() != "" { + versionName += fmt.Sprintf(" [%s]", h.GetAppVersion()) + } + return versionName +} + +func (h HelmVersionWrapper) GetPackageName() string { + file := h.GetUrls() + if len(file) == 0 { + return fmt.Sprintf("%s-%s.tgz", h.Name, h.Version) + } + return file +} diff --git a/pkg/simple/client/openpitrix/helmrepoindex/repo_index.go b/pkg/simple/client/openpitrix/helmrepoindex/repo_index.go new file mode 100644 index 0000000000000000000000000000000000000000..43d796bae0fb37a02bbd75910ebf67e26af5324f --- /dev/null +++ b/pkg/simple/client/openpitrix/helmrepoindex/repo_index.go @@ -0,0 +1,270 @@ +/* +Copyright 2020 The KubeSphere 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 helmrepoindex + +import ( + "bytes" + "compress/zlib" + "context" + "encoding/base64" + "encoding/json" + "fmt" + helmrepo "helm.sh/helm/v3/pkg/repo" + "io" + "io/ioutil" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/utils/idutils" + "sigs.k8s.io/yaml" + "strings" + "time" +) + +const IndexYaml = "index.yaml" + +func LoadRepoIndex(ctx context.Context, u string, cred *v1alpha1.HelmRepoCredential) (*helmrepo.IndexFile, error) { + + if !strings.HasSuffix(u, "/") { + u = fmt.Sprintf("%s/%s", u, IndexYaml) + } else { + u = fmt.Sprintf("%s%s", u, IndexYaml) + } + + resp, err := loadData(ctx, u, cred) + if err != nil { + return nil, err + } + + indexFile, err := loadIndex(resp.Bytes()) + if err != nil { + return nil, err + } + + return indexFile, nil +} + +// loadIndex loads an index file and does minimal validity checking. +// +// This will fail if API Version is not set (ErrNoAPIVersion) or if the unmarshal fails. +func loadIndex(data []byte) (*helmrepo.IndexFile, error) { + i := &helmrepo.IndexFile{} + if err := yaml.UnmarshalStrict(data, i); err != nil { + return i, err + } + i.SortEntries() + if i.APIVersion == "" { + return i, helmrepo.ErrNoAPIVersion + } + return i, nil +} + +// merge new index with index from crd +func MergeRepoIndex(index *helmrepo.IndexFile, existsSavedIndex *SavedIndex) *SavedIndex { + saved := &SavedIndex{} + if index == nil { + return existsSavedIndex + } + + saved.Applications = make(map[string]*Application) + if existsSavedIndex != nil { + for name := range existsSavedIndex.Applications { + saved.Applications[name] = existsSavedIndex.Applications[name] + } + } + + // just copy fields from index + saved.APIVersion = index.APIVersion + saved.Generated = index.Generated + saved.PublicKeys = index.PublicKeys + + allNames := make(map[string]bool, len(index.Entries)) + for name, versions := range index.Entries { + // add new applications + if application, exists := saved.Applications[name]; !exists { + application = &Application{ + Name: name, + ApplicationId: idutils.GetUuid36(v1alpha1.HelmApplicationIdPrefix), + Description: versions[0].Description, + Icon: versions[0].Icon, + } + + charts := make([]*ChartVersion, 0, len(versions)) + for ind := range versions { + chart := &ChartVersion{ + ApplicationId: application.ApplicationId, + ApplicationVersionId: idutils.GetUuid36(v1alpha1.HelmApplicationVersionIdPrefix), + ChartVersion: *versions[ind], + } + charts = append(charts, chart) + } + application.Charts = charts + saved.Applications[name] = application + } else { + // update exists applications + savedChartVersion := make(map[string]struct{}) + for _, ver := range application.Charts { + savedChartVersion[ver.Version] = struct{}{} + } + charts := application.Charts + for _, ver := range versions { + // add new chart version + if _, exists := savedChartVersion[ver.Version]; !exists { + chart := &ChartVersion{ + ApplicationId: application.ApplicationId, + ApplicationVersionId: idutils.GetUuid36(v1alpha1.HelmApplicationVersionIdPrefix), + ChartVersion: *ver, + } + charts = append(charts, chart) + } + application.Charts = charts + saved.Applications[name] = application + } + } + allNames[name] = true + } + + for name := range saved.Applications { + if _, exists := allNames[name]; !exists { + delete(saved.Applications, name) + } + } + + return saved +} + +func (i *SavedIndex) GetApplicationVersion(appId, versionId string) *v1alpha1.HelmApplicationVersion { + for _, app := range i.Applications { + if app.ApplicationId == appId { + for _, ver := range app.Charts { + if ver.ApplicationVersionId == versionId { + version := &v1alpha1.HelmApplicationVersion{ + ObjectMeta: metav1.ObjectMeta{ + Name: versionId, + Labels: map[string]string{ + constants.ChartApplicationIdLabelKey: appId, + }, + }, + Spec: v1alpha1.HelmApplicationVersionSpec{ + URLs: ver.URLs, + Digest: ver.Digest, + Metadata: &v1alpha1.Metadata{ + Name: ver.Name, + AppVersion: ver.AppVersion, + Version: ver.Version, + Annotations: ver.Annotations, + }, + }, + } + return version + } + } + } + } + return nil +} + +type SavedIndex struct { + APIVersion string `json:"apiVersion"` + Generated time.Time `json:"generated"` + Applications map[string]*Application `json:"apps"` + PublicKeys []string `json:"publicKeys,omitempty"` + + // Annotations are additional mappings uninterpreted by Helm. They are made available for + // other applications to add information to the index file. + Annotations map[string]string `json:"annotations,omitempty"` +} + +func ByteArrayToSavedIndex(data []byte) (*SavedIndex, error) { + ret := &SavedIndex{} + if len(data) == 0 { + return ret, nil + } + + enc := base64.URLEncoding + buf := make([]byte, enc.DecodedLen(len(data))) + n, err := enc.Decode(buf, data) + if err != nil { + return nil, err + } + buf = buf[:n] + + r, err := zlib.NewReader(bytes.NewBuffer(buf)) + if err != nil { + return nil, err + } + r.Close() + b, err := ioutil.ReadAll(r) + + if err != nil && err != io.EOF { + return nil, err + } + + err = json.Unmarshal(b, ret) + if err != nil { + return nil, err + } + return ret, nil +} + +func (i *SavedIndex) Bytes() ([]byte, error) { + + d, err := json.Marshal(i) + if err != nil { + return nil, err + } + + buf := &bytes.Buffer{} + w := zlib.NewWriter(buf) + _, err = w.Write(d) + if err != nil { + return nil, err + } + err = w.Close() + if err != nil { + return nil, err + } + encSrc := buf.Bytes() + + enc := base64.URLEncoding + ret := make([]byte, enc.EncodedLen(len(encSrc))) + + enc.Encode(ret, encSrc) + return ret, nil +} + +// chart version with app id and app version id +type ChartVersion struct { + // Do not save ApplicationId into crd + ApplicationId string `json:"-"` + ApplicationVersionId string `json:"verId"` + helmrepo.ChartVersion `json:",inline"` +} + +type Application struct { + // application name + Name string `json:"name"` + ApplicationId string `json:"appId"` + // chart description + Description string `json:"desc"` + // application status + Status string `json:"status"` + // The URL to an icon file. + Icon string `json:"icon,omitempty"` + + Charts []*ChartVersion `json:"charts"` +} diff --git a/pkg/simple/client/openpitrix/helmrepoindex/repo_index_test.go b/pkg/simple/client/openpitrix/helmrepoindex/repo_index_test.go new file mode 100644 index 0000000000000000000000000000000000000000..6ea52af19512539937f6d7e7fcb10823b28dadc6 --- /dev/null +++ b/pkg/simple/client/openpitrix/helmrepoindex/repo_index_test.go @@ -0,0 +1,53 @@ +/* +Copyright 2020 The KubeSphere 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 helmrepoindex + +import ( + "context" + "fmt" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "strings" + "testing" +) + +func TestLoadRepo(t *testing.T) { + + u := "https://charts.kubesphere.io/main" + + index, err := LoadRepoIndex(context.TODO(), u, &v1alpha1.HelmRepoCredential{}) + if err != nil { + t.Errorf("load repo failed, err: %s", err) + t.Failed() + return + } + + for _, entry := range index.Entries { + chartUrl := entry[0].URLs[0] + + if !(strings.HasPrefix(chartUrl, "https://") || strings.HasPrefix(chartUrl, "http://")) { + chartUrl = fmt.Sprintf("%s/%s", u, chartUrl) + } + chartData, err := LoadChart(context.TODO(), chartUrl, &v1alpha1.HelmRepoCredential{}) + if err != nil { + t.Errorf("load chart data failed, err: %s", err) + t.Failed() + } + _ = chartData + break + } + +} diff --git a/pkg/simple/client/openpitrix/helmwrapper/helm_wrapper.go b/pkg/simple/client/openpitrix/helmwrapper/helm_wrapper.go new file mode 100644 index 0000000000000000000000000000000000000000..86d1d3c5d8647b25ee6d71ac8d52c81bc06b867d --- /dev/null +++ b/pkg/simple/client/openpitrix/helmwrapper/helm_wrapper.go @@ -0,0 +1,470 @@ +/* +Copyright 2020 The KubeSphere 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 helmwrapper + +import ( + "bytes" + "encoding/json" + "fmt" + "k8s.io/klog" + kpath "k8s.io/utils/path" + "kubesphere.io/kubesphere/pkg/utils/idutils" + "os" + "os/exec" + "path" + "path/filepath" + "strings" + "time" +) + +var ( + UninstallNotFoundFormat = "Error: uninstall: Release not loaded: %s: release: not found" + StatusNotFoundFormat = "Error: release: not found" +) + +type HelmRes struct { + Message string +} + +type releaseStatus struct { + Name string `json:"name,omitempty"` + Info *Info `json:"info,omitempty"` +} + +// copy from helm +// Info describes release information. +type Info struct { + // FirstDeployed is when the release was first deployed. + FirstDeployed time.Time `json:"first_deployed,omitempty"` + // LastDeployed is when the release was last deployed. + LastDeployed time.Time `json:"last_deployed,omitempty"` + // Deleted tracks when this object was deleted. + Deleted time.Time `json:"deleted"` + // Description is human-friendly "log entry" about this release. + Description string `json:"description,omitempty"` + // Status is the current state of the release + Status string `json:"status,omitempty"` + // Contains the rendered templates/NOTES.txt if available + Notes string `json:"notes,omitempty"` +} + +type helmRlsStatus struct { + Name string `json:"name"` + Namespace string `json:"namespace"` + Revision int `json:"revision"` + Status string `json:"status"` + Chart string `json:"chart"` + AppVersion string `json:"app_version"` +} + +var _ HelmWrapper = &helmWrapper{} + +type HelmWrapper interface { + Install(chartName, chartData, values string) (HelmRes, error) + // upgrade a release + Upgrade(chartName, chartData, values string) (HelmRes, error) + Uninstall() (HelmRes, error) + // Get manifests + Manifest() (string, error) +} + +func (c *helmWrapper) Status() (status *releaseStatus, err error) { + if err = c.ensureWorkspace(); err != nil { + return nil, err + } + defer c.cleanup() + + stdout := &bytes.Buffer{} + stderr := &bytes.Buffer{} + cmd := exec.Cmd{ + Path: c.cmdPath, + Dir: c.Workspace(), + Args: []string{ + c.cmdPath, + "status", + fmt.Sprintf("%s", c.ReleaseName), + "--namespace", + c.Namespace, + "--output", + "json", + }, + Stderr: stderr, + Stdout: stdout, + } + + if c.kubeConfigPath() != "" { + cmd.Args = append(cmd.Args, "--kubeconfig", c.kubeConfigPath()) + } + + err = cmd.Run() + + if err != nil { + klog.Errorf("namespace: %s, name: %s, run command failed, stderr: %s, error: %v", c.Namespace, c.ReleaseName, stderr, err) + return + } else { + klog.V(2).Infof("namespace: %s, name: %s, run command success", c.Namespace, c.ReleaseName) + klog.V(8).Infof("namespace: %s, name: %s, run command success, stdout: %s", c.Namespace, c.ReleaseName, stdout) + } + + status = &releaseStatus{} + err = json.Unmarshal(stdout.Bytes(), status) + if err != nil { + klog.Errorf("namespace: %s, name: %s, json unmarshal failed, error: %s", c.Namespace, c.ReleaseName, err) + } + + return +} + +func (c *helmWrapper) Workspace() string { + if c.workspaceSuffix == "" { + return path.Join(c.base, fmt.Sprintf("%s_%s", c.Namespace, c.ReleaseName)) + } else { + return path.Join(c.base, fmt.Sprintf("%s_%s_%s", c.Namespace, c.ReleaseName, c.workspaceSuffix)) + } +} + +type helmWrapper struct { + // KubeConfig string + Kubeconfig string + Namespace string + // helm release name + ReleaseName string + ChartName string + + // helm cmd path + cmdPath string + // base should be /dev/shm on linux + base string + workspaceSuffix string + dryRun bool + mock bool +} + +func (c *helmWrapper) kubeConfigPath() string { + if len(c.Kubeconfig) == 0 { + return "" + } + return path.Join(c.Workspace(), "kube.config") +} + +func (c *helmWrapper) chartPath() string { + return filepath.Join(c.Workspace(), fmt.Sprintf("%s.tgz", c.ChartName)) +} + +func (c *helmWrapper) cleanup() { + if err := os.RemoveAll(c.Workspace()); err != nil { + klog.Errorf("remove dir %s faield, error: %s", c.Workspace(), err) + } +} + +func (c *helmWrapper) Set(options ...Option) { + for _, option := range options { + option(c) + } +} + +type Option func(*helmWrapper) + +func SetDryRun(dryRun bool) Option { + return func(wrapper *helmWrapper) { + wrapper.dryRun = dryRun + } +} + +func SetMock(mock bool) Option { + return func(wrapper *helmWrapper) { + wrapper.mock = mock + } +} + +func NewHelmWrapper(kubeconfig, ns, rls string, options ...Option) *helmWrapper { + c := &helmWrapper{ + Kubeconfig: kubeconfig, + Namespace: ns, + ReleaseName: rls, + base: workspaceBase, + cmdPath: helmPath, + workspaceSuffix: idutils.GetUuid36(""), + } + + for _, option := range options { + option(c) + } + + return c +} + +// ensureWorkspace check whether workspace exists or not. +// If not exists, create workspace dir. +func (c *helmWrapper) ensureWorkspace() error { + if exists, err := kpath.Exists(kpath.CheckFollowSymlink, c.Workspace()); err != nil { + klog.Errorf("check dir %s failed, error: %s", c.Workspace(), err) + return err + } else if !exists { + err = os.MkdirAll(c.Workspace(), os.ModeDir|os.ModePerm) + if err != nil { + klog.Errorf("mkdir %s failed, error: %s", c.Workspace(), err) + return err + } + } + + if len(c.Kubeconfig) > 0 { + kubeFile, err := os.OpenFile(c.kubeConfigPath(), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0600) + if err != nil { + return err + } + _, err = kubeFile.WriteString(c.Kubeconfig) + if err != nil { + return err + } + kubeFile.Close() + } + + return nil +} + +// create chart dir in workspace +// write values.yaml into workspace +func (c *helmWrapper) createChart(chartName, chartData, values string) error { + c.ChartName = chartName + + // write chart + f, err := os.Create(path.Join(c.chartPath())) + + if err != nil { + return err + } + + _, err = f.Write([]byte(chartData)) + + if err != nil { + return err + } + f.Close() + + // write values + f, err = os.Create(path.Join(c.Workspace(), "values.yaml")) + if err != nil { + return err + } + + _, err = f.WriteString(values) + if err != nil { + return err + } + + f.Close() + return nil +} + +func (c *helmWrapper) Uninstall() (res HelmRes, err error) { + start := time.Now() + defer func() { + klog.V(2).Infof("run command end, namespace: %s, name: %s elapsed: %v", c.Namespace, c.ReleaseName, time.Now().Sub(start)) + }() + + if err = c.ensureWorkspace(); err != nil { + return + } + defer c.cleanup() + + stderr := &bytes.Buffer{} + stdout := &bytes.Buffer{} + cmd := exec.Cmd{ + Path: c.cmdPath, + Dir: c.Workspace(), + Stdout: stdout, + Stderr: stderr, + } + + cmd.Args = make([]string, 0, 10) + + // only for mock + if c.mock { + cmd.Path = os.Args[0] + cmd.Args = []string{os.Args[0], "-test.run=TestHelperProcess", "--"} + cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} + } + + cmd.Args = append(cmd.Args, c.cmdPath, + "uninstall", + c.ReleaseName, + "--namespace", + c.Namespace) + + if c.dryRun { + cmd.Args = append(cmd.Args, "--dry-run") + } + + if c.kubeConfigPath() != "" { + cmd.Args = append(cmd.Args, "--kubeconfig", c.kubeConfigPath()) + } + + klog.V(4).Infof("run command: %s", cmd.String()) + err = cmd.Run() + + if err != nil { + eMsg := strings.TrimSpace(stderr.String()) + if fmt.Sprintf(UninstallNotFoundFormat, c.ReleaseName) == eMsg { + return res, nil + } + klog.Errorf("run command failed, stderr: %s, error: %v", eMsg, err) + res.Message = eMsg + } else { + klog.V(2).Infof("namespace: %s, name: %s, run command success", c.Namespace, c.ReleaseName) + klog.V(8).Infof("namespace: %s, name: %s, run command success, stdout: %s", c.Namespace, c.ReleaseName, stdout) + } + + return +} + +func (c *helmWrapper) Upgrade(chartName, chartData, values string) (res HelmRes, err error) { + // TODO: check release status first + if true { + return c.install(chartName, chartData, values, true) + } else { + klog.V(3).Infof("release %s/%s not exists, cannot upgrade it, install a new one", c.Namespace, c.ReleaseName) + return + } +} + +func (c *helmWrapper) Install(chartName, chartData, values string) (res HelmRes, err error) { + return c.install(chartName, chartData, values, false) +} + +func (c *helmWrapper) install(chartName, chartData, values string, upgrade bool) (res HelmRes, err error) { + if klog.V(2) { + start := time.Now() + defer func() { + klog.V(2).Infof("run command end, namespace: %s, name: %s elapsed: %v", c.Namespace, c.ReleaseName, time.Now().Sub(start)) + }() + } + + if err = c.ensureWorkspace(); err != nil { + return + } + defer c.cleanup() + + if err = c.createChart(chartName, chartData, values); err != nil { + return + } + klog.V(8).Infof("namespace: %s, name: %s, chart values: %s", c.Namespace, c.ReleaseName, values) + + stdout := &bytes.Buffer{} + stderr := &bytes.Buffer{} + + cmd := exec.Cmd{ + Path: c.cmdPath, + Dir: c.Workspace(), + Stdout: stdout, + Stderr: stderr, + } + + cmd.Args = make([]string, 0, 10) + + // only for mock + if c.mock { + cmd.Path = os.Args[0] + cmd.Args = []string{os.Args[0], "-test.run=TestHelperProcess", "--"} + cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"} + } + + cmd.Args = append(cmd.Args, c.cmdPath) + if upgrade { + cmd.Args = append(cmd.Args, "upgrade") + } else { + cmd.Args = append(cmd.Args, "install") + } + + cmd.Args = append(cmd.Args, c.ReleaseName, c.chartPath(), "--namespace", c.Namespace) + + if len(values) > 0 { + cmd.Args = append(cmd.Args, "--values", path.Join(c.Workspace(), "values.yaml")) + } + + if c.dryRun { + cmd.Args = append(cmd.Args, "--dry-run") + } + + if c.kubeConfigPath() != "" { + cmd.Args = append(cmd.Args, "--kubeconfig", c.kubeConfigPath()) + } + + if klog.V(8) { + // output debug info + cmd.Args = append(cmd.Args, "--debug") + } + + klog.V(4).Infof("run command: %s", cmd.String()) + err = cmd.Run() + + if err != nil { + klog.Errorf("namespace: %s, name: %s, run command: %s failed, stderr: %s, error: %v", c.Namespace, c.ReleaseName, cmd.String(), stderr, err) + res.Message = stderr.String() + } else { + klog.V(2).Infof("namespace: %s, name: %s, run command success", c.Namespace, c.ReleaseName) + klog.V(8).Infof("namespace: %s, name: %s, run command success, stdout: %s", c.Namespace, c.ReleaseName, stdout) + } + + return +} + +func (c *helmWrapper) Manifest() (manifest string, err error) { + if err = c.ensureWorkspace(); err != nil { + return "", err + } + defer c.cleanup() + + stdout := &bytes.Buffer{} + stderr := &bytes.Buffer{} + cmd := exec.Cmd{ + Path: c.cmdPath, + Dir: c.Workspace(), + Args: []string{ + c.cmdPath, + "get", + "manifest", + c.ReleaseName, + "--namespace", + c.Namespace, + }, + Stderr: stderr, + Stdout: stdout, + } + + if c.kubeConfigPath() != "" { + cmd.Args = append(cmd.Args, "--kubeconfig", c.kubeConfigPath()) + } + + if klog.V(8) { + // output debug info + cmd.Args = append(cmd.Args, "--debug") + } + + klog.V(4).Infof("run command: %s", cmd.String()) + err = cmd.Run() + + if err != nil { + klog.Errorf("namespace: %s, name: %s, run command failed, stderr: %s, error: %v", c.Namespace, c.ReleaseName, stderr, err) + return "", err + } else { + klog.V(2).Infof("namespace: %s, name: %s, run command success", c.Namespace, c.ReleaseName) + klog.V(8).Infof("namespace: %s, name: %s, run command success, stdout: %s", c.Namespace, c.ReleaseName, stdout) + } + + return stdout.String(), nil +} diff --git a/pkg/simple/client/openpitrix/helmwrapper/helm_wrapper_darwin.go b/pkg/simple/client/openpitrix/helmwrapper/helm_wrapper_darwin.go new file mode 100644 index 0000000000000000000000000000000000000000..e3f988daeecb1a6e043511d24d0d9d6705f9da81 --- /dev/null +++ b/pkg/simple/client/openpitrix/helmwrapper/helm_wrapper_darwin.go @@ -0,0 +1,22 @@ +/* +Copyright 2020 The KubeSphere 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 helmwrapper + +const ( + workspaceBase = "/tmp/helm-operator" + helmPath = "/usr/local/bin/helm" +) diff --git a/pkg/simple/client/openpitrix/helmwrapper/helm_wrapper_linux.go b/pkg/simple/client/openpitrix/helmwrapper/helm_wrapper_linux.go new file mode 100644 index 0000000000000000000000000000000000000000..0688ac5f908f05bdd84772b1000b93495adde559 --- /dev/null +++ b/pkg/simple/client/openpitrix/helmwrapper/helm_wrapper_linux.go @@ -0,0 +1,22 @@ +/* +Copyright 2020 The KubeSphere 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 helmwrapper + +const ( + workspaceBase = "/dev/shm/helm-operator" + helmPath = "/usr/bin/helm" +) diff --git a/pkg/simple/client/openpitrix/helmwrapper/helm_wrapper_test.go b/pkg/simple/client/openpitrix/helmwrapper/helm_wrapper_test.go new file mode 100644 index 0000000000000000000000000000000000000000..3f953a2c6807ecb0db60efade5b7057596450bda --- /dev/null +++ b/pkg/simple/client/openpitrix/helmwrapper/helm_wrapper_test.go @@ -0,0 +1,44 @@ +/* +Copyright 2020 The KubeSphere 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 helmwrapper + +import ( + "fmt" + "os" + "testing" +) + +func TestHelmInstall(t *testing.T) { + wr := NewHelmWrapper("", "dummy", "dummy", SetMock(true)) + + res, err := wr.Install("dummy-chart", "", "dummy-value") + if err != nil { + t.Fail() + } + + _ = res +} + +func TestHelperProcess(t *testing.T) { + if os.Getenv("GO_WANT_HELPER_PROCESS") != "1" { + return + } + + // some code here to check arguments perhaps? + fmt.Fprintf(os.Stdout, "helm mock success") + os.Exit(0) +} diff --git a/pkg/simple/client/openpitrix/mock.go b/pkg/simple/client/openpitrix/mock.go deleted file mode 100644 index 2d0f032c6ef07d07c2552f0b458e5009ab8fa2bd..0000000000000000000000000000000000000000 --- a/pkg/simple/client/openpitrix/mock.go +++ /dev/null @@ -1,2115 +0,0 @@ -/* -Copyright 2020 KubeSphere 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. -*/ - -// Code generated by MockGen. DO NOT EDIT. -// Source: pkg/simple/client/openpitrix/openpitrix.go - -// Package openpitrix is a generated GoMock package. -package openpitrix - -import ( - context "context" - gomock "github.com/golang/mock/gomock" - empty "github.com/golang/protobuf/ptypes/empty" - grpc "google.golang.org/grpc" - pb "openpitrix.io/openpitrix/pkg/pb" - reflect "reflect" -) - -// MockClient is a mock of Client interface. -type MockClient struct { - ctrl *gomock.Controller - recorder *MockClientMockRecorder -} - -// MockClientMockRecorder is the mock recorder for MockClient. -type MockClientMockRecorder struct { - mock *MockClient -} - -// NewMockClient creates a new mock instance. -func NewMockClient(ctrl *gomock.Controller) *MockClient { - mock := &MockClient{ctrl: ctrl} - mock.recorder = &MockClientMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use. -func (m *MockClient) EXPECT() *MockClientMockRecorder { - return m.recorder -} - -// CreateRuntime mocks base method. -func (m *MockClient) CreateRuntime(ctx context.Context, in *pb.CreateRuntimeRequest, opts ...grpc.CallOption) (*pb.CreateRuntimeResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateRuntime", varargs...) - ret0, _ := ret[0].(*pb.CreateRuntimeResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateRuntime indicates an expected call of CreateRuntime. -func (mr *MockClientMockRecorder) CreateRuntime(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRuntime", reflect.TypeOf((*MockClient)(nil).CreateRuntime), varargs...) -} - -// CreateDebugRuntime mocks base method. -func (m *MockClient) CreateDebugRuntime(ctx context.Context, in *pb.CreateRuntimeRequest, opts ...grpc.CallOption) (*pb.CreateRuntimeResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateDebugRuntime", varargs...) - ret0, _ := ret[0].(*pb.CreateRuntimeResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateDebugRuntime indicates an expected call of CreateDebugRuntime. -func (mr *MockClientMockRecorder) CreateDebugRuntime(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDebugRuntime", reflect.TypeOf((*MockClient)(nil).CreateDebugRuntime), varargs...) -} - -// DescribeRuntimeDetails mocks base method. -func (m *MockClient) DescribeRuntimeDetails(ctx context.Context, in *pb.DescribeRuntimesRequest, opts ...grpc.CallOption) (*pb.DescribeRuntimeDetailsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeRuntimeDetails", varargs...) - ret0, _ := ret[0].(*pb.DescribeRuntimeDetailsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeRuntimeDetails indicates an expected call of DescribeRuntimeDetails. -func (mr *MockClientMockRecorder) DescribeRuntimeDetails(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeRuntimeDetails", reflect.TypeOf((*MockClient)(nil).DescribeRuntimeDetails), varargs...) -} - -// DescribeRuntimes mocks base method. -func (m *MockClient) DescribeRuntimes(ctx context.Context, in *pb.DescribeRuntimesRequest, opts ...grpc.CallOption) (*pb.DescribeRuntimesResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeRuntimes", varargs...) - ret0, _ := ret[0].(*pb.DescribeRuntimesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeRuntimes indicates an expected call of DescribeRuntimes. -func (mr *MockClientMockRecorder) DescribeRuntimes(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeRuntimes", reflect.TypeOf((*MockClient)(nil).DescribeRuntimes), varargs...) -} - -// DescribeDebugRuntimes mocks base method. -func (m *MockClient) DescribeDebugRuntimes(ctx context.Context, in *pb.DescribeRuntimesRequest, opts ...grpc.CallOption) (*pb.DescribeRuntimesResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeDebugRuntimes", varargs...) - ret0, _ := ret[0].(*pb.DescribeRuntimesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeDebugRuntimes indicates an expected call of DescribeDebugRuntimes. -func (mr *MockClientMockRecorder) DescribeDebugRuntimes(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeDebugRuntimes", reflect.TypeOf((*MockClient)(nil).DescribeDebugRuntimes), varargs...) -} - -// ModifyRuntime mocks base method. -func (m *MockClient) ModifyRuntime(ctx context.Context, in *pb.ModifyRuntimeRequest, opts ...grpc.CallOption) (*pb.ModifyRuntimeResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ModifyRuntime", varargs...) - ret0, _ := ret[0].(*pb.ModifyRuntimeResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ModifyRuntime indicates an expected call of ModifyRuntime. -func (mr *MockClientMockRecorder) ModifyRuntime(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyRuntime", reflect.TypeOf((*MockClient)(nil).ModifyRuntime), varargs...) -} - -// DeleteRuntimes mocks base method. -func (m *MockClient) DeleteRuntimes(ctx context.Context, in *pb.DeleteRuntimesRequest, opts ...grpc.CallOption) (*pb.DeleteRuntimesResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteRuntimes", varargs...) - ret0, _ := ret[0].(*pb.DeleteRuntimesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteRuntimes indicates an expected call of DeleteRuntimes. -func (mr *MockClientMockRecorder) DeleteRuntimes(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRuntimes", reflect.TypeOf((*MockClient)(nil).DeleteRuntimes), varargs...) -} - -// CreateRuntimeCredential mocks base method. -func (m *MockClient) CreateRuntimeCredential(ctx context.Context, in *pb.CreateRuntimeCredentialRequest, opts ...grpc.CallOption) (*pb.CreateRuntimeCredentialResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateRuntimeCredential", varargs...) - ret0, _ := ret[0].(*pb.CreateRuntimeCredentialResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateRuntimeCredential indicates an expected call of CreateRuntimeCredential. -func (mr *MockClientMockRecorder) CreateRuntimeCredential(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRuntimeCredential", reflect.TypeOf((*MockClient)(nil).CreateRuntimeCredential), varargs...) -} - -// CreateDebugRuntimeCredential mocks base method. -func (m *MockClient) CreateDebugRuntimeCredential(ctx context.Context, in *pb.CreateRuntimeCredentialRequest, opts ...grpc.CallOption) (*pb.CreateRuntimeCredentialResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateDebugRuntimeCredential", varargs...) - ret0, _ := ret[0].(*pb.CreateRuntimeCredentialResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateDebugRuntimeCredential indicates an expected call of CreateDebugRuntimeCredential. -func (mr *MockClientMockRecorder) CreateDebugRuntimeCredential(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDebugRuntimeCredential", reflect.TypeOf((*MockClient)(nil).CreateDebugRuntimeCredential), varargs...) -} - -// DescribeRuntimeCredentials mocks base method. -func (m *MockClient) DescribeRuntimeCredentials(ctx context.Context, in *pb.DescribeRuntimeCredentialsRequest, opts ...grpc.CallOption) (*pb.DescribeRuntimeCredentialsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeRuntimeCredentials", varargs...) - ret0, _ := ret[0].(*pb.DescribeRuntimeCredentialsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeRuntimeCredentials indicates an expected call of DescribeRuntimeCredentials. -func (mr *MockClientMockRecorder) DescribeRuntimeCredentials(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeRuntimeCredentials", reflect.TypeOf((*MockClient)(nil).DescribeRuntimeCredentials), varargs...) -} - -// DescribeDebugRuntimeCredentials mocks base method. -func (m *MockClient) DescribeDebugRuntimeCredentials(ctx context.Context, in *pb.DescribeRuntimeCredentialsRequest, opts ...grpc.CallOption) (*pb.DescribeRuntimeCredentialsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeDebugRuntimeCredentials", varargs...) - ret0, _ := ret[0].(*pb.DescribeRuntimeCredentialsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeDebugRuntimeCredentials indicates an expected call of DescribeDebugRuntimeCredentials. -func (mr *MockClientMockRecorder) DescribeDebugRuntimeCredentials(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeDebugRuntimeCredentials", reflect.TypeOf((*MockClient)(nil).DescribeDebugRuntimeCredentials), varargs...) -} - -// ModifyRuntimeCredential mocks base method. -func (m *MockClient) ModifyRuntimeCredential(ctx context.Context, in *pb.ModifyRuntimeCredentialRequest, opts ...grpc.CallOption) (*pb.ModifyRuntimeCredentialResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ModifyRuntimeCredential", varargs...) - ret0, _ := ret[0].(*pb.ModifyRuntimeCredentialResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ModifyRuntimeCredential indicates an expected call of ModifyRuntimeCredential. -func (mr *MockClientMockRecorder) ModifyRuntimeCredential(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyRuntimeCredential", reflect.TypeOf((*MockClient)(nil).ModifyRuntimeCredential), varargs...) -} - -// DeleteRuntimeCredentials mocks base method. -func (m *MockClient) DeleteRuntimeCredentials(ctx context.Context, in *pb.DeleteRuntimeCredentialsRequest, opts ...grpc.CallOption) (*pb.DeleteRuntimeCredentialsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteRuntimeCredentials", varargs...) - ret0, _ := ret[0].(*pb.DeleteRuntimeCredentialsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteRuntimeCredentials indicates an expected call of DeleteRuntimeCredentials. -func (mr *MockClientMockRecorder) DeleteRuntimeCredentials(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRuntimeCredentials", reflect.TypeOf((*MockClient)(nil).DeleteRuntimeCredentials), varargs...) -} - -// ValidateRuntimeCredential mocks base method. -func (m *MockClient) ValidateRuntimeCredential(ctx context.Context, in *pb.ValidateRuntimeCredentialRequest, opts ...grpc.CallOption) (*pb.ValidateRuntimeCredentialResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ValidateRuntimeCredential", varargs...) - ret0, _ := ret[0].(*pb.ValidateRuntimeCredentialResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ValidateRuntimeCredential indicates an expected call of ValidateRuntimeCredential. -func (mr *MockClientMockRecorder) ValidateRuntimeCredential(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateRuntimeCredential", reflect.TypeOf((*MockClient)(nil).ValidateRuntimeCredential), varargs...) -} - -// DescribeRuntimeProviderZones mocks base method. -func (m *MockClient) DescribeRuntimeProviderZones(ctx context.Context, in *pb.DescribeRuntimeProviderZonesRequest, opts ...grpc.CallOption) (*pb.DescribeRuntimeProviderZonesResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeRuntimeProviderZones", varargs...) - ret0, _ := ret[0].(*pb.DescribeRuntimeProviderZonesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeRuntimeProviderZones indicates an expected call of DescribeRuntimeProviderZones. -func (mr *MockClientMockRecorder) DescribeRuntimeProviderZones(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeRuntimeProviderZones", reflect.TypeOf((*MockClient)(nil).DescribeRuntimeProviderZones), varargs...) -} - -// GetRuntimeStatistics mocks base method. -func (m *MockClient) GetRuntimeStatistics(ctx context.Context, in *pb.GetRuntimeStatisticsRequest, opts ...grpc.CallOption) (*pb.GetRuntimeStatisticsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "GetRuntimeStatistics", varargs...) - ret0, _ := ret[0].(*pb.GetRuntimeStatisticsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetRuntimeStatistics indicates an expected call of GetRuntimeStatistics. -func (mr *MockClientMockRecorder) GetRuntimeStatistics(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetRuntimeStatistics", reflect.TypeOf((*MockClient)(nil).GetRuntimeStatistics), varargs...) -} - -// AddNodeKeyPairs mocks base method. -func (m *MockClient) AddNodeKeyPairs(ctx context.Context, in *pb.AddNodeKeyPairsRequest, opts ...grpc.CallOption) (*pb.AddNodeKeyPairsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "AddNodeKeyPairs", varargs...) - ret0, _ := ret[0].(*pb.AddNodeKeyPairsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AddNodeKeyPairs indicates an expected call of AddNodeKeyPairs. -func (mr *MockClientMockRecorder) AddNodeKeyPairs(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddNodeKeyPairs", reflect.TypeOf((*MockClient)(nil).AddNodeKeyPairs), varargs...) -} - -// DeleteNodeKeyPairs mocks base method. -func (m *MockClient) DeleteNodeKeyPairs(ctx context.Context, in *pb.DeleteNodeKeyPairsRequest, opts ...grpc.CallOption) (*pb.DeleteNodeKeyPairsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteNodeKeyPairs", varargs...) - ret0, _ := ret[0].(*pb.DeleteNodeKeyPairsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteNodeKeyPairs indicates an expected call of DeleteNodeKeyPairs. -func (mr *MockClientMockRecorder) DeleteNodeKeyPairs(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteNodeKeyPairs", reflect.TypeOf((*MockClient)(nil).DeleteNodeKeyPairs), varargs...) -} - -// CreateKeyPair mocks base method. -func (m *MockClient) CreateKeyPair(ctx context.Context, in *pb.CreateKeyPairRequest, opts ...grpc.CallOption) (*pb.CreateKeyPairResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateKeyPair", varargs...) - ret0, _ := ret[0].(*pb.CreateKeyPairResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateKeyPair indicates an expected call of CreateKeyPair. -func (mr *MockClientMockRecorder) CreateKeyPair(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateKeyPair", reflect.TypeOf((*MockClient)(nil).CreateKeyPair), varargs...) -} - -// DescribeKeyPairs mocks base method. -func (m *MockClient) DescribeKeyPairs(ctx context.Context, in *pb.DescribeKeyPairsRequest, opts ...grpc.CallOption) (*pb.DescribeKeyPairsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeKeyPairs", varargs...) - ret0, _ := ret[0].(*pb.DescribeKeyPairsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeKeyPairs indicates an expected call of DescribeKeyPairs. -func (mr *MockClientMockRecorder) DescribeKeyPairs(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeKeyPairs", reflect.TypeOf((*MockClient)(nil).DescribeKeyPairs), varargs...) -} - -// DeleteKeyPairs mocks base method. -func (m *MockClient) DeleteKeyPairs(ctx context.Context, in *pb.DeleteKeyPairsRequest, opts ...grpc.CallOption) (*pb.DeleteKeyPairsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteKeyPairs", varargs...) - ret0, _ := ret[0].(*pb.DeleteKeyPairsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteKeyPairs indicates an expected call of DeleteKeyPairs. -func (mr *MockClientMockRecorder) DeleteKeyPairs(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteKeyPairs", reflect.TypeOf((*MockClient)(nil).DeleteKeyPairs), varargs...) -} - -// AttachKeyPairs mocks base method. -func (m *MockClient) AttachKeyPairs(ctx context.Context, in *pb.AttachKeyPairsRequest, opts ...grpc.CallOption) (*pb.AttachKeyPairsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "AttachKeyPairs", varargs...) - ret0, _ := ret[0].(*pb.AttachKeyPairsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AttachKeyPairs indicates an expected call of AttachKeyPairs. -func (mr *MockClientMockRecorder) AttachKeyPairs(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AttachKeyPairs", reflect.TypeOf((*MockClient)(nil).AttachKeyPairs), varargs...) -} - -// DetachKeyPairs mocks base method. -func (m *MockClient) DetachKeyPairs(ctx context.Context, in *pb.DetachKeyPairsRequest, opts ...grpc.CallOption) (*pb.DetachKeyPairsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DetachKeyPairs", varargs...) - ret0, _ := ret[0].(*pb.DetachKeyPairsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DetachKeyPairs indicates an expected call of DetachKeyPairs. -func (mr *MockClientMockRecorder) DetachKeyPairs(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DetachKeyPairs", reflect.TypeOf((*MockClient)(nil).DetachKeyPairs), varargs...) -} - -// DescribeSubnets mocks base method. -func (m *MockClient) DescribeSubnets(ctx context.Context, in *pb.DescribeSubnetsRequest, opts ...grpc.CallOption) (*pb.DescribeSubnetsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeSubnets", varargs...) - ret0, _ := ret[0].(*pb.DescribeSubnetsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeSubnets indicates an expected call of DescribeSubnets. -func (mr *MockClientMockRecorder) DescribeSubnets(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeSubnets", reflect.TypeOf((*MockClient)(nil).DescribeSubnets), varargs...) -} - -// CreateCluster mocks base method. -func (m *MockClient) CreateCluster(ctx context.Context, in *pb.CreateClusterRequest, opts ...grpc.CallOption) (*pb.CreateClusterResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateCluster", varargs...) - ret0, _ := ret[0].(*pb.CreateClusterResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateCluster indicates an expected call of CreateCluster. -func (mr *MockClientMockRecorder) CreateCluster(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateCluster", reflect.TypeOf((*MockClient)(nil).CreateCluster), varargs...) -} - -// CreateDebugCluster mocks base method. -func (m *MockClient) CreateDebugCluster(ctx context.Context, in *pb.CreateClusterRequest, opts ...grpc.CallOption) (*pb.CreateClusterResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateDebugCluster", varargs...) - ret0, _ := ret[0].(*pb.CreateClusterResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateDebugCluster indicates an expected call of CreateDebugCluster. -func (mr *MockClientMockRecorder) CreateDebugCluster(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDebugCluster", reflect.TypeOf((*MockClient)(nil).CreateDebugCluster), varargs...) -} - -// ModifyCluster mocks base method. -func (m *MockClient) ModifyCluster(ctx context.Context, in *pb.ModifyClusterRequest, opts ...grpc.CallOption) (*pb.ModifyClusterResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ModifyCluster", varargs...) - ret0, _ := ret[0].(*pb.ModifyClusterResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ModifyCluster indicates an expected call of ModifyCluster. -func (mr *MockClientMockRecorder) ModifyCluster(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyCluster", reflect.TypeOf((*MockClient)(nil).ModifyCluster), varargs...) -} - -// ModifyClusterNode mocks base method. -func (m *MockClient) ModifyClusterNode(ctx context.Context, in *pb.ModifyClusterNodeRequest, opts ...grpc.CallOption) (*pb.ModifyClusterNodeResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ModifyClusterNode", varargs...) - ret0, _ := ret[0].(*pb.ModifyClusterNodeResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ModifyClusterNode indicates an expected call of ModifyClusterNode. -func (mr *MockClientMockRecorder) ModifyClusterNode(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyClusterNode", reflect.TypeOf((*MockClient)(nil).ModifyClusterNode), varargs...) -} - -// ModifyClusterAttributes mocks base method. -func (m *MockClient) ModifyClusterAttributes(ctx context.Context, in *pb.ModifyClusterAttributesRequest, opts ...grpc.CallOption) (*pb.ModifyClusterAttributesResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ModifyClusterAttributes", varargs...) - ret0, _ := ret[0].(*pb.ModifyClusterAttributesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ModifyClusterAttributes indicates an expected call of ModifyClusterAttributes. -func (mr *MockClientMockRecorder) ModifyClusterAttributes(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyClusterAttributes", reflect.TypeOf((*MockClient)(nil).ModifyClusterAttributes), varargs...) -} - -// ModifyClusterNodeAttributes mocks base method. -func (m *MockClient) ModifyClusterNodeAttributes(ctx context.Context, in *pb.ModifyClusterNodeAttributesRequest, opts ...grpc.CallOption) (*pb.ModifyClusterNodeAttributesResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ModifyClusterNodeAttributes", varargs...) - ret0, _ := ret[0].(*pb.ModifyClusterNodeAttributesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ModifyClusterNodeAttributes indicates an expected call of ModifyClusterNodeAttributes. -func (mr *MockClientMockRecorder) ModifyClusterNodeAttributes(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyClusterNodeAttributes", reflect.TypeOf((*MockClient)(nil).ModifyClusterNodeAttributes), varargs...) -} - -// AddTableClusterNodes mocks base method. -func (m *MockClient) AddTableClusterNodes(ctx context.Context, in *pb.AddTableClusterNodesRequest, opts ...grpc.CallOption) (*empty.Empty, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "AddTableClusterNodes", varargs...) - ret0, _ := ret[0].(*empty.Empty) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AddTableClusterNodes indicates an expected call of AddTableClusterNodes. -func (mr *MockClientMockRecorder) AddTableClusterNodes(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddTableClusterNodes", reflect.TypeOf((*MockClient)(nil).AddTableClusterNodes), varargs...) -} - -// DeleteTableClusterNodes mocks base method. -func (m *MockClient) DeleteTableClusterNodes(ctx context.Context, in *pb.DeleteTableClusterNodesRequest, opts ...grpc.CallOption) (*empty.Empty, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteTableClusterNodes", varargs...) - ret0, _ := ret[0].(*empty.Empty) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteTableClusterNodes indicates an expected call of DeleteTableClusterNodes. -func (mr *MockClientMockRecorder) DeleteTableClusterNodes(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteTableClusterNodes", reflect.TypeOf((*MockClient)(nil).DeleteTableClusterNodes), varargs...) -} - -// DeleteClusters mocks base method. -func (m *MockClient) DeleteClusters(ctx context.Context, in *pb.DeleteClustersRequest, opts ...grpc.CallOption) (*pb.DeleteClustersResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteClusters", varargs...) - ret0, _ := ret[0].(*pb.DeleteClustersResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteClusters indicates an expected call of DeleteClusters. -func (mr *MockClientMockRecorder) DeleteClusters(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteClusters", reflect.TypeOf((*MockClient)(nil).DeleteClusters), varargs...) -} - -// UpgradeCluster mocks base method. -func (m *MockClient) UpgradeCluster(ctx context.Context, in *pb.UpgradeClusterRequest, opts ...grpc.CallOption) (*pb.UpgradeClusterResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "UpgradeCluster", varargs...) - ret0, _ := ret[0].(*pb.UpgradeClusterResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpgradeCluster indicates an expected call of UpgradeCluster. -func (mr *MockClientMockRecorder) UpgradeCluster(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpgradeCluster", reflect.TypeOf((*MockClient)(nil).UpgradeCluster), varargs...) -} - -// RollbackCluster mocks base method. -func (m *MockClient) RollbackCluster(ctx context.Context, in *pb.RollbackClusterRequest, opts ...grpc.CallOption) (*pb.RollbackClusterResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "RollbackCluster", varargs...) - ret0, _ := ret[0].(*pb.RollbackClusterResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// RollbackCluster indicates an expected call of RollbackCluster. -func (mr *MockClientMockRecorder) RollbackCluster(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RollbackCluster", reflect.TypeOf((*MockClient)(nil).RollbackCluster), varargs...) -} - -// ResizeCluster mocks base method. -func (m *MockClient) ResizeCluster(ctx context.Context, in *pb.ResizeClusterRequest, opts ...grpc.CallOption) (*pb.ResizeClusterResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ResizeCluster", varargs...) - ret0, _ := ret[0].(*pb.ResizeClusterResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ResizeCluster indicates an expected call of ResizeCluster. -func (mr *MockClientMockRecorder) ResizeCluster(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ResizeCluster", reflect.TypeOf((*MockClient)(nil).ResizeCluster), varargs...) -} - -// AddClusterNodes mocks base method. -func (m *MockClient) AddClusterNodes(ctx context.Context, in *pb.AddClusterNodesRequest, opts ...grpc.CallOption) (*pb.AddClusterNodesResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "AddClusterNodes", varargs...) - ret0, _ := ret[0].(*pb.AddClusterNodesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AddClusterNodes indicates an expected call of AddClusterNodes. -func (mr *MockClientMockRecorder) AddClusterNodes(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddClusterNodes", reflect.TypeOf((*MockClient)(nil).AddClusterNodes), varargs...) -} - -// DeleteClusterNodes mocks base method. -func (m *MockClient) DeleteClusterNodes(ctx context.Context, in *pb.DeleteClusterNodesRequest, opts ...grpc.CallOption) (*pb.DeleteClusterNodesResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteClusterNodes", varargs...) - ret0, _ := ret[0].(*pb.DeleteClusterNodesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteClusterNodes indicates an expected call of DeleteClusterNodes. -func (mr *MockClientMockRecorder) DeleteClusterNodes(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteClusterNodes", reflect.TypeOf((*MockClient)(nil).DeleteClusterNodes), varargs...) -} - -// UpdateClusterEnv mocks base method. -func (m *MockClient) UpdateClusterEnv(ctx context.Context, in *pb.UpdateClusterEnvRequest, opts ...grpc.CallOption) (*pb.UpdateClusterEnvResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "UpdateClusterEnv", varargs...) - ret0, _ := ret[0].(*pb.UpdateClusterEnvResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UpdateClusterEnv indicates an expected call of UpdateClusterEnv. -func (mr *MockClientMockRecorder) UpdateClusterEnv(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpdateClusterEnv", reflect.TypeOf((*MockClient)(nil).UpdateClusterEnv), varargs...) -} - -// DescribeClusters mocks base method. -func (m *MockClient) DescribeClusters(ctx context.Context, in *pb.DescribeClustersRequest, opts ...grpc.CallOption) (*pb.DescribeClustersResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeClusters", varargs...) - ret0, _ := ret[0].(*pb.DescribeClustersResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeClusters indicates an expected call of DescribeClusters. -func (mr *MockClientMockRecorder) DescribeClusters(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeClusters", reflect.TypeOf((*MockClient)(nil).DescribeClusters), varargs...) -} - -// DescribeDebugClusters mocks base method. -func (m *MockClient) DescribeDebugClusters(ctx context.Context, in *pb.DescribeClustersRequest, opts ...grpc.CallOption) (*pb.DescribeClustersResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeDebugClusters", varargs...) - ret0, _ := ret[0].(*pb.DescribeClustersResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeDebugClusters indicates an expected call of DescribeDebugClusters. -func (mr *MockClientMockRecorder) DescribeDebugClusters(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeDebugClusters", reflect.TypeOf((*MockClient)(nil).DescribeDebugClusters), varargs...) -} - -// DescribeAppClusters mocks base method. -func (m *MockClient) DescribeAppClusters(ctx context.Context, in *pb.DescribeAppClustersRequest, opts ...grpc.CallOption) (*pb.DescribeAppClustersResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeAppClusters", varargs...) - ret0, _ := ret[0].(*pb.DescribeAppClustersResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeAppClusters indicates an expected call of DescribeAppClusters. -func (mr *MockClientMockRecorder) DescribeAppClusters(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAppClusters", reflect.TypeOf((*MockClient)(nil).DescribeAppClusters), varargs...) -} - -// DescribeDebugAppClusters mocks base method. -func (m *MockClient) DescribeDebugAppClusters(ctx context.Context, in *pb.DescribeAppClustersRequest, opts ...grpc.CallOption) (*pb.DescribeAppClustersResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeDebugAppClusters", varargs...) - ret0, _ := ret[0].(*pb.DescribeAppClustersResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeDebugAppClusters indicates an expected call of DescribeDebugAppClusters. -func (mr *MockClientMockRecorder) DescribeDebugAppClusters(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeDebugAppClusters", reflect.TypeOf((*MockClient)(nil).DescribeDebugAppClusters), varargs...) -} - -// DescribeClusterNodes mocks base method. -func (m *MockClient) DescribeClusterNodes(ctx context.Context, in *pb.DescribeClusterNodesRequest, opts ...grpc.CallOption) (*pb.DescribeClusterNodesResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeClusterNodes", varargs...) - ret0, _ := ret[0].(*pb.DescribeClusterNodesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeClusterNodes indicates an expected call of DescribeClusterNodes. -func (mr *MockClientMockRecorder) DescribeClusterNodes(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeClusterNodes", reflect.TypeOf((*MockClient)(nil).DescribeClusterNodes), varargs...) -} - -// StopClusters mocks base method. -func (m *MockClient) StopClusters(ctx context.Context, in *pb.StopClustersRequest, opts ...grpc.CallOption) (*pb.StopClustersResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "StopClusters", varargs...) - ret0, _ := ret[0].(*pb.StopClustersResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// StopClusters indicates an expected call of StopClusters. -func (mr *MockClientMockRecorder) StopClusters(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StopClusters", reflect.TypeOf((*MockClient)(nil).StopClusters), varargs...) -} - -// StartClusters mocks base method. -func (m *MockClient) StartClusters(ctx context.Context, in *pb.StartClustersRequest, opts ...grpc.CallOption) (*pb.StartClustersResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "StartClusters", varargs...) - ret0, _ := ret[0].(*pb.StartClustersResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// StartClusters indicates an expected call of StartClusters. -func (mr *MockClientMockRecorder) StartClusters(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "StartClusters", reflect.TypeOf((*MockClient)(nil).StartClusters), varargs...) -} - -// RecoverClusters mocks base method. -func (m *MockClient) RecoverClusters(ctx context.Context, in *pb.RecoverClustersRequest, opts ...grpc.CallOption) (*pb.RecoverClustersResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "RecoverClusters", varargs...) - ret0, _ := ret[0].(*pb.RecoverClustersResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// RecoverClusters indicates an expected call of RecoverClusters. -func (mr *MockClientMockRecorder) RecoverClusters(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecoverClusters", reflect.TypeOf((*MockClient)(nil).RecoverClusters), varargs...) -} - -// CeaseClusters mocks base method. -func (m *MockClient) CeaseClusters(ctx context.Context, in *pb.CeaseClustersRequest, opts ...grpc.CallOption) (*pb.CeaseClustersResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CeaseClusters", varargs...) - ret0, _ := ret[0].(*pb.CeaseClustersResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CeaseClusters indicates an expected call of CeaseClusters. -func (mr *MockClientMockRecorder) CeaseClusters(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CeaseClusters", reflect.TypeOf((*MockClient)(nil).CeaseClusters), varargs...) -} - -// GetClusterStatistics mocks base method. -func (m *MockClient) GetClusterStatistics(ctx context.Context, in *pb.GetClusterStatisticsRequest, opts ...grpc.CallOption) (*pb.GetClusterStatisticsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "GetClusterStatistics", varargs...) - ret0, _ := ret[0].(*pb.GetClusterStatisticsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetClusterStatistics indicates an expected call of GetClusterStatistics. -func (mr *MockClientMockRecorder) GetClusterStatistics(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetClusterStatistics", reflect.TypeOf((*MockClient)(nil).GetClusterStatistics), varargs...) -} - -// DeleteClusterInRuntime mocks base method. -func (m *MockClient) DeleteClusterInRuntime(ctx context.Context, in *pb.DeleteClusterInRuntimeRequest, opts ...grpc.CallOption) (*pb.DeleteClusterInRuntimeResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteClusterInRuntime", varargs...) - ret0, _ := ret[0].(*pb.DeleteClusterInRuntimeResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteClusterInRuntime indicates an expected call of DeleteClusterInRuntime. -func (mr *MockClientMockRecorder) DeleteClusterInRuntime(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteClusterInRuntime", reflect.TypeOf((*MockClient)(nil).DeleteClusterInRuntime), varargs...) -} - -// MigrateClusterInRuntime mocks base method. -func (m *MockClient) MigrateClusterInRuntime(ctx context.Context, in *pb.MigrateClusterInRuntimeRequest, opts ...grpc.CallOption) (*pb.MigrateClusterInRuntimeResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "MigrateClusterInRuntime", varargs...) - ret0, _ := ret[0].(*pb.MigrateClusterInRuntimeResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// MigrateClusterInRuntime indicates an expected call of MigrateClusterInRuntime. -func (mr *MockClientMockRecorder) MigrateClusterInRuntime(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MigrateClusterInRuntime", reflect.TypeOf((*MockClient)(nil).MigrateClusterInRuntime), varargs...) -} - -// SyncRepo mocks base method. -func (m *MockClient) SyncRepo(ctx context.Context, in *pb.SyncRepoRequest, opts ...grpc.CallOption) (*pb.SyncRepoResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "SyncRepo", varargs...) - ret0, _ := ret[0].(*pb.SyncRepoResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SyncRepo indicates an expected call of SyncRepo. -func (mr *MockClientMockRecorder) SyncRepo(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SyncRepo", reflect.TypeOf((*MockClient)(nil).SyncRepo), varargs...) -} - -// CreateApp mocks base method. -func (m *MockClient) CreateApp(ctx context.Context, in *pb.CreateAppRequest, opts ...grpc.CallOption) (*pb.CreateAppResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateApp", varargs...) - ret0, _ := ret[0].(*pb.CreateAppResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateApp indicates an expected call of CreateApp. -func (mr *MockClientMockRecorder) CreateApp(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateApp", reflect.TypeOf((*MockClient)(nil).CreateApp), varargs...) -} - -// ValidatePackage mocks base method. -func (m *MockClient) ValidatePackage(ctx context.Context, in *pb.ValidatePackageRequest, opts ...grpc.CallOption) (*pb.ValidatePackageResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ValidatePackage", varargs...) - ret0, _ := ret[0].(*pb.ValidatePackageResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ValidatePackage indicates an expected call of ValidatePackage. -func (mr *MockClientMockRecorder) ValidatePackage(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatePackage", reflect.TypeOf((*MockClient)(nil).ValidatePackage), varargs...) -} - -// GetAppStatistics mocks base method. -func (m *MockClient) GetAppStatistics(ctx context.Context, in *pb.GetAppStatisticsRequest, opts ...grpc.CallOption) (*pb.GetAppStatisticsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "GetAppStatistics", varargs...) - ret0, _ := ret[0].(*pb.GetAppStatisticsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetAppStatistics indicates an expected call of GetAppStatistics. -func (mr *MockClientMockRecorder) GetAppStatistics(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAppStatistics", reflect.TypeOf((*MockClient)(nil).GetAppStatistics), varargs...) -} - -// DescribeApps mocks base method. -func (m *MockClient) DescribeApps(ctx context.Context, in *pb.DescribeAppsRequest, opts ...grpc.CallOption) (*pb.DescribeAppsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeApps", varargs...) - ret0, _ := ret[0].(*pb.DescribeAppsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeApps indicates an expected call of DescribeApps. -func (mr *MockClientMockRecorder) DescribeApps(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeApps", reflect.TypeOf((*MockClient)(nil).DescribeApps), varargs...) -} - -// DescribeActiveApps mocks base method. -func (m *MockClient) DescribeActiveApps(ctx context.Context, in *pb.DescribeAppsRequest, opts ...grpc.CallOption) (*pb.DescribeAppsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeActiveApps", varargs...) - ret0, _ := ret[0].(*pb.DescribeAppsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeActiveApps indicates an expected call of DescribeActiveApps. -func (mr *MockClientMockRecorder) DescribeActiveApps(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeActiveApps", reflect.TypeOf((*MockClient)(nil).DescribeActiveApps), varargs...) -} - -// ModifyApp mocks base method. -func (m *MockClient) ModifyApp(ctx context.Context, in *pb.ModifyAppRequest, opts ...grpc.CallOption) (*pb.ModifyAppResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ModifyApp", varargs...) - ret0, _ := ret[0].(*pb.ModifyAppResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ModifyApp indicates an expected call of ModifyApp. -func (mr *MockClientMockRecorder) ModifyApp(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyApp", reflect.TypeOf((*MockClient)(nil).ModifyApp), varargs...) -} - -// UploadAppAttachment mocks base method. -func (m *MockClient) UploadAppAttachment(ctx context.Context, in *pb.UploadAppAttachmentRequest, opts ...grpc.CallOption) (*pb.UploadAppAttachmentResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "UploadAppAttachment", varargs...) - ret0, _ := ret[0].(*pb.UploadAppAttachmentResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// UploadAppAttachment indicates an expected call of UploadAppAttachment. -func (mr *MockClientMockRecorder) UploadAppAttachment(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UploadAppAttachment", reflect.TypeOf((*MockClient)(nil).UploadAppAttachment), varargs...) -} - -// DeleteApps mocks base method. -func (m *MockClient) DeleteApps(ctx context.Context, in *pb.DeleteAppsRequest, opts ...grpc.CallOption) (*pb.DeleteAppsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteApps", varargs...) - ret0, _ := ret[0].(*pb.DeleteAppsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteApps indicates an expected call of DeleteApps. -func (mr *MockClientMockRecorder) DeleteApps(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteApps", reflect.TypeOf((*MockClient)(nil).DeleteApps), varargs...) -} - -// CreateAppVersion mocks base method. -func (m *MockClient) CreateAppVersion(ctx context.Context, in *pb.CreateAppVersionRequest, opts ...grpc.CallOption) (*pb.CreateAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateAppVersion", varargs...) - ret0, _ := ret[0].(*pb.CreateAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateAppVersion indicates an expected call of CreateAppVersion. -func (mr *MockClientMockRecorder) CreateAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAppVersion", reflect.TypeOf((*MockClient)(nil).CreateAppVersion), varargs...) -} - -// DescribeAppVersions mocks base method. -func (m *MockClient) DescribeAppVersions(ctx context.Context, in *pb.DescribeAppVersionsRequest, opts ...grpc.CallOption) (*pb.DescribeAppVersionsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeAppVersions", varargs...) - ret0, _ := ret[0].(*pb.DescribeAppVersionsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeAppVersions indicates an expected call of DescribeAppVersions. -func (mr *MockClientMockRecorder) DescribeAppVersions(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAppVersions", reflect.TypeOf((*MockClient)(nil).DescribeAppVersions), varargs...) -} - -// DescribeActiveAppVersions mocks base method. -func (m *MockClient) DescribeActiveAppVersions(ctx context.Context, in *pb.DescribeAppVersionsRequest, opts ...grpc.CallOption) (*pb.DescribeAppVersionsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeActiveAppVersions", varargs...) - ret0, _ := ret[0].(*pb.DescribeAppVersionsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeActiveAppVersions indicates an expected call of DescribeActiveAppVersions. -func (mr *MockClientMockRecorder) DescribeActiveAppVersions(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeActiveAppVersions", reflect.TypeOf((*MockClient)(nil).DescribeActiveAppVersions), varargs...) -} - -// DescribeAppVersionAudits mocks base method. -func (m *MockClient) DescribeAppVersionAudits(ctx context.Context, in *pb.DescribeAppVersionAuditsRequest, opts ...grpc.CallOption) (*pb.DescribeAppVersionAuditsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeAppVersionAudits", varargs...) - ret0, _ := ret[0].(*pb.DescribeAppVersionAuditsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeAppVersionAudits indicates an expected call of DescribeAppVersionAudits. -func (mr *MockClientMockRecorder) DescribeAppVersionAudits(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAppVersionAudits", reflect.TypeOf((*MockClient)(nil).DescribeAppVersionAudits), varargs...) -} - -// DescribeAppVersionReviews mocks base method. -func (m *MockClient) DescribeAppVersionReviews(ctx context.Context, in *pb.DescribeAppVersionReviewsRequest, opts ...grpc.CallOption) (*pb.DescribeAppVersionReviewsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeAppVersionReviews", varargs...) - ret0, _ := ret[0].(*pb.DescribeAppVersionReviewsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeAppVersionReviews indicates an expected call of DescribeAppVersionReviews. -func (mr *MockClientMockRecorder) DescribeAppVersionReviews(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeAppVersionReviews", reflect.TypeOf((*MockClient)(nil).DescribeAppVersionReviews), varargs...) -} - -// ModifyAppVersion mocks base method. -func (m *MockClient) ModifyAppVersion(ctx context.Context, in *pb.ModifyAppVersionRequest, opts ...grpc.CallOption) (*pb.ModifyAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ModifyAppVersion", varargs...) - ret0, _ := ret[0].(*pb.ModifyAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ModifyAppVersion indicates an expected call of ModifyAppVersion. -func (mr *MockClientMockRecorder) ModifyAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyAppVersion", reflect.TypeOf((*MockClient)(nil).ModifyAppVersion), varargs...) -} - -// GetAppVersionPackage mocks base method. -func (m *MockClient) GetAppVersionPackage(ctx context.Context, in *pb.GetAppVersionPackageRequest, opts ...grpc.CallOption) (*pb.GetAppVersionPackageResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "GetAppVersionPackage", varargs...) - ret0, _ := ret[0].(*pb.GetAppVersionPackageResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetAppVersionPackage indicates an expected call of GetAppVersionPackage. -func (mr *MockClientMockRecorder) GetAppVersionPackage(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAppVersionPackage", reflect.TypeOf((*MockClient)(nil).GetAppVersionPackage), varargs...) -} - -// GetAppVersionPackageFiles mocks base method. -func (m *MockClient) GetAppVersionPackageFiles(ctx context.Context, in *pb.GetAppVersionPackageFilesRequest, opts ...grpc.CallOption) (*pb.GetAppVersionPackageFilesResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "GetAppVersionPackageFiles", varargs...) - ret0, _ := ret[0].(*pb.GetAppVersionPackageFilesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetAppVersionPackageFiles indicates an expected call of GetAppVersionPackageFiles. -func (mr *MockClientMockRecorder) GetAppVersionPackageFiles(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAppVersionPackageFiles", reflect.TypeOf((*MockClient)(nil).GetAppVersionPackageFiles), varargs...) -} - -// SubmitAppVersion mocks base method. -func (m *MockClient) SubmitAppVersion(ctx context.Context, in *pb.SubmitAppVersionRequest, opts ...grpc.CallOption) (*pb.SubmitAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "SubmitAppVersion", varargs...) - ret0, _ := ret[0].(*pb.SubmitAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SubmitAppVersion indicates an expected call of SubmitAppVersion. -func (mr *MockClientMockRecorder) SubmitAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SubmitAppVersion", reflect.TypeOf((*MockClient)(nil).SubmitAppVersion), varargs...) -} - -// CancelAppVersion mocks base method. -func (m *MockClient) CancelAppVersion(ctx context.Context, in *pb.CancelAppVersionRequest, opts ...grpc.CallOption) (*pb.CancelAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CancelAppVersion", varargs...) - ret0, _ := ret[0].(*pb.CancelAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CancelAppVersion indicates an expected call of CancelAppVersion. -func (mr *MockClientMockRecorder) CancelAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CancelAppVersion", reflect.TypeOf((*MockClient)(nil).CancelAppVersion), varargs...) -} - -// ReleaseAppVersion mocks base method. -func (m *MockClient) ReleaseAppVersion(ctx context.Context, in *pb.ReleaseAppVersionRequest, opts ...grpc.CallOption) (*pb.ReleaseAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ReleaseAppVersion", varargs...) - ret0, _ := ret[0].(*pb.ReleaseAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ReleaseAppVersion indicates an expected call of ReleaseAppVersion. -func (mr *MockClientMockRecorder) ReleaseAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReleaseAppVersion", reflect.TypeOf((*MockClient)(nil).ReleaseAppVersion), varargs...) -} - -// DeleteAppVersion mocks base method. -func (m *MockClient) DeleteAppVersion(ctx context.Context, in *pb.DeleteAppVersionRequest, opts ...grpc.CallOption) (*pb.DeleteAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteAppVersion", varargs...) - ret0, _ := ret[0].(*pb.DeleteAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteAppVersion indicates an expected call of DeleteAppVersion. -func (mr *MockClientMockRecorder) DeleteAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAppVersion", reflect.TypeOf((*MockClient)(nil).DeleteAppVersion), varargs...) -} - -// IsvReviewAppVersion mocks base method. -func (m *MockClient) IsvReviewAppVersion(ctx context.Context, in *pb.ReviewAppVersionRequest, opts ...grpc.CallOption) (*pb.ReviewAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "IsvReviewAppVersion", varargs...) - ret0, _ := ret[0].(*pb.ReviewAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// IsvReviewAppVersion indicates an expected call of IsvReviewAppVersion. -func (mr *MockClientMockRecorder) IsvReviewAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsvReviewAppVersion", reflect.TypeOf((*MockClient)(nil).IsvReviewAppVersion), varargs...) -} - -// IsvPassAppVersion mocks base method. -func (m *MockClient) IsvPassAppVersion(ctx context.Context, in *pb.PassAppVersionRequest, opts ...grpc.CallOption) (*pb.PassAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "IsvPassAppVersion", varargs...) - ret0, _ := ret[0].(*pb.PassAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// IsvPassAppVersion indicates an expected call of IsvPassAppVersion. -func (mr *MockClientMockRecorder) IsvPassAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsvPassAppVersion", reflect.TypeOf((*MockClient)(nil).IsvPassAppVersion), varargs...) -} - -// IsvRejectAppVersion mocks base method. -func (m *MockClient) IsvRejectAppVersion(ctx context.Context, in *pb.RejectAppVersionRequest, opts ...grpc.CallOption) (*pb.RejectAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "IsvRejectAppVersion", varargs...) - ret0, _ := ret[0].(*pb.RejectAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// IsvRejectAppVersion indicates an expected call of IsvRejectAppVersion. -func (mr *MockClientMockRecorder) IsvRejectAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsvRejectAppVersion", reflect.TypeOf((*MockClient)(nil).IsvRejectAppVersion), varargs...) -} - -// BusinessReviewAppVersion mocks base method. -func (m *MockClient) BusinessReviewAppVersion(ctx context.Context, in *pb.ReviewAppVersionRequest, opts ...grpc.CallOption) (*pb.ReviewAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "BusinessReviewAppVersion", varargs...) - ret0, _ := ret[0].(*pb.ReviewAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// BusinessReviewAppVersion indicates an expected call of BusinessReviewAppVersion. -func (mr *MockClientMockRecorder) BusinessReviewAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BusinessReviewAppVersion", reflect.TypeOf((*MockClient)(nil).BusinessReviewAppVersion), varargs...) -} - -// BusinessPassAppVersion mocks base method. -func (m *MockClient) BusinessPassAppVersion(ctx context.Context, in *pb.PassAppVersionRequest, opts ...grpc.CallOption) (*pb.PassAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "BusinessPassAppVersion", varargs...) - ret0, _ := ret[0].(*pb.PassAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// BusinessPassAppVersion indicates an expected call of BusinessPassAppVersion. -func (mr *MockClientMockRecorder) BusinessPassAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BusinessPassAppVersion", reflect.TypeOf((*MockClient)(nil).BusinessPassAppVersion), varargs...) -} - -// BusinessRejectAppVersion mocks base method. -func (m *MockClient) BusinessRejectAppVersion(ctx context.Context, in *pb.RejectAppVersionRequest, opts ...grpc.CallOption) (*pb.RejectAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "BusinessRejectAppVersion", varargs...) - ret0, _ := ret[0].(*pb.RejectAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// BusinessRejectAppVersion indicates an expected call of BusinessRejectAppVersion. -func (mr *MockClientMockRecorder) BusinessRejectAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "BusinessRejectAppVersion", reflect.TypeOf((*MockClient)(nil).BusinessRejectAppVersion), varargs...) -} - -// TechnicalReviewAppVersion mocks base method. -func (m *MockClient) TechnicalReviewAppVersion(ctx context.Context, in *pb.ReviewAppVersionRequest, opts ...grpc.CallOption) (*pb.ReviewAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "TechnicalReviewAppVersion", varargs...) - ret0, _ := ret[0].(*pb.ReviewAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// TechnicalReviewAppVersion indicates an expected call of TechnicalReviewAppVersion. -func (mr *MockClientMockRecorder) TechnicalReviewAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TechnicalReviewAppVersion", reflect.TypeOf((*MockClient)(nil).TechnicalReviewAppVersion), varargs...) -} - -// TechnicalPassAppVersion mocks base method. -func (m *MockClient) TechnicalPassAppVersion(ctx context.Context, in *pb.PassAppVersionRequest, opts ...grpc.CallOption) (*pb.PassAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "TechnicalPassAppVersion", varargs...) - ret0, _ := ret[0].(*pb.PassAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// TechnicalPassAppVersion indicates an expected call of TechnicalPassAppVersion. -func (mr *MockClientMockRecorder) TechnicalPassAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TechnicalPassAppVersion", reflect.TypeOf((*MockClient)(nil).TechnicalPassAppVersion), varargs...) -} - -// TechnicalRejectAppVersion mocks base method. -func (m *MockClient) TechnicalRejectAppVersion(ctx context.Context, in *pb.RejectAppVersionRequest, opts ...grpc.CallOption) (*pb.RejectAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "TechnicalRejectAppVersion", varargs...) - ret0, _ := ret[0].(*pb.RejectAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// TechnicalRejectAppVersion indicates an expected call of TechnicalRejectAppVersion. -func (mr *MockClientMockRecorder) TechnicalRejectAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "TechnicalRejectAppVersion", reflect.TypeOf((*MockClient)(nil).TechnicalRejectAppVersion), varargs...) -} - -// AdminPassAppVersion mocks base method. -func (m *MockClient) AdminPassAppVersion(ctx context.Context, in *pb.PassAppVersionRequest, opts ...grpc.CallOption) (*pb.PassAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "AdminPassAppVersion", varargs...) - ret0, _ := ret[0].(*pb.PassAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AdminPassAppVersion indicates an expected call of AdminPassAppVersion. -func (mr *MockClientMockRecorder) AdminPassAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AdminPassAppVersion", reflect.TypeOf((*MockClient)(nil).AdminPassAppVersion), varargs...) -} - -// AdminRejectAppVersion mocks base method. -func (m *MockClient) AdminRejectAppVersion(ctx context.Context, in *pb.RejectAppVersionRequest, opts ...grpc.CallOption) (*pb.RejectAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "AdminRejectAppVersion", varargs...) - ret0, _ := ret[0].(*pb.RejectAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AdminRejectAppVersion indicates an expected call of AdminRejectAppVersion. -func (mr *MockClientMockRecorder) AdminRejectAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AdminRejectAppVersion", reflect.TypeOf((*MockClient)(nil).AdminRejectAppVersion), varargs...) -} - -// SuspendAppVersion mocks base method. -func (m *MockClient) SuspendAppVersion(ctx context.Context, in *pb.SuspendAppVersionRequest, opts ...grpc.CallOption) (*pb.SuspendAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "SuspendAppVersion", varargs...) - ret0, _ := ret[0].(*pb.SuspendAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// SuspendAppVersion indicates an expected call of SuspendAppVersion. -func (mr *MockClientMockRecorder) SuspendAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SuspendAppVersion", reflect.TypeOf((*MockClient)(nil).SuspendAppVersion), varargs...) -} - -// RecoverAppVersion mocks base method. -func (m *MockClient) RecoverAppVersion(ctx context.Context, in *pb.RecoverAppVersionRequest, opts ...grpc.CallOption) (*pb.RecoverAppVersionResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "RecoverAppVersion", varargs...) - ret0, _ := ret[0].(*pb.RecoverAppVersionResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// RecoverAppVersion indicates an expected call of RecoverAppVersion. -func (mr *MockClientMockRecorder) RecoverAppVersion(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RecoverAppVersion", reflect.TypeOf((*MockClient)(nil).RecoverAppVersion), varargs...) -} - -// CreateRepo mocks base method. -func (m *MockClient) CreateRepo(ctx context.Context, in *pb.CreateRepoRequest, opts ...grpc.CallOption) (*pb.CreateRepoResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateRepo", varargs...) - ret0, _ := ret[0].(*pb.CreateRepoResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateRepo indicates an expected call of CreateRepo. -func (mr *MockClientMockRecorder) CreateRepo(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateRepo", reflect.TypeOf((*MockClient)(nil).CreateRepo), varargs...) -} - -// DescribeRepos mocks base method. -func (m *MockClient) DescribeRepos(ctx context.Context, in *pb.DescribeReposRequest, opts ...grpc.CallOption) (*pb.DescribeReposResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeRepos", varargs...) - ret0, _ := ret[0].(*pb.DescribeReposResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeRepos indicates an expected call of DescribeRepos. -func (mr *MockClientMockRecorder) DescribeRepos(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeRepos", reflect.TypeOf((*MockClient)(nil).DescribeRepos), varargs...) -} - -// ModifyRepo mocks base method. -func (m *MockClient) ModifyRepo(ctx context.Context, in *pb.ModifyRepoRequest, opts ...grpc.CallOption) (*pb.ModifyRepoResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ModifyRepo", varargs...) - ret0, _ := ret[0].(*pb.ModifyRepoResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ModifyRepo indicates an expected call of ModifyRepo. -func (mr *MockClientMockRecorder) ModifyRepo(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyRepo", reflect.TypeOf((*MockClient)(nil).ModifyRepo), varargs...) -} - -// DeleteRepos mocks base method. -func (m *MockClient) DeleteRepos(ctx context.Context, in *pb.DeleteReposRequest, opts ...grpc.CallOption) (*pb.DeleteReposResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteRepos", varargs...) - ret0, _ := ret[0].(*pb.DeleteReposResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteRepos indicates an expected call of DeleteRepos. -func (mr *MockClientMockRecorder) DeleteRepos(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteRepos", reflect.TypeOf((*MockClient)(nil).DeleteRepos), varargs...) -} - -// ValidateRepo mocks base method. -func (m *MockClient) ValidateRepo(ctx context.Context, in *pb.ValidateRepoRequest, opts ...grpc.CallOption) (*pb.ValidateRepoResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ValidateRepo", varargs...) - ret0, _ := ret[0].(*pb.ValidateRepoResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ValidateRepo indicates an expected call of ValidateRepo. -func (mr *MockClientMockRecorder) ValidateRepo(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidateRepo", reflect.TypeOf((*MockClient)(nil).ValidateRepo), varargs...) -} - -// DescribeCategories mocks base method. -func (m *MockClient) DescribeCategories(ctx context.Context, in *pb.DescribeCategoriesRequest, opts ...grpc.CallOption) (*pb.DescribeCategoriesResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeCategories", varargs...) - ret0, _ := ret[0].(*pb.DescribeCategoriesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeCategories indicates an expected call of DescribeCategories. -func (mr *MockClientMockRecorder) DescribeCategories(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeCategories", reflect.TypeOf((*MockClient)(nil).DescribeCategories), varargs...) -} - -// CreateCategory mocks base method. -func (m *MockClient) CreateCategory(ctx context.Context, in *pb.CreateCategoryRequest, opts ...grpc.CallOption) (*pb.CreateCategoryResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateCategory", varargs...) - ret0, _ := ret[0].(*pb.CreateCategoryResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateCategory indicates an expected call of CreateCategory. -func (mr *MockClientMockRecorder) CreateCategory(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateCategory", reflect.TypeOf((*MockClient)(nil).CreateCategory), varargs...) -} - -// ModifyCategory mocks base method. -func (m *MockClient) ModifyCategory(ctx context.Context, in *pb.ModifyCategoryRequest, opts ...grpc.CallOption) (*pb.ModifyCategoryResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ModifyCategory", varargs...) - ret0, _ := ret[0].(*pb.ModifyCategoryResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ModifyCategory indicates an expected call of ModifyCategory. -func (mr *MockClientMockRecorder) ModifyCategory(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ModifyCategory", reflect.TypeOf((*MockClient)(nil).ModifyCategory), varargs...) -} - -// DeleteCategories mocks base method. -func (m *MockClient) DeleteCategories(ctx context.Context, in *pb.DeleteCategoriesRequest, opts ...grpc.CallOption) (*pb.DeleteCategoriesResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteCategories", varargs...) - ret0, _ := ret[0].(*pb.DeleteCategoriesResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteCategories indicates an expected call of DeleteCategories. -func (mr *MockClientMockRecorder) DeleteCategories(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteCategories", reflect.TypeOf((*MockClient)(nil).DeleteCategories), varargs...) -} - -// CreateAttachment mocks base method. -func (m *MockClient) CreateAttachment(ctx context.Context, in *pb.CreateAttachmentRequest, opts ...grpc.CallOption) (*pb.CreateAttachmentResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "CreateAttachment", varargs...) - ret0, _ := ret[0].(*pb.CreateAttachmentResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// CreateAttachment indicates an expected call of CreateAttachment. -func (mr *MockClientMockRecorder) CreateAttachment(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateAttachment", reflect.TypeOf((*MockClient)(nil).CreateAttachment), varargs...) -} - -// AppendAttachment mocks base method. -func (m *MockClient) AppendAttachment(ctx context.Context, in *pb.AppendAttachmentRequest, opts ...grpc.CallOption) (*pb.AppendAttachmentResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "AppendAttachment", varargs...) - ret0, _ := ret[0].(*pb.AppendAttachmentResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// AppendAttachment indicates an expected call of AppendAttachment. -func (mr *MockClientMockRecorder) AppendAttachment(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AppendAttachment", reflect.TypeOf((*MockClient)(nil).AppendAttachment), varargs...) -} - -// ReplaceAttachment mocks base method. -func (m *MockClient) ReplaceAttachment(ctx context.Context, in *pb.ReplaceAttachmentRequest, opts ...grpc.CallOption) (*pb.ReplaceAttachmentResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "ReplaceAttachment", varargs...) - ret0, _ := ret[0].(*pb.ReplaceAttachmentResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// ReplaceAttachment indicates an expected call of ReplaceAttachment. -func (mr *MockClientMockRecorder) ReplaceAttachment(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ReplaceAttachment", reflect.TypeOf((*MockClient)(nil).ReplaceAttachment), varargs...) -} - -// GetAttachments mocks base method. -func (m *MockClient) GetAttachments(ctx context.Context, in *pb.GetAttachmentsRequest, opts ...grpc.CallOption) (*pb.GetAttachmentsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "GetAttachments", varargs...) - ret0, _ := ret[0].(*pb.GetAttachmentsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// GetAttachments indicates an expected call of GetAttachments. -func (mr *MockClientMockRecorder) GetAttachments(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetAttachments", reflect.TypeOf((*MockClient)(nil).GetAttachments), varargs...) -} - -// DeleteAttachments mocks base method. -func (m *MockClient) DeleteAttachments(ctx context.Context, in *pb.DeleteAttachmentsRequest, opts ...grpc.CallOption) (*pb.DeleteAttachmentsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DeleteAttachments", varargs...) - ret0, _ := ret[0].(*pb.DeleteAttachmentsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DeleteAttachments indicates an expected call of DeleteAttachments. -func (mr *MockClientMockRecorder) DeleteAttachments(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DeleteAttachments", reflect.TypeOf((*MockClient)(nil).DeleteAttachments), varargs...) -} - -// IndexRepo mocks base method. -func (m *MockClient) IndexRepo(ctx context.Context, in *pb.IndexRepoRequest, opts ...grpc.CallOption) (*pb.IndexRepoResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "IndexRepo", varargs...) - ret0, _ := ret[0].(*pb.IndexRepoResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// IndexRepo indicates an expected call of IndexRepo. -func (mr *MockClientMockRecorder) IndexRepo(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IndexRepo", reflect.TypeOf((*MockClient)(nil).IndexRepo), varargs...) -} - -// DescribeRepoEvents mocks base method. -func (m *MockClient) DescribeRepoEvents(ctx context.Context, in *pb.DescribeRepoEventsRequest, opts ...grpc.CallOption) (*pb.DescribeRepoEventsResponse, error) { - m.ctrl.T.Helper() - varargs := []interface{}{ctx, in} - for _, a := range opts { - varargs = append(varargs, a) - } - ret := m.ctrl.Call(m, "DescribeRepoEvents", varargs...) - ret0, _ := ret[0].(*pb.DescribeRepoEventsResponse) - ret1, _ := ret[1].(error) - return ret0, ret1 -} - -// DescribeRepoEvents indicates an expected call of DescribeRepoEvents. -func (mr *MockClientMockRecorder) DescribeRepoEvents(ctx, in interface{}, opts ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{ctx, in}, opts...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "DescribeRepoEvents", reflect.TypeOf((*MockClient)(nil).DescribeRepoEvents), varargs...) -} - -// UpsertRuntime mocks base method. -func (m *MockClient) UpsertRuntime(cluster, kubeConfig string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "UpsertRuntime", cluster, kubeConfig) - ret0, _ := ret[0].(error) - return ret0 -} - -// UpsertRuntime indicates an expected call of UpsertRuntime. -func (mr *MockClientMockRecorder) UpsertRuntime(cluster, kubeConfig interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "UpsertRuntime", reflect.TypeOf((*MockClient)(nil).UpsertRuntime), cluster, kubeConfig) -} - -// CleanupRuntime mocks base method. -func (m *MockClient) CleanupRuntime(cluster string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "CleanupRuntime", cluster) - ret0, _ := ret[0].(error) - return ret0 -} - -// CleanupRuntime indicates an expected call of CleanupRuntime. -func (mr *MockClientMockRecorder) CleanupRuntime(cluster interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CleanupRuntime", reflect.TypeOf((*MockClient)(nil).CleanupRuntime), cluster) -} - -// MigrateRuntime mocks base method. -func (m *MockClient) MigrateRuntime(runtimeId, cluster string) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "MigrateRuntime", runtimeId, cluster) - ret0, _ := ret[0].(error) - return ret0 -} - -// MigrateRuntime indicates an expected call of MigrateRuntime. -func (mr *MockClientMockRecorder) MigrateRuntime(runtimeId, cluster interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "MigrateRuntime", reflect.TypeOf((*MockClient)(nil).MigrateRuntime), runtimeId, cluster) -} diff --git a/pkg/simple/client/openpitrix/openpitrix.go b/pkg/simple/client/openpitrix/openpitrix.go deleted file mode 100644 index f9bfea9a773f0f99b0370cdd1af1828077ace342..0000000000000000000000000000000000000000 --- a/pkg/simple/client/openpitrix/openpitrix.go +++ /dev/null @@ -1,326 +0,0 @@ -/* - - Copyright 2020 The KubeSphere 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 openpitrix - -import ( - "context" - "fmt" - "github.com/golang/protobuf/ptypes/wrappers" - "k8s.io/klog" - "openpitrix.io/openpitrix/pkg/manager" - "openpitrix.io/openpitrix/pkg/pb" - "openpitrix.io/openpitrix/pkg/sender" - "openpitrix.io/openpitrix/pkg/util/ctxutil" - "strconv" - "strings" -) - -const ( - RuntimeAnnotationKey = "openpitrix_runtime" - KubernetesProvider = "kubernetes" - Unknown = "-" - DeploySuffix = "-Deployment" - DaemonSuffix = "-DaemonSet" - StateSuffix = "-StatefulSet" - SystemUsername = "system" - SystemUserPath = ":system" -) - -type Client interface { - pb.RuntimeManagerClient - pb.ClusterManagerClient - pb.AppManagerClient - pb.RepoManagerClient - pb.CategoryManagerClient - pb.AttachmentManagerClient - pb.RepoIndexerClient - // upsert the openpitrix runtime when cluster is updated or created - UpsertRuntime(cluster string, kubeConfig string) error - // clean up the openpitrix runtime when cluster is deleted - CleanupRuntime(cluster string) error - // migrate the openpitrix runtime when upgrade ks2.x to ks3.x - MigrateRuntime(runtimeId string, cluster string) error -} - -type client struct { - pb.RuntimeManagerClient - pb.ClusterManagerClient - pb.AppManagerClient - pb.RepoManagerClient - pb.CategoryManagerClient - pb.AttachmentManagerClient - pb.RepoIndexerClient -} - -func (c *client) UpsertRuntime(cluster string, kubeConfig string) error { - ctx := SystemContext() - req := &pb.CreateRuntimeCredentialRequest{ - Name: &wrappers.StringValue{Value: fmt.Sprintf("kubeconfig-%s", cluster)}, - Provider: &wrappers.StringValue{Value: KubernetesProvider}, - Description: &wrappers.StringValue{Value: "kubeconfig"}, - RuntimeUrl: &wrappers.StringValue{Value: "kubesphere"}, - RuntimeCredentialContent: &wrappers.StringValue{Value: kubeConfig}, - RuntimeCredentialId: &wrappers.StringValue{Value: cluster}, - } - _, err := c.CreateRuntimeCredential(ctx, req) - if err != nil { - return err - } - _, err = c.CreateRuntime(ctx, &pb.CreateRuntimeRequest{ - Name: &wrappers.StringValue{Value: cluster}, - RuntimeCredentialId: &wrappers.StringValue{Value: cluster}, - Provider: &wrappers.StringValue{Value: KubernetesProvider}, - Zone: &wrappers.StringValue{Value: cluster}, - RuntimeId: &wrappers.StringValue{Value: cluster}, - }) - - return err -} - -func (c *client) CleanupRuntime(cluster string) error { - ctx := SystemContext() - _, err := c.DeleteClusterInRuntime(ctx, &pb.DeleteClusterInRuntimeRequest{ - RuntimeId: []string{cluster}, - }) - return err -} - -func (c *client) MigrateRuntime(runtimeId string, cluster string) error { - ctx := SystemContext() - _, err := c.MigrateClusterInRuntime(ctx, &pb.MigrateClusterInRuntimeRequest{ - FromRuntimeId: runtimeId, - ToRuntimeId: cluster, - }) - return err -} - -func parseToHostPort(endpoint string) (string, int, error) { - args := strings.Split(endpoint, ":") - if len(args) != 2 { - return "", 0, fmt.Errorf("invalid server host: %s", endpoint) - } - host := args[0] - port, err := strconv.Atoi(args[1]) - if err != nil { - return "", 0, err - } - return host, port, nil -} - -func newRuntimeManagerClient(endpoint string) (pb.RuntimeManagerClient, error) { - if len(endpoint) == 0 { - return nil, nil - } - - host, port, err := parseToHostPort(endpoint) - if err != nil { - return nil, err - } - - conn, err := manager.NewClient(host, port) - if err != nil { - return nil, err - } - return pb.NewRuntimeManagerClient(conn), nil -} -func newClusterManagerClient(endpoint string) (pb.ClusterManagerClient, error) { - if len(endpoint) == 0 { - return nil, nil - } - - host, port, err := parseToHostPort(endpoint) - if err != nil { - return nil, err - } - conn, err := manager.NewClient(host, port) - if err != nil { - return nil, err - } - return pb.NewClusterManagerClient(conn), nil -} -func newCategoryManagerClient(endpoint string) (pb.CategoryManagerClient, error) { - if len(endpoint) == 0 { - return nil, nil - } - - host, port, err := parseToHostPort(endpoint) - if err != nil { - return nil, err - } - conn, err := manager.NewClient(host, port) - if err != nil { - return nil, err - } - return pb.NewCategoryManagerClient(conn), nil -} - -func newAttachmentManagerClient(endpoint string) (pb.AttachmentManagerClient, error) { - if len(endpoint) == 0 { - return nil, nil - } - - host, port, err := parseToHostPort(endpoint) - if err != nil { - return nil, err - } - conn, err := manager.NewClient(host, port) - if err != nil { - return nil, err - } - return pb.NewAttachmentManagerClient(conn), nil -} - -func newRepoManagerClient(endpoint string) (pb.RepoManagerClient, error) { - if len(endpoint) == 0 { - return nil, nil - } - - host, port, err := parseToHostPort(endpoint) - if err != nil { - return nil, err - } - conn, err := manager.NewClient(host, port) - if err != nil { - return nil, err - } - return pb.NewRepoManagerClient(conn), nil -} - -func newRepoIndexer(endpoint string) (pb.RepoIndexerClient, error) { - if len(endpoint) == 0 { - return nil, nil - } - - host, port, err := parseToHostPort(endpoint) - if err != nil { - return nil, err - } - conn, err := manager.NewClient(host, port) - if err != nil { - return nil, err - } - return pb.NewRepoIndexerClient(conn), nil -} - -func newAppManagerClient(endpoint string) (pb.AppManagerClient, error) { - if len(endpoint) == 0 { - return nil, nil - } - - host, port, err := parseToHostPort(endpoint) - if err != nil { - return nil, err - } - conn, err := manager.NewClient(host, port) - if err != nil { - return nil, err - } - return pb.NewAppManagerClient(conn), nil -} - -// will return a nil client and nil error if endpoint is empty -func NewClient(options *Options) (Client, error) { - if options.IsEmpty() { - return nil, nil - } - - runtimeMangerClient, err := newRuntimeManagerClient(options.RuntimeManagerEndpoint) - if err != nil { - klog.Error(err) - return nil, err - } - - clusterManagerClient, err := newClusterManagerClient(options.ClusterManagerEndpoint) - if err != nil { - klog.Error(err) - return nil, err - } - - repoManagerClient, err := newRepoManagerClient(options.RepoManagerEndpoint) - if err != nil { - klog.Error(err) - return nil, err - } - - repoIndexerClient, err := newRepoIndexer(options.RepoIndexerEndpoint) - if err != nil { - klog.Error(err) - return nil, err - } - - appManagerClient, err := newAppManagerClient(options.AppManagerEndpoint) - if err != nil { - klog.Error(err) - return nil, err - } - - categoryManagerClient, err := newCategoryManagerClient(options.CategoryManagerEndpoint) - if err != nil { - klog.Error(err) - return nil, err - } - - attachmentManagerClient, err := newAttachmentManagerClient(options.AttachmentManagerEndpoint) - if err != nil { - klog.Error(err) - return nil, err - } - - client := client{ - RuntimeManagerClient: runtimeMangerClient, - ClusterManagerClient: clusterManagerClient, - RepoManagerClient: repoManagerClient, - AppManagerClient: appManagerClient, - CategoryManagerClient: categoryManagerClient, - AttachmentManagerClient: attachmentManagerClient, - RepoIndexerClient: repoIndexerClient, - } - - return &client, nil -} - -func SystemContext() context.Context { - ctx := context.Background() - ctx = ctxutil.ContextWithSender(ctx, sender.New(SystemUsername, SystemUserPath, "")) - return ctx -} -func ContextWithUsername(username string) context.Context { - ctx := context.Background() - if username == "" { - username = SystemUsername - } - ctx = ctxutil.ContextWithSender(ctx, sender.New(username, SystemUserPath, "")) - return ctx -} - -func IsNotFound(err error) bool { - if strings.Contains(err.Error(), "not exist") { - return true - } - if strings.Contains(err.Error(), "not found") { - return true - } - return false -} - -func IsDeleted(err error) bool { - if strings.Contains(err.Error(), "is [deleted]") { - return true - } - return false -} diff --git a/pkg/simple/client/openpitrix/options.go b/pkg/simple/client/openpitrix/options.go index edeb38c1125ebfa2cb2af798f355217546364e86..f6d09681f59d1da977e028365af2223e455dbbfc 100644 --- a/pkg/simple/client/openpitrix/options.go +++ b/pkg/simple/client/openpitrix/options.go @@ -17,113 +17,58 @@ limitations under the License. package openpitrix import ( - "fmt" "github.com/spf13/pflag" + "kubesphere.io/kubesphere/pkg/simple/client/s3" "kubesphere.io/kubesphere/pkg/utils/reflectutils" ) type Options struct { - RuntimeManagerEndpoint string `json:"runtimeManagerEndpoint,omitempty" yaml:"runtimeManagerEndpoint,omitempty"` - ClusterManagerEndpoint string `json:"clusterManagerEndpoint,omitempty" yaml:"clusterManagerEndpoint,omitempty"` - RepoManagerEndpoint string `json:"repoManagerEndpoint,omitempty" yaml:"repoManagerEndpoint,omitempty"` - AppManagerEndpoint string `json:"appManagerEndpoint,omitempty" yaml:"appManagerEndpoint,omitempty"` - CategoryManagerEndpoint string `json:"categoryManagerEndpoint,omitempty" yaml:"categoryManagerEndpoint,omitempty"` - AttachmentManagerEndpoint string `json:"attachmentManagerEndpoint,omitempty" yaml:"attachmentManagerEndpoint,omitempty"` - RepoIndexerEndpoint string `json:"repoIndexerEndpoint,omitempty" yaml:"repoIndexerEndpoint,omitempty"` + S3Options *s3.Options `json:"s3,omitempty" yaml:"s3,omitempty" mapstructure:"s3"` } func NewOptions() *Options { - return &Options{} + return &Options{ + S3Options: &s3.Options{}, + } } -func (s *Options) ApplyTo(options *Options) { - if options == nil { - options = s - return - } - if s.RuntimeManagerEndpoint != "" { - reflectutils.Override(options, s) - } +// Validate check options values +func (s *Options) Validate() []error { + var errors []error + + return errors } func (s *Options) IsEmpty() bool { - return s.RuntimeManagerEndpoint == "" && - s.ClusterManagerEndpoint == "" && - s.RepoManagerEndpoint == "" && - s.AppManagerEndpoint == "" && - s.CategoryManagerEndpoint == "" && - s.AttachmentManagerEndpoint == "" && - s.RepoIndexerEndpoint == "" + return s.S3Options == nil || s.S3Options.Endpoint == "" } -func (s *Options) Validate() []error { - var errs []error - - if s.RuntimeManagerEndpoint != "" { - _, _, err := parseToHostPort(s.RuntimeManagerEndpoint) - if err != nil { - errs = append(errs, fmt.Errorf("invalid host port:%s", s.RuntimeManagerEndpoint)) - } - } - if s.ClusterManagerEndpoint != "" { - _, _, err := parseToHostPort(s.ClusterManagerEndpoint) - if err != nil { - errs = append(errs, fmt.Errorf("invalid host port:%s", s.ClusterManagerEndpoint)) - } - } - if s.RepoManagerEndpoint != "" { - _, _, err := parseToHostPort(s.RepoManagerEndpoint) - if err != nil { - errs = append(errs, fmt.Errorf("invalid host port:%s", s.RepoManagerEndpoint)) - } - } - if s.RepoIndexerEndpoint != "" { - _, _, err := parseToHostPort(s.RepoIndexerEndpoint) - if err != nil { - errs = append(errs, fmt.Errorf("invalid host port:%s", s.RepoIndexerEndpoint)) - } - } - if s.AppManagerEndpoint != "" { - _, _, err := parseToHostPort(s.AppManagerEndpoint) - if err != nil { - errs = append(errs, fmt.Errorf("invalid host port:%s", s.AppManagerEndpoint)) - } - } - if s.CategoryManagerEndpoint != "" { - _, _, err := parseToHostPort(s.CategoryManagerEndpoint) - if err != nil { - errs = append(errs, fmt.Errorf("invalid host port:%s", s.CategoryManagerEndpoint)) - } - } - if s.AttachmentManagerEndpoint != "" { - _, _, err := parseToHostPort(s.CategoryManagerEndpoint) - if err != nil { - errs = append(errs, fmt.Errorf("invalid host port:%s", s.CategoryManagerEndpoint)) - } +// ApplyTo overrides options if it's valid, which endpoint is not empty +func (s *Options) ApplyTo(options *Options) { + if s.S3Options != nil { + reflectutils.Override(options, s) } - - return errs } +// AddFlags add options flags to command line flags, func (s *Options) AddFlags(fs *pflag.FlagSet, c *Options) { - fs.StringVar(&s.RuntimeManagerEndpoint, "openpitrix-runtime-manager-endpoint", c.RuntimeManagerEndpoint, ""+ - "OpenPitrix runtime manager endpoint") + // if s3-endpoint if left empty, following options will be ignored + fs.StringVar(&s.S3Options.Endpoint, "openpitrix-s3-endpoint", c.S3Options.Endpoint, ""+ + "Endpoint to access to s3 object storage service for openpitrix, if left blank, the following options "+ + "will be ignored.") + + fs.StringVar(&s.S3Options.Region, "openpitrix-s3-region", c.S3Options.Region, ""+ + "Region of s3 that openpitrix will access to, like us-east-1.") - fs.StringVar(&s.AppManagerEndpoint, "openpitrix-app-manager-endpoint", c.AppManagerEndpoint, ""+ - "OpenPitrix app manager endpoint") + fs.StringVar(&s.S3Options.AccessKeyID, "openpitrix-s3-access-key-id", c.S3Options.AccessKeyID, "access key of openpitrix s3") - fs.StringVar(&s.ClusterManagerEndpoint, "openpitrix-cluster-manager-endpoint", c.ClusterManagerEndpoint, ""+ - "OpenPitrix cluster manager endpoint") + fs.StringVar(&s.S3Options.SecretAccessKey, "openpitrix-s3-secret-access-key", c.S3Options.SecretAccessKey, "secret access key of openpitrix s3") - fs.StringVar(&s.CategoryManagerEndpoint, "openpitrix-category-manager-endpoint", c.CategoryManagerEndpoint, ""+ - "OpenPitrix category manager endpoint") + fs.StringVar(&s.S3Options.SessionToken, "openpitrix-s3-session-token", c.S3Options.SessionToken, "session token of openpitrix s3") - fs.StringVar(&s.RepoManagerEndpoint, "openpitrix-repo-manager-endpoint", c.RepoManagerEndpoint, ""+ - "OpenPitrix repo manager endpoint") + fs.StringVar(&s.S3Options.Bucket, "openpitrix-s3-bucket", c.S3Options.Bucket, "bucket name of openpitrix s3") - fs.StringVar(&s.RepoIndexerEndpoint, "openpitrix-repo-indexer-endpoint", c.RepoIndexerEndpoint, ""+ - "OpenPitrix repo indexer endpoint") + fs.BoolVar(&s.S3Options.DisableSSL, "openpitrix-s3-disable-SSL", c.S3Options.DisableSSL, "disable ssl") - fs.StringVar(&s.AttachmentManagerEndpoint, "openpitrix-attachment-manager-endpoint", c.AttachmentManagerEndpoint, ""+ - "OpenPitrix attachment manager endpoint") + fs.BoolVar(&s.S3Options.ForcePathStyle, "openpitrix-s3-force-path-style", c.S3Options.ForcePathStyle, "force path style") } diff --git a/pkg/simple/client/s3/fake/fakes3.go b/pkg/simple/client/s3/fake/fakes3.go index 801d6a6c892326e532aea9bb833c6857c945c6e6..4d404de0c81d43c732c79ab8cbe73f3734883e7a 100644 --- a/pkg/simple/client/s3/fake/fakes3.go +++ b/pkg/simple/client/s3/fake/fakes3.go @@ -21,6 +21,7 @@ import ( "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/s3" "io" + "io/ioutil" ) type FakeS3 struct { @@ -61,3 +62,14 @@ func (s *FakeS3) Delete(key string) error { delete(s.Storage, key) return nil } + +func (s *FakeS3) Read(key string) ([]byte, error) { + if o, ok := s.Storage[key]; ok && o.Body != nil { + data, err := ioutil.ReadAll(o.Body) + if err != nil { + return nil, err + } + return data, nil + } + return nil, awserr.New(s3.ErrCodeNoSuchKey, "no such object", nil) +} diff --git a/pkg/simple/client/s3/interface.go b/pkg/simple/client/s3/interface.go index 8c5d8f9be55dcd535c75fb1f4b796a4c015d3d07..681c9dc54e60936a62963ef8f84b070407fbafe3 100644 --- a/pkg/simple/client/s3/interface.go +++ b/pkg/simple/client/s3/interface.go @@ -21,6 +21,9 @@ import ( ) type Interface interface { + //read the content, caller should close the io.ReadCloser. + Read(key string) ([]byte, error) + // Upload uploads a object to storage and returns object location if succeeded Upload(key, fileName string, body io.Reader) error diff --git a/pkg/simple/client/s3/s3.go b/pkg/simple/client/s3/s3.go index e55b9ffd4ce5f8b78771e2379f57adbf699e45ba..8d4f7a82244eaa842f6eaba1393d1d64d366ed82 100644 --- a/pkg/simple/client/s3/s3.go +++ b/pkg/simple/client/s3/s3.go @@ -49,6 +49,24 @@ func (s *Client) Upload(key, fileName string, body io.Reader) error { return err } +func (s *Client) Read(key string) ([]byte, error) { + + downloader := s3manager.NewDownloader(s.s3Session) + + writer := aws.NewWriteAtBuffer([]byte{}) + _, err := downloader.Download(writer, + &s3.GetObjectInput{ + Bucket: aws.String(s.bucket), + Key: aws.String(key), + }) + + if err != nil { + return nil, err + } + + return writer.Bytes(), nil +} + func (s *Client) GetDownloadURL(key string, fileName string) (string, error) { req, _ := s.s3Client.GetObjectRequest(&s3.GetObjectInput{ Bucket: aws.String(s.bucket), diff --git a/pkg/utils/clusterclient/clusterclient.go b/pkg/utils/clusterclient/clusterclient.go new file mode 100644 index 0000000000000000000000000000000000000000..8c3508c9d8a82781567bf31389ae9f1e2cd4e2f3 --- /dev/null +++ b/pkg/utils/clusterclient/clusterclient.go @@ -0,0 +1,207 @@ +/* +Copyright 2020 KubeSphere 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 clusterclient + +import ( + "fmt" + corev1 "k8s.io/api/core/v1" + "k8s.io/client-go/rest" + "k8s.io/client-go/tools/cache" + "k8s.io/client-go/tools/clientcmd" + "k8s.io/klog" + clusterv1alpha1 "kubesphere.io/kubesphere/pkg/apis/cluster/v1alpha1" + clusterinformer "kubesphere.io/kubesphere/pkg/client/informers/externalversions/cluster/v1alpha1" + "net/http" + "net/url" + "sync" +) + +var ( + ClusterNotExistsFormat = "cluster %s not exists" +) + +type innerCluster struct { + KubernetesURL *url.URL + KubesphereURL *url.URL + Transport http.RoundTripper +} + +type clusterClients struct { + sync.RWMutex + clusterMap map[string]*clusterv1alpha1.Cluster + clusterKubeconfig map[string]string + + // build a in memory cluster cache to speed things up + innerClusters map[string]*innerCluster +} + +type ClusterClients interface { + IsHostCluster(cluster *clusterv1alpha1.Cluster) bool + IsClusterReady(cluster *clusterv1alpha1.Cluster) bool + GetClusterKubeconfig(string) (string, error) + Get(string) (*clusterv1alpha1.Cluster, error) + GetInnerCluster(string) *innerCluster +} + +func (c *clusterClients) IsClusterReady(cluster *clusterv1alpha1.Cluster) bool { + for _, condition := range cluster.Status.Conditions { + if condition.Type == clusterv1alpha1.ClusterReady && condition.Status == corev1.ConditionTrue { + return true + } + } + return false +} + +func (c *clusterClients) IsHostCluster(cluster *clusterv1alpha1.Cluster) bool { + if _, ok := cluster.Labels[clusterv1alpha1.HostCluster]; ok { + return true + } + return false +} + +func (c *clusterClients) GetInnerCluster(name string) *innerCluster { + c.RLock() + defer c.RUnlock() + if cluster, ok := c.innerClusters[name]; ok { + return cluster + } + return nil +} + +var c *clusterClients +var lock sync.Mutex + +func NewClusterClient(clusterInformer clusterinformer.ClusterInformer) ClusterClients { + + if c == nil { + lock.Lock() + defer lock.Unlock() + + if c != nil { + return c + } + + c = &clusterClients{ + clusterMap: map[string]*clusterv1alpha1.Cluster{}, + clusterKubeconfig: map[string]string{}, + innerClusters: make(map[string]*innerCluster), + } + + clusterInformer.Informer().AddEventHandler(cache.ResourceEventHandlerFuncs{ + AddFunc: func(obj interface{}) { + c.addCluster(obj) + }, + UpdateFunc: func(oldObj, newObj interface{}) { + c.removeCluster(oldObj) + c.addCluster(newObj) + }, + DeleteFunc: func(obj interface{}) { + c.removeCluster(obj) + }, + }) + } + + return c +} + +func (c *clusterClients) removeCluster(obj interface{}) { + cluster := obj.(*clusterv1alpha1.Cluster) + klog.V(4).Infof("remove cluster %s", cluster.Name) + c.Lock() + if _, ok := c.clusterMap[cluster.Name]; ok { + delete(c.clusterMap, cluster.Name) + delete(c.innerClusters, cluster.Name) + delete(c.clusterKubeconfig, cluster.Name) + } + c.Unlock() +} + +func newInnerCluster(cluster *clusterv1alpha1.Cluster) *innerCluster { + kubernetesEndpoint, err := url.Parse(cluster.Spec.Connection.KubernetesAPIEndpoint) + if err != nil { + klog.Errorf("Parse kubernetes apiserver endpoint %s failed, %v", cluster.Spec.Connection.KubernetesAPIEndpoint, err) + return nil + } + + kubesphereEndpoint, err := url.Parse(cluster.Spec.Connection.KubeSphereAPIEndpoint) + if err != nil { + klog.Errorf("Parse kubesphere apiserver endpoint %s failed, %v", cluster.Spec.Connection.KubeSphereAPIEndpoint, err) + return nil + } + + // prepare for + clientConfig, err := clientcmd.NewClientConfigFromBytes(cluster.Spec.Connection.KubeConfig) + if err != nil { + klog.Errorf("Unable to create client config from kubeconfig bytes, %#v", err) + return nil + } + + clusterConfig, err := clientConfig.ClientConfig() + if err != nil { + klog.Errorf("Failed to get client config, %#v", err) + return nil + } + + transport, err := rest.TransportFor(clusterConfig) + if err != nil { + klog.Errorf("Create transport failed, %v", err) + return nil + } + + return &innerCluster{ + KubernetesURL: kubernetesEndpoint, + KubesphereURL: kubesphereEndpoint, + Transport: transport, + } +} + +func (c *clusterClients) addCluster(obj interface{}) { + cluster := obj.(*clusterv1alpha1.Cluster) + klog.V(4).Infof("add new cluster %s", cluster.Name) + _, err := url.Parse(cluster.Spec.Connection.KubernetesAPIEndpoint) + if err != nil { + klog.Errorf("Parse kubernetes apiserver endpoint %s failed, %v", cluster.Spec.Connection.KubernetesAPIEndpoint, err) + return + } + + innerCluster := newInnerCluster(cluster) + c.Lock() + c.clusterMap[cluster.Name] = cluster + c.clusterKubeconfig[cluster.Name] = string(cluster.Spec.Connection.KubeConfig) + c.innerClusters[cluster.Name] = innerCluster + c.Unlock() +} + +func (c *clusterClients) GetClusterKubeconfig(clusterName string) (string, error) { + c.RLock() + defer c.RUnlock() + if c, exists := c.clusterKubeconfig[clusterName]; exists { + return c, nil + } else { + return "", fmt.Errorf(ClusterNotExistsFormat, clusterName) + } +} + +func (c *clusterClients) Get(clusterName string) (*clusterv1alpha1.Cluster, error) { + c.RLock() + defer c.RUnlock() + if cluster, exists := c.clusterMap[clusterName]; exists { + return cluster, nil + } else { + return nil, fmt.Errorf(ClusterNotExistsFormat, clusterName) + } +} diff --git a/pkg/utils/metrics/metrics.go b/pkg/utils/metrics/metrics.go index b18a1dd3760a46065db2acd2003c3f2180a8ef8c..fbfea1621b6f290940dfa66a5116199e288e5a77 100644 --- a/pkg/utils/metrics/metrics.go +++ b/pkg/utils/metrics/metrics.go @@ -1,3 +1,20 @@ +// /* +// Copyright 2020 The KubeSphere 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 metrics import ( @@ -22,13 +39,12 @@ var ( ) func init() { + compbasemetrics.BuildVersion = versionGet + defaultRegistry = compbasemetrics.NewKubeRegistry() MustRegister = defaultRegistry.MustRegister Register = defaultRegistry.Register RawMustRegister = defaultRegistry.RawMustRegister - - RawMustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{})) - RawMustRegister(prometheus.NewGoCollector()) } // DefaultMetrics installs the default prometheus metrics handler @@ -36,6 +52,9 @@ type DefaultMetrics struct{} // Install adds the DefaultMetrics handler func (m DefaultMetrics) Install(c *restful.Container) { + RawMustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{})) + RawMustRegister(prometheus.NewGoCollector()) + c.Handle("/kapis/metrics", Handler()) } @@ -59,5 +78,5 @@ func versionGet() apimachineryversion.Info { // already instrumented with InstrumentHandler (using "prometheus" as handler // name). func Handler() http.Handler { - return promhttp.InstrumentMetricHandler(prometheus.DefaultRegisterer, promhttp.HandlerFor(defaultRegistry, promhttp.HandlerOpts{})) + return promhttp.InstrumentMetricHandler(prometheus.NewRegistry(), promhttp.HandlerFor(defaultRegistry, promhttp.HandlerOpts{})) } diff --git a/pkg/utils/reposcache/repo_cahes.go b/pkg/utils/reposcache/repo_cahes.go new file mode 100644 index 0000000000000000000000000000000000000000..99aecd31a364bf42a6cba3f6e82752b9d66d90f5 --- /dev/null +++ b/pkg/utils/reposcache/repo_cahes.go @@ -0,0 +1,349 @@ +// /* +// Copyright 2020 The KubeSphere 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 reposcache + +import ( + "context" + "encoding/base64" + "errors" + "fmt" + "io/ioutil" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/klog" + "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/simple/client/openpitrix/helmrepoindex" + "os" + "path" + "strings" + "sync" +) + +var WorkDir string + +func NewReposCache() ReposCache { + return &cachedRepos{ + chartsInRepo: map[workspace]map[string]int{}, + repos: map[string]*v1alpha1.HelmRepo{}, + apps: map[string]*v1alpha1.HelmApplication{}, + versions: map[string]*v1alpha1.HelmApplicationVersion{}, + repoCtgCounts: map[string]map[string]int{}, + } +} + +type ReposCache interface { + AddRepo(repo *v1alpha1.HelmRepo) error + DeleteRepo(repo *v1alpha1.HelmRepo) error + + GetApplication(string) (*v1alpha1.HelmApplication, bool) + GetAppVersion(string) (*v1alpha1.HelmApplicationVersion, bool, error) + GetAppVersionWithData(string) (*v1alpha1.HelmApplicationVersion, bool, error) + + ListAppVersionsByAppId(appId string) (ret []*v1alpha1.HelmApplicationVersion, exists bool) + ListApplicationsByRepoId(repoId string) (ret []*v1alpha1.HelmApplication, exists bool) +} + +type workspace string +type cachedRepos struct { + sync.RWMutex + + chartsInRepo map[workspace]map[string]int + repoCtgCounts map[string]map[string]int + + repos map[string]*v1alpha1.HelmRepo + apps map[string]*v1alpha1.HelmApplication + versions map[string]*v1alpha1.HelmApplicationVersion +} + +func (c *cachedRepos) deleteRepo(repo *v1alpha1.HelmRepo) { + if len(repo.Status.Data) == 0 { + return + } + index, err := helmrepoindex.ByteArrayToSavedIndex([]byte(repo.Status.Data)) + if err != nil { + klog.Errorf("json unmarshal repo %s failed, error: %s", repo.Name, err) + return + } + + klog.V(4).Infof("delete repo %s from cache", repo.Name) + c.Lock() + defer c.Unlock() + repoId := repo.GetHelmRepoId() + ws := workspace(repo.GetWorkspace()) + if _, exists := c.chartsInRepo[ws]; exists { + delete(c.chartsInRepo[ws], repoId) + } + + delete(c.repoCtgCounts, repoId) + delete(c.repos, repoId) + + for _, app := range index.Applications { + delete(c.apps, app.ApplicationId) + for _, ver := range app.Charts { + delete(c.versions, ver.ApplicationVersionId) + } + } +} + +func loadBuiltinChartData(name, version string) ([]byte, error) { + fName := path.Join(WorkDir, "chart", fmt.Sprintf("%s-%s.tgz", name, version)) + f, err := os.Open(fName) + if err != nil { + return nil, err + } + data, err := ioutil.ReadAll(f) + if err != nil { + klog.Errorf("read index failed, error: %s", err) + return nil, err + } + return data, nil +} + +func (c *cachedRepos) DeleteRepo(repo *v1alpha1.HelmRepo) error { + c.deleteRepo(repo) + return nil +} + +func (c *cachedRepos) GetApplication(appId string) (app *v1alpha1.HelmApplication, exists bool) { + c.RLock() + defer c.RUnlock() + if app, exists := c.apps[appId]; exists { + return app, true + } + return +} + +func (c *cachedRepos) AddRepo(repo *v1alpha1.HelmRepo) error { + return c.addRepo(repo, false) +} + +//Add new Repo to cachedRepos +func (c *cachedRepos) addRepo(repo *v1alpha1.HelmRepo, builtin bool) error { + if len(repo.Status.Data) == 0 { + return nil + } + index, err := helmrepoindex.ByteArrayToSavedIndex([]byte(repo.Status.Data)) + if err != nil { + klog.Errorf("json unmarshal repo %s failed, error: %s", repo.Name, err) + return err + } + + klog.V(4).Infof("add repo %s to cache", repo.Name) + + c.Lock() + defer c.Unlock() + + ws := workspace(repo.GetWorkspace()) + if _, exists := c.chartsInRepo[ws]; !exists { + c.chartsInRepo[ws] = make(map[string]int) + } + + repoId := repo.GetHelmRepoId() + c.repos[repoId] = repo + //c.repoCtgCounts[repo.GetHelmRepoId()] = make(map[string]int) + if _, exists := c.repoCtgCounts[repoId]; !exists { + c.repoCtgCounts[repoId] = map[string]int{} + } + var appName string + + chartsCount := 0 + for key, app := range index.Applications { + if builtin { + appName = v1alpha1.HelmApplicationIdPrefix + app.Name + } else { + appName = app.ApplicationId + } + + HelmApp := v1alpha1.HelmApplication{ + ObjectMeta: metav1.ObjectMeta{ + Name: appName, + Annotations: map[string]string{ + constants.CreatorAnnotationKey: repo.GetCreator(), + }, + Labels: map[string]string{ + constants.ChartRepoIdLabelKey: repo.GetHelmRepoId(), + }, + }, + Spec: v1alpha1.HelmApplicationSpec{ + Name: key, + Description: app.Description, + Icon: app.Icon, + }, + Status: v1alpha1.HelmApplicationStatus{ + State: v1alpha1.StateActive, + }, + } + c.apps[app.ApplicationId] = &HelmApp + + var ctg, appVerName string + var chartData []byte + for _, ver := range app.Charts { + chartsCount += 1 + if ver.Annotations != nil && ver.Annotations["category"] != "" { + ctg = ver.Annotations["category"] + } + if builtin { + appVerName = base64.StdEncoding.EncodeToString([]byte(ver.Name + ver.Version)) + chartData, err = loadBuiltinChartData(ver.Name, ver.Version) + if err != nil { + return err + } + } else { + appVerName = ver.ApplicationVersionId + } + + version := &v1alpha1.HelmApplicationVersion{ + ObjectMeta: metav1.ObjectMeta{ + Name: appVerName, + Annotations: map[string]string{constants.CreatorAnnotationKey: repo.GetCreator()}, + Labels: map[string]string{ + constants.ChartApplicationIdLabelKey: appName, + constants.ChartRepoIdLabelKey: repo.GetHelmRepoId(), + }, + CreationTimestamp: metav1.Time{Time: ver.Created}, + }, + Spec: v1alpha1.HelmApplicationVersionSpec{ + Metadata: &v1alpha1.Metadata{ + Name: ver.Name, + AppVersion: ver.AppVersion, + Version: ver.Version, + }, + URLs: ver.URLs, + Digest: ver.Digest, + Data: chartData, + }, + Status: v1alpha1.HelmApplicationVersionStatus{ + State: v1alpha1.StateActive, + }, + } + c.versions[ver.ApplicationVersionId] = version + } + + //modify application category + ctgId := "" + if ctg != "" { + if c.apps[app.ApplicationId].Annotations == nil { + c.apps[app.ApplicationId].Annotations = map[string]string{constants.CategoryIdLabelKey: ctg} + } else { + c.apps[app.ApplicationId].Annotations[constants.CategoryIdLabelKey] = ctg + } + ctgId = ctg + } else { + ctgId = v1alpha1.UncategorizedId + } + + if _, exists := c.repoCtgCounts[repoId][ctgId]; !exists { + c.repoCtgCounts[repoId][ctgId] = 1 + } else { + c.repoCtgCounts[repoId][ctgId] += 1 + } + } + + c.chartsInRepo[ws][repo.GetHelmRepoId()] = chartsCount + + return nil +} + +func (c *cachedRepos) ListApplicationsByRepoId(repoId string) (ret []*v1alpha1.HelmApplication, exists bool) { + c.RLock() + defer c.RUnlock() + + if repo, exists := c.repos[repoId]; !exists { + return nil, false + } else { + ret = make([]*v1alpha1.HelmApplication, 0, 10) + for _, app := range c.apps { + if app.GetHelmRepoId() == repo.Name { + ret = append(ret, app) + } + } + } + return ret, true +} + +func (c *cachedRepos) ListAppVersionsByAppId(appId string) (ret []*v1alpha1.HelmApplicationVersion, exists bool) { + c.RLock() + defer c.RUnlock() + + if _, exists := c.apps[appId]; !exists { + return nil, false + } + + ret = make([]*v1alpha1.HelmApplicationVersion, 0, 10) + for _, ver := range c.versions { + if ver.GetHelmApplicationId() == appId { + ret = append(ret, ver) + } + } + return ret, true +} + +func (c *cachedRepos) getAppVersion(versionId string, withData bool) (ret *v1alpha1.HelmApplicationVersion, exists bool, err error) { + c.RLock() + if version, exists := c.versions[versionId]; exists { + //builtin chart data + if withData { + if len(version.Spec.Data) != 0 { + c.RUnlock() + return version, true, nil + } + + if len(version.Spec.URLs) == 0 { + c.RUnlock() + return nil, true, errors.New("invalid chart spec") + } + var repo *v1alpha1.HelmRepo + var exists bool + if repo, exists = c.repos[version.GetHelmRepoId()]; !exists { + c.RUnlock() + klog.Errorf("load repo for app version: %s/%s failed", + version.GetWorkspace(), version.GetTrueName()) + return nil, true, err + } + + c.RUnlock() + url := version.Spec.URLs[0] + if !(strings.HasPrefix(url, "https://") || strings.HasPrefix(url, "http://") || strings.HasPrefix(url, "s3://")) { + url = repo.Spec.Url + "/" + url + } + + buf, err := helmrepoindex.LoadChart(context.TODO(), url, &repo.Spec.Credential) + if err != nil { + klog.Errorf("load chart data for app version: %s/%s failed, error : %s", version.GetTrueName(), + version.GetTrueName(), err) + return nil, true, err + } + version.Spec.Data = buf.Bytes() + return version, true, nil + } else { + c.RUnlock() + return version, true, nil + } + } else { + c.RUnlock() + //version does not exists + return nil, false, nil + } +} +func (c *cachedRepos) GetAppVersion(versionId string) (ret *v1alpha1.HelmApplicationVersion, exists bool, err error) { + return c.getAppVersion(versionId, false) +} + +func (c *cachedRepos) GetAppVersionWithData(versionId string) (ret *v1alpha1.HelmApplicationVersion, exists bool, err error) { + return c.getAppVersion(versionId, true) +} diff --git a/pkg/utils/resourceparse/resource_parse.go b/pkg/utils/resourceparse/resource_parse.go new file mode 100644 index 0000000000000000000000000000000000000000..d99572b956b735a68ee108dc9e5ba20c45a2af25 --- /dev/null +++ b/pkg/utils/resourceparse/resource_parse.go @@ -0,0 +1,63 @@ +// /* +// Copyright 2020 The KubeSphere 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 resourceparse + +import ( + "io" + "k8s.io/cli-runtime/pkg/genericclioptions" + "k8s.io/cli-runtime/pkg/resource" + "k8s.io/klog" + cmdutil "k8s.io/kubectl/pkg/cmd/util" + "time" +) + +func Parse(reader io.Reader, namespace, rlsName string, local bool) ([]*resource.Info, error) { + if klog.V(2) { + klog.Infof("parse resources, namespace: %s, release: %s", namespace, rlsName) + start := time.Now() + defer func() { + klog.Infof("parse resources end, namespace: %s, release: %s, cost: %v", namespace, rlsName, time.Now().Sub(start)) + }() + } + + kubeConfigFlags := genericclioptions.NewConfigFlags(true) + matchVersionKubeConfigFlags := cmdutil.NewMatchVersionFlags(kubeConfigFlags) + f := cmdutil.NewFactory(matchVersionKubeConfigFlags) + builder := f.NewBuilder().Unstructured().NamespaceParam(namespace).ContinueOnError().Stream(reader, rlsName).Flatten() + + if local == true { + builder = builder.Local() + } + r := builder.Do() + infos, err := r.Infos() + if err != nil { + return nil, err + } + + if local == false { + for i := range infos { + infos[i].Namespace = namespace + err := infos[i].Get() + if err != nil { + return nil, err + } + } + } + + return infos, err +} diff --git a/pkg/utils/stringutils/string.go b/pkg/utils/stringutils/string.go index a7375f895c0dbe69e4e7caa4d8e7d679c6ace5af..d15397634eec9bcd3c880ebd7e8d2ec5d28fea63 100644 --- a/pkg/utils/stringutils/string.go +++ b/pkg/utils/stringutils/string.go @@ -95,3 +95,10 @@ func Split(str string, sep string) []string { func StripAnsi(str string) string { return re.ReplaceAllString(str, "") } + +func ShortenString(str string, n int) string { + if len(str) <= n { + return str + } + return str[:n] +} diff --git a/tools/cmd/crd-doc-gen/main.go b/tools/cmd/crd-doc-gen/main.go index 98ed70446c250334e19ea084f86b429384432cf6..a7a52f8764a78b508dd4eb7c7078d5472b135452 100644 --- a/tools/cmd/crd-doc-gen/main.go +++ b/tools/cmd/crd-doc-gen/main.go @@ -21,6 +21,7 @@ import ( "io/ioutil" "k8s.io/apimachinery/pkg/api/meta" urlruntime "k8s.io/apimachinery/pkg/util/runtime" + applicationv1alpha1 "kubesphere.io/kubesphere/pkg/apis/application/v1alpha1" clusterv1alpha1 "kubesphere.io/kubesphere/pkg/apis/cluster/v1alpha1" devopsv1alpha3 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha3" "kubesphere.io/kubesphere/pkg/version" @@ -34,6 +35,7 @@ import ( "k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/serializer" "k8s.io/kube-openapi/pkg/common" + applicationinstall "kubesphere.io/kubesphere/pkg/apis/application/crdinstall" devopsinstall "kubesphere.io/kubesphere/pkg/apis/devops/crdinstall" devopsv1alpha1 "kubesphere.io/kubesphere/pkg/apis/devops/v1alpha1" networkinstall "kubesphere.io/kubesphere/pkg/apis/network/crdinstall" @@ -61,6 +63,7 @@ func main() { tenantinstall.Install(Scheme) networkinstall.Install(Scheme) devopsinstall.Install(Scheme) + applicationinstall.Install(Scheme) urlruntime.Must(clusterv1alpha1.AddToScheme(Scheme)) urlruntime.Must(Scheme.SetVersionPriority(clusterv1alpha1.SchemeGroupVersion)) @@ -116,6 +119,26 @@ func main() { clusterv1alpha1.SchemeGroupVersion.WithResource(clusterv1alpha1.ResourcesPluralCluster), clusterv1alpha1.SchemeGroupVersion.WithResource(clusterv1alpha1.ResourcesSingularCluster), meta.RESTScopeRoot) + mapper.AddSpecific(applicationv1alpha1.SchemeGroupVersion.WithKind(applicationv1alpha1.ResourceKindHelmApplication), + applicationv1alpha1.SchemeGroupVersion.WithResource(applicationv1alpha1.ResourcePluralHelmApplication), + applicationv1alpha1.SchemeGroupVersion.WithResource(applicationv1alpha1.ResourceSingularHelmApplication), meta.RESTScopeRoot) + + mapper.AddSpecific(applicationv1alpha1.SchemeGroupVersion.WithKind(applicationv1alpha1.ResourceKindHelmApplicationVersion), + applicationv1alpha1.SchemeGroupVersion.WithResource(applicationv1alpha1.ResourcePluralHelmApplicationVersion), + applicationv1alpha1.SchemeGroupVersion.WithResource(applicationv1alpha1.ResourceSingularHelmApplicationVersion), meta.RESTScopeRoot) + + mapper.AddSpecific(applicationv1alpha1.SchemeGroupVersion.WithKind(applicationv1alpha1.ResourceKindHelmRelease), + applicationv1alpha1.SchemeGroupVersion.WithResource(applicationv1alpha1.ResourcePluralHelmRelease), + applicationv1alpha1.SchemeGroupVersion.WithResource(applicationv1alpha1.ResourceSingularHelmRelease), meta.RESTScopeRoot) + + mapper.AddSpecific(applicationv1alpha1.SchemeGroupVersion.WithKind(applicationv1alpha1.ResourceKindHelmRepo), + applicationv1alpha1.SchemeGroupVersion.WithResource(applicationv1alpha1.ResourcePluralHelmRepo), + applicationv1alpha1.SchemeGroupVersion.WithResource(applicationv1alpha1.ResourceSingularHelmRepo), meta.RESTScopeRoot) + + mapper.AddSpecific(applicationv1alpha1.SchemeGroupVersion.WithKind(applicationv1alpha1.ResourceKindHelmCategory), + applicationv1alpha1.SchemeGroupVersion.WithResource(applicationv1alpha1.ResourcePluralHelmCategory), + applicationv1alpha1.SchemeGroupVersion.WithResource(applicationv1alpha1.ResourceSingularHelmCategory), meta.RESTScopeRoot) + spec, err := lib.RenderOpenAPISpec(lib.Config{ Scheme: Scheme, Codecs: Codecs, diff --git a/tools/cmd/doc-gen/main.go b/tools/cmd/doc-gen/main.go index 0cfd39d28be2c80b0e8d83d97fe453f0065c8f08..7ca40481e2e3877b8402845d453c08ecbe4f16ca 100644 --- a/tools/cmd/doc-gen/main.go +++ b/tools/cmd/doc-gen/main.go @@ -22,6 +22,8 @@ import ( "flag" "fmt" "io/ioutil" + "kubesphere.io/kubesphere/pkg/client/clientset/versioned/fake" + "kubesphere.io/kubesphere/pkg/version" "log" "github.com/emicklei/go-restful" @@ -46,6 +48,7 @@ import ( networkv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/network/v1alpha2" "kubesphere.io/kubesphere/pkg/kapis/oauth" openpitrixv1 "kubesphere.io/kubesphere/pkg/kapis/openpitrix/v1" + openpitrixv2 "kubesphere.io/kubesphere/pkg/kapis/openpitrix/v2alpha1" operationsv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/operations/v1alpha2" resourcesv1alpha2 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha2" resourcesv1alpha3 "kubesphere.io/kubesphere/pkg/kapis/resources/v1alpha3" @@ -56,9 +59,7 @@ import ( "kubesphere.io/kubesphere/pkg/simple/client/alerting" fakedevops "kubesphere.io/kubesphere/pkg/simple/client/devops/fake" "kubesphere.io/kubesphere/pkg/simple/client/k8s" - "kubesphere.io/kubesphere/pkg/simple/client/openpitrix" fakes3 "kubesphere.io/kubesphere/pkg/simple/client/s3/fake" - "kubesphere.io/kubesphere/pkg/version" ) var output string @@ -122,12 +123,13 @@ func generateSwaggerJson() []byte { urlruntime.Must(devopsv1alpha2.AddToContainer(container, informerFactory.KubeSphereSharedInformerFactory(), &fakedevops.Devops{}, nil, clientsets.KubeSphere(), fakes3.NewFakeS3(), "", nil)) urlruntime.Must(devopsv1alpha3.AddToContainer(container, &fakedevops.Devops{}, clientsets.Kubernetes(), clientsets.KubeSphere(), informerFactory.KubeSphereSharedInformerFactory(), informerFactory.KubernetesSharedInformerFactory())) urlruntime.Must(iamv1alpha2.AddToContainer(container, nil, nil, group.New(informerFactory, clientsets.KubeSphere(), clientsets.Kubernetes()), nil)) - urlruntime.Must(monitoringv1alpha3.AddToContainer(container, clientsets.Kubernetes(), nil, nil, informerFactory, nil)) - urlruntime.Must(openpitrixv1.AddToContainer(container, informerFactory, openpitrix.NewMockClient(nil))) + urlruntime.Must(monitoringv1alpha3.AddToContainer(container, clientsets.Kubernetes(), nil, nil, informerFactory)) + urlruntime.Must(openpitrixv1.AddToContainer(container, informerFactory, fake.NewSimpleClientset(), nil)) + urlruntime.Must(openpitrixv2.AddToContainer(container, informerFactory, fake.NewSimpleClientset(), nil)) urlruntime.Must(operationsv1alpha2.AddToContainer(container, clientsets.Kubernetes())) urlruntime.Must(resourcesv1alpha2.AddToContainer(container, clientsets.Kubernetes(), informerFactory, "")) urlruntime.Must(resourcesv1alpha3.AddToContainer(container, informerFactory, nil)) - urlruntime.Must(tenantv1alpha2.AddToContainer(container, informerFactory, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil)) + urlruntime.Must(tenantv1alpha2.AddToContainer(container, informerFactory, nil, nil, nil, nil, nil, nil, nil, nil, nil)) urlruntime.Must(terminalv1alpha2.AddToContainer(container, clientsets.Kubernetes(), nil)) urlruntime.Must(metricsv1alpha2.AddToContainer(container)) urlruntime.Must(networkv1alpha2.AddToContainer(container, "")) diff --git a/vendor/helm.sh/helm/v3/LICENSE b/vendor/helm.sh/helm/v3/LICENSE new file mode 100644 index 0000000000000000000000000000000000000000..21c57fae21f7e9ab4112e99ddbf14e74528a0abc --- /dev/null +++ b/vendor/helm.sh/helm/v3/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright 2016 The Kubernetes Authors All Rights Reserved + + 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. diff --git a/vendor/helm.sh/helm/v3/internal/fileutil/fileutil.go b/vendor/helm.sh/helm/v3/internal/fileutil/fileutil.go new file mode 100644 index 0000000000000000000000000000000000000000..739093f3b3d4cd082ee5036f81b7b89d14acf68b --- /dev/null +++ b/vendor/helm.sh/helm/v3/internal/fileutil/fileutil.go @@ -0,0 +1,51 @@ +/* +Copyright The Helm 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 fileutil + +import ( + "io" + "io/ioutil" + "os" + "path/filepath" + + "helm.sh/helm/v3/internal/third_party/dep/fs" +) + +// AtomicWriteFile atomically (as atomic as os.Rename allows) writes a file to a +// disk. +func AtomicWriteFile(filename string, reader io.Reader, mode os.FileMode) error { + tempFile, err := ioutil.TempFile(filepath.Split(filename)) + if err != nil { + return err + } + tempName := tempFile.Name() + + if _, err := io.Copy(tempFile, reader); err != nil { + tempFile.Close() // return value is ignored as we are already on error path + return err + } + + if err := tempFile.Close(); err != nil { + return err + } + + if err := os.Chmod(tempName, mode); err != nil { + return err + } + + return fs.RenameWithFallback(tempName, filename) +} diff --git a/vendor/helm.sh/helm/v3/internal/ignore/doc.go b/vendor/helm.sh/helm/v3/internal/ignore/doc.go new file mode 100644 index 0000000000000000000000000000000000000000..e6a6a6c7b5658703988c436dac327ff15cb07886 --- /dev/null +++ b/vendor/helm.sh/helm/v3/internal/ignore/doc.go @@ -0,0 +1,67 @@ +/* +Copyright The Helm 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 ignore provides tools for writing ignore files (a la .gitignore). + +This provides both an ignore parser and a file-aware processor. + +The format of ignore files closely follows, but does not exactly match, the +format for .gitignore files (https://git-scm.com/docs/gitignore). + +The formatting rules are as follows: + + - Parsing is line-by-line + - Empty lines are ignored + - Lines the begin with # (comments) will be ignored + - Leading and trailing spaces are always ignored + - Inline comments are NOT supported ('foo* # Any foo' does not contain a comment) + - There is no support for multi-line patterns + - Shell glob patterns are supported. See Go's "path/filepath".Match + - If a pattern begins with a leading !, the match will be negated. + - If a pattern begins with a leading /, only paths relatively rooted will match. + - If the pattern ends with a trailing /, only directories will match + - If a pattern contains no slashes, file basenames are tested (not paths) + - The pattern sequence "**", while legal in a glob, will cause an error here + (to indicate incompatibility with .gitignore). + +Example: + + # Match any file named foo.txt + foo.txt + + # Match any text file + *.txt + + # Match only directories named mydir + mydir/ + + # Match only text files in the top-level directory + /*.txt + + # Match only the file foo.txt in the top-level directory + /foo.txt + + # Match any file named ab.txt, ac.txt, or ad.txt + a[b-d].txt + +Notable differences from .gitignore: + - The '**' syntax is not supported. + - The globbing library is Go's 'filepath.Match', not fnmatch(3) + - Trailing spaces are always ignored (there is no supported escape sequence) + - The evaluation of escape sequences has not been tested for compatibility + - There is no support for '\!' as a special leading sequence. +*/ +package ignore // import "helm.sh/helm/v3/internal/ignore" diff --git a/vendor/helm.sh/helm/v3/internal/ignore/rules.go b/vendor/helm.sh/helm/v3/internal/ignore/rules.go new file mode 100644 index 0000000000000000000000000000000000000000..a80923baf0ca00c7b625216118bc9c15851f9603 --- /dev/null +++ b/vendor/helm.sh/helm/v3/internal/ignore/rules.go @@ -0,0 +1,228 @@ +/* +Copyright The Helm 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 ignore + +import ( + "bufio" + "bytes" + "io" + "log" + "os" + "path/filepath" + "strings" + + "github.com/pkg/errors" +) + +// HelmIgnore default name of an ignorefile. +const HelmIgnore = ".helmignore" + +// Rules is a collection of path matching rules. +// +// Parse() and ParseFile() will construct and populate new Rules. +// Empty() will create an immutable empty ruleset. +type Rules struct { + patterns []*pattern +} + +// Empty builds an empty ruleset. +func Empty() *Rules { + return &Rules{patterns: []*pattern{}} +} + +// AddDefaults adds default ignore patterns. +// +// Ignore all dotfiles in "templates/" +func (r *Rules) AddDefaults() { + r.parseRule(`templates/.?*`) +} + +// ParseFile parses a helmignore file and returns the *Rules. +func ParseFile(file string) (*Rules, error) { + f, err := os.Open(file) + if err != nil { + return nil, err + } + defer f.Close() + return Parse(f) +} + +// Parse parses a rules file +func Parse(file io.Reader) (*Rules, error) { + r := &Rules{patterns: []*pattern{}} + + s := bufio.NewScanner(file) + currentLine := 0 + utf8bom := []byte{0xEF, 0xBB, 0xBF} + for s.Scan() { + scannedBytes := s.Bytes() + // We trim UTF8 BOM + if currentLine == 0 { + scannedBytes = bytes.TrimPrefix(scannedBytes, utf8bom) + } + line := string(scannedBytes) + currentLine++ + + if err := r.parseRule(line); err != nil { + return r, err + } + } + return r, s.Err() +} + +// Ignore evaluates the file at the given path, and returns true if it should be ignored. +// +// Ignore evaluates path against the rules in order. Evaluation stops when a match +// is found. Matching a negative rule will stop evaluation. +func (r *Rules) Ignore(path string, fi os.FileInfo) bool { + // Don't match on empty dirs. + if path == "" { + return false + } + + // Disallow ignoring the current working directory. + // See issue: + // 1776 (New York City) Hamilton: "Pardon me, are you Aaron Burr, sir?" + if path == "." || path == "./" { + return false + } + for _, p := range r.patterns { + if p.match == nil { + log.Printf("ignore: no matcher supplied for %q", p.raw) + return false + } + + // For negative rules, we need to capture and return non-matches, + // and continue for matches. + if p.negate { + if p.mustDir && !fi.IsDir() { + return true + } + if !p.match(path, fi) { + return true + } + continue + } + + // If the rule is looking for directories, and this is not a directory, + // skip it. + if p.mustDir && !fi.IsDir() { + continue + } + if p.match(path, fi) { + return true + } + } + return false +} + +// parseRule parses a rule string and creates a pattern, which is then stored in the Rules object. +func (r *Rules) parseRule(rule string) error { + rule = strings.TrimSpace(rule) + + // Ignore blank lines + if rule == "" { + return nil + } + // Comment + if strings.HasPrefix(rule, "#") { + return nil + } + + // Fail any rules that contain ** + if strings.Contains(rule, "**") { + return errors.New("double-star (**) syntax is not supported") + } + + // Fail any patterns that can't compile. A non-empty string must be + // given to Match() to avoid optimization that skips rule evaluation. + if _, err := filepath.Match(rule, "abc"); err != nil { + return err + } + + p := &pattern{raw: rule} + + // Negation is handled at a higher level, so strip the leading ! from the + // string. + if strings.HasPrefix(rule, "!") { + p.negate = true + rule = rule[1:] + } + + // Directory verification is handled by a higher level, so the trailing / + // is removed from the rule. That way, a directory named "foo" matches, + // even if the supplied string does not contain a literal slash character. + if strings.HasSuffix(rule, "/") { + p.mustDir = true + rule = strings.TrimSuffix(rule, "/") + } + + if strings.HasPrefix(rule, "/") { + // Require path matches the root path. + p.match = func(n string, fi os.FileInfo) bool { + rule = strings.TrimPrefix(rule, "/") + ok, err := filepath.Match(rule, n) + if err != nil { + log.Printf("Failed to compile %q: %s", rule, err) + return false + } + return ok + } + } else if strings.Contains(rule, "/") { + // require structural match. + p.match = func(n string, fi os.FileInfo) bool { + ok, err := filepath.Match(rule, n) + if err != nil { + log.Printf("Failed to compile %q: %s", rule, err) + return false + } + return ok + } + } else { + p.match = func(n string, fi os.FileInfo) bool { + // When there is no slash in the pattern, we evaluate ONLY the + // filename. + n = filepath.Base(n) + ok, err := filepath.Match(rule, n) + if err != nil { + log.Printf("Failed to compile %q: %s", rule, err) + return false + } + return ok + } + } + + r.patterns = append(r.patterns, p) + return nil +} + +// matcher is a function capable of computing a match. +// +// It returns true if the rule matches. +type matcher func(name string, fi os.FileInfo) bool + +// pattern describes a pattern to be matched in a rule set. +type pattern struct { + // raw is the unparsed string, with nothing stripped. + raw string + // match is the matcher function. + match matcher + // negate indicates that the rule's outcome should be negated. + negate bool + // mustDir indicates that the matched file must be a directory. + mustDir bool +} diff --git a/vendor/helm.sh/helm/v3/internal/sympath/walk.go b/vendor/helm.sh/helm/v3/internal/sympath/walk.go new file mode 100644 index 0000000000000000000000000000000000000000..752526fe939be7e8493af3bd9e2fc4507d9f4152 --- /dev/null +++ b/vendor/helm.sh/helm/v3/internal/sympath/walk.go @@ -0,0 +1,119 @@ +/* +Copyright (c) for portions of walk.go are held by The Go Authors, 2009 and are +provided under the BSD license. + +https://github.com/golang/go/blob/master/LICENSE + +Copyright The Helm 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 sympath + +import ( + "log" + "os" + "path/filepath" + "sort" + + "github.com/pkg/errors" +) + +// Walk walks the file tree rooted at root, calling walkFn for each file or directory +// in the tree, including root. All errors that arise visiting files and directories +// are filtered by walkFn. The files are walked in lexical order, which makes the +// output deterministic but means that for very large directories Walk can be +// inefficient. Walk follows symbolic links. +func Walk(root string, walkFn filepath.WalkFunc) error { + info, err := os.Lstat(root) + if err != nil { + err = walkFn(root, nil, err) + } else { + err = symwalk(root, info, walkFn) + } + if err == filepath.SkipDir { + return nil + } + return err +} + +// readDirNames reads the directory named by dirname and returns +// a sorted list of directory entries. +func readDirNames(dirname string) ([]string, error) { + f, err := os.Open(dirname) + if err != nil { + return nil, err + } + names, err := f.Readdirnames(-1) + f.Close() + if err != nil { + return nil, err + } + sort.Strings(names) + return names, nil +} + +// symwalk recursively descends path, calling walkFn. +func symwalk(path string, info os.FileInfo, walkFn filepath.WalkFunc) error { + // Recursively walk symlinked directories. + if IsSymlink(info) { + resolved, err := filepath.EvalSymlinks(path) + if err != nil { + return errors.Wrapf(err, "error evaluating symlink %s", path) + } + log.Printf("found symbolic link in path: %s resolves to %s", path, resolved) + if info, err = os.Lstat(resolved); err != nil { + return err + } + if err := symwalk(path, info, walkFn); err != nil && err != filepath.SkipDir { + return err + } + return nil + } + + if err := walkFn(path, info, nil); err != nil { + return err + } + + if !info.IsDir() { + return nil + } + + names, err := readDirNames(path) + if err != nil { + return walkFn(path, info, err) + } + + for _, name := range names { + filename := filepath.Join(path, name) + fileInfo, err := os.Lstat(filename) + if err != nil { + if err := walkFn(filename, fileInfo, err); err != nil && err != filepath.SkipDir { + return err + } + } else { + err = symwalk(filename, fileInfo, walkFn) + if err != nil { + if (!fileInfo.IsDir() && !IsSymlink(fileInfo)) || err != filepath.SkipDir { + return err + } + } + } + } + return nil +} + +// IsSymlink is used to determine if the fileinfo is a symbolic link. +func IsSymlink(fi os.FileInfo) bool { + return fi.Mode()&os.ModeSymlink != 0 +} diff --git a/vendor/helm.sh/helm/v3/internal/third_party/dep/fs/fs.go b/vendor/helm.sh/helm/v3/internal/third_party/dep/fs/fs.go new file mode 100644 index 0000000000000000000000000000000000000000..8325921973698afe7721ee0ea2e08501113f7fd6 --- /dev/null +++ b/vendor/helm.sh/helm/v3/internal/third_party/dep/fs/fs.go @@ -0,0 +1,373 @@ +/* +Copyright (c) for portions of fs.go are held by The Go Authors, 2016 and are provided under +the BSD license. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package fs + +import ( + "io" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "syscall" + + "github.com/pkg/errors" +) + +// fs contains a copy of a few functions from dep tool code to avoid a dependency on golang/dep. +// This code is copied from https://github.com/golang/dep/blob/37d6c560cdf407be7b6cd035b23dba89df9275cf/internal/fs/fs.go +// No changes to the code were made other than removing some unused functions + +// RenameWithFallback attempts to rename a file or directory, but falls back to +// copying in the event of a cross-device link error. If the fallback copy +// succeeds, src is still removed, emulating normal rename behavior. +func RenameWithFallback(src, dst string) error { + _, err := os.Stat(src) + if err != nil { + return errors.Wrapf(err, "cannot stat %s", src) + } + + err = os.Rename(src, dst) + if err == nil { + return nil + } + + return renameFallback(err, src, dst) +} + +// renameByCopy attempts to rename a file or directory by copying it to the +// destination and then removing the src thus emulating the rename behavior. +func renameByCopy(src, dst string) error { + var cerr error + if dir, _ := IsDir(src); dir { + cerr = CopyDir(src, dst) + if cerr != nil { + cerr = errors.Wrap(cerr, "copying directory failed") + } + } else { + cerr = copyFile(src, dst) + if cerr != nil { + cerr = errors.Wrap(cerr, "copying file failed") + } + } + + if cerr != nil { + return errors.Wrapf(cerr, "rename fallback failed: cannot rename %s to %s", src, dst) + } + + return errors.Wrapf(os.RemoveAll(src), "cannot delete %s", src) +} + +var ( + errSrcNotDir = errors.New("source is not a directory") + errDstExist = errors.New("destination already exists") +) + +// CopyDir recursively copies a directory tree, attempting to preserve permissions. +// Source directory must exist, destination directory must *not* exist. +func CopyDir(src, dst string) error { + src = filepath.Clean(src) + dst = filepath.Clean(dst) + + // We use os.Lstat() here to ensure we don't fall in a loop where a symlink + // actually links to a one of its parent directories. + fi, err := os.Lstat(src) + if err != nil { + return err + } + if !fi.IsDir() { + return errSrcNotDir + } + + _, err = os.Stat(dst) + if err != nil && !os.IsNotExist(err) { + return err + } + if err == nil { + return errDstExist + } + + if err = os.MkdirAll(dst, fi.Mode()); err != nil { + return errors.Wrapf(err, "cannot mkdir %s", dst) + } + + entries, err := ioutil.ReadDir(src) + if err != nil { + return errors.Wrapf(err, "cannot read directory %s", dst) + } + + for _, entry := range entries { + srcPath := filepath.Join(src, entry.Name()) + dstPath := filepath.Join(dst, entry.Name()) + + if entry.IsDir() { + if err = CopyDir(srcPath, dstPath); err != nil { + return errors.Wrap(err, "copying directory failed") + } + } else { + // This will include symlinks, which is what we want when + // copying things. + if err = copyFile(srcPath, dstPath); err != nil { + return errors.Wrap(err, "copying file failed") + } + } + } + + return nil +} + +// copyFile copies the contents of the file named src to the file named +// by dst. The file will be created if it does not already exist. If the +// destination file exists, all its contents will be replaced by the contents +// of the source file. The file mode will be copied from the source. +func copyFile(src, dst string) (err error) { + if sym, err := IsSymlink(src); err != nil { + return errors.Wrap(err, "symlink check failed") + } else if sym { + if err := cloneSymlink(src, dst); err != nil { + if runtime.GOOS == "windows" { + // If cloning the symlink fails on Windows because the user + // does not have the required privileges, ignore the error and + // fall back to copying the file contents. + // + // ERROR_PRIVILEGE_NOT_HELD is 1314 (0x522): + // https://msdn.microsoft.com/en-us/library/windows/desktop/ms681385(v=vs.85).aspx + if lerr, ok := err.(*os.LinkError); ok && lerr.Err != syscall.Errno(1314) { + return err + } + } else { + return err + } + } else { + return nil + } + } + + in, err := os.Open(src) + if err != nil { + return + } + defer in.Close() + + out, err := os.Create(dst) + if err != nil { + return + } + + if _, err = io.Copy(out, in); err != nil { + out.Close() + return + } + + // Check for write errors on Close + if err = out.Close(); err != nil { + return + } + + si, err := os.Stat(src) + if err != nil { + return + } + + // Temporary fix for Go < 1.9 + // + // See: https://github.com/golang/dep/issues/774 + // and https://github.com/golang/go/issues/20829 + if runtime.GOOS == "windows" { + dst = fixLongPath(dst) + } + err = os.Chmod(dst, si.Mode()) + + return +} + +// cloneSymlink will create a new symlink that points to the resolved path of sl. +// If sl is a relative symlink, dst will also be a relative symlink. +func cloneSymlink(sl, dst string) error { + resolved, err := os.Readlink(sl) + if err != nil { + return err + } + + return os.Symlink(resolved, dst) +} + +// IsDir determines is the path given is a directory or not. +func IsDir(name string) (bool, error) { + fi, err := os.Stat(name) + if err != nil { + return false, err + } + if !fi.IsDir() { + return false, errors.Errorf("%q is not a directory", name) + } + return true, nil +} + +// IsSymlink determines if the given path is a symbolic link. +func IsSymlink(path string) (bool, error) { + l, err := os.Lstat(path) + if err != nil { + return false, err + } + + return l.Mode()&os.ModeSymlink == os.ModeSymlink, nil +} + +// fixLongPath returns the extended-length (\\?\-prefixed) form of +// path when needed, in order to avoid the default 260 character file +// path limit imposed by Windows. If path is not easily converted to +// the extended-length form (for example, if path is a relative path +// or contains .. elements), or is short enough, fixLongPath returns +// path unmodified. +// +// See https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath +func fixLongPath(path string) string { + // Do nothing (and don't allocate) if the path is "short". + // Empirically (at least on the Windows Server 2013 builder), + // the kernel is arbitrarily okay with < 248 bytes. That + // matches what the docs above say: + // "When using an API to create a directory, the specified + // path cannot be so long that you cannot append an 8.3 file + // name (that is, the directory name cannot exceed MAX_PATH + // minus 12)." Since MAX_PATH is 260, 260 - 12 = 248. + // + // The MSDN docs appear to say that a normal path that is 248 bytes long + // will work; empirically the path must be less then 248 bytes long. + if len(path) < 248 { + // Don't fix. (This is how Go 1.7 and earlier worked, + // not automatically generating the \\?\ form) + return path + } + + // The extended form begins with \\?\, as in + // \\?\c:\windows\foo.txt or \\?\UNC\server\share\foo.txt. + // The extended form disables evaluation of . and .. path + // elements and disables the interpretation of / as equivalent + // to \. The conversion here rewrites / to \ and elides + // . elements as well as trailing or duplicate separators. For + // simplicity it avoids the conversion entirely for relative + // paths or paths containing .. elements. For now, + // \\server\share paths are not converted to + // \\?\UNC\server\share paths because the rules for doing so + // are less well-specified. + if len(path) >= 2 && path[:2] == `\\` { + // Don't canonicalize UNC paths. + return path + } + if !isAbs(path) { + // Relative path + return path + } + + const prefix = `\\?` + + pathbuf := make([]byte, len(prefix)+len(path)+len(`\`)) + copy(pathbuf, prefix) + n := len(path) + r, w := 0, len(prefix) + for r < n { + switch { + case os.IsPathSeparator(path[r]): + // empty block + r++ + case path[r] == '.' && (r+1 == n || os.IsPathSeparator(path[r+1])): + // /./ + r++ + case r+1 < n && path[r] == '.' && path[r+1] == '.' && (r+2 == n || os.IsPathSeparator(path[r+2])): + // /../ is currently unhandled + return path + default: + pathbuf[w] = '\\' + w++ + for ; r < n && !os.IsPathSeparator(path[r]); r++ { + pathbuf[w] = path[r] + w++ + } + } + } + // A drive's root directory needs a trailing \ + if w == len(`\\?\c:`) { + pathbuf[w] = '\\' + w++ + } + return string(pathbuf[:w]) +} + +func isAbs(path string) (b bool) { + v := volumeName(path) + if v == "" { + return false + } + path = path[len(v):] + if path == "" { + return false + } + return os.IsPathSeparator(path[0]) +} + +func volumeName(path string) (v string) { + if len(path) < 2 { + return "" + } + // with drive letter + c := path[0] + if path[1] == ':' && + ('0' <= c && c <= '9' || 'a' <= c && c <= 'z' || + 'A' <= c && c <= 'Z') { + return path[:2] + } + // is it UNC + if l := len(path); l >= 5 && os.IsPathSeparator(path[0]) && os.IsPathSeparator(path[1]) && + !os.IsPathSeparator(path[2]) && path[2] != '.' { + // first, leading `\\` and next shouldn't be `\`. its server name. + for n := 3; n < l-1; n++ { + // second, next '\' shouldn't be repeated. + if os.IsPathSeparator(path[n]) { + n++ + // third, following something characters. its share name. + if !os.IsPathSeparator(path[n]) { + if path[n] == '.' { + break + } + for ; n < l; n++ { + if os.IsPathSeparator(path[n]) { + break + } + } + return path[:n] + } + break + } + } + } + return "" +} diff --git a/vendor/helm.sh/helm/v3/internal/third_party/dep/fs/rename.go b/vendor/helm.sh/helm/v3/internal/third_party/dep/fs/rename.go new file mode 100644 index 0000000000000000000000000000000000000000..0bb600949e640e1f6c4c91f1c65e8e5ba80f1348 --- /dev/null +++ b/vendor/helm.sh/helm/v3/internal/third_party/dep/fs/rename.go @@ -0,0 +1,58 @@ +// +build !windows + +/* +Copyright (c) for portions of rename.go are held by The Go Authors, 2016 and are provided under +the BSD license. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package fs + +import ( + "os" + "syscall" + + "github.com/pkg/errors" +) + +// renameFallback attempts to determine the appropriate fallback to failed rename +// operation depending on the resulting error. +func renameFallback(err error, src, dst string) error { + // Rename may fail if src and dst are on different devices; fall back to + // copy if we detect that case. syscall.EXDEV is the common name for the + // cross device link error which has varying output text across different + // operating systems. + terr, ok := err.(*os.LinkError) + if !ok { + return err + } else if terr.Err != syscall.EXDEV { + return errors.Wrapf(terr, "link error: cannot rename %s to %s", src, dst) + } + + return renameByCopy(src, dst) +} diff --git a/vendor/helm.sh/helm/v3/internal/third_party/dep/fs/rename_windows.go b/vendor/helm.sh/helm/v3/internal/third_party/dep/fs/rename_windows.go new file mode 100644 index 0000000000000000000000000000000000000000..14f017d0956aea95c0bbb9f1da50753bc344c7b3 --- /dev/null +++ b/vendor/helm.sh/helm/v3/internal/third_party/dep/fs/rename_windows.go @@ -0,0 +1,69 @@ +// +build windows + +/* +Copyright (c) for portions of rename_windows.go are held by The Go Authors, 2016 and are provided under +the BSD license. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +package fs + +import ( + "os" + "syscall" + + "github.com/pkg/errors" +) + +// renameFallback attempts to determine the appropriate fallback to failed rename +// operation depending on the resulting error. +func renameFallback(err error, src, dst string) error { + // Rename may fail if src and dst are on different devices; fall back to + // copy if we detect that case. syscall.EXDEV is the common name for the + // cross device link error which has varying output text across different + // operating systems. + terr, ok := err.(*os.LinkError) + if !ok { + return err + } + + if terr.Err != syscall.EXDEV { + // In windows it can drop down to an operating system call that + // returns an operating system error with a different number and + // message. Checking for that as a fall back. + noerr, ok := terr.Err.(syscall.Errno) + + // 0x11 (ERROR_NOT_SAME_DEVICE) is the windows error. + // See https://msdn.microsoft.com/en-us/library/cc231199.aspx + if ok && noerr != 0x11 { + return errors.Wrapf(terr, "link error: cannot rename %s to %s", src, dst) + } + } + + return renameByCopy(src, dst) +} diff --git a/vendor/helm.sh/helm/v3/internal/tlsutil/cfg.go b/vendor/helm.sh/helm/v3/internal/tlsutil/cfg.go new file mode 100644 index 0000000000000000000000000000000000000000..8b9d4329fe9be754291546332830505f1d5997de --- /dev/null +++ b/vendor/helm.sh/helm/v3/internal/tlsutil/cfg.go @@ -0,0 +1,58 @@ +/* +Copyright The Helm 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 tlsutil + +import ( + "crypto/tls" + "crypto/x509" + "os" + + "github.com/pkg/errors" +) + +// Options represents configurable options used to create client and server TLS configurations. +type Options struct { + CaCertFile string + // If either the KeyFile or CertFile is empty, ClientConfig() will not load them. + KeyFile string + CertFile string + // Client-only options + InsecureSkipVerify bool +} + +// ClientConfig returns a TLS configuration for use by a Helm client. +func ClientConfig(opts Options) (cfg *tls.Config, err error) { + var cert *tls.Certificate + var pool *x509.CertPool + + if opts.CertFile != "" || opts.KeyFile != "" { + if cert, err = CertFromFilePair(opts.CertFile, opts.KeyFile); err != nil { + if os.IsNotExist(err) { + return nil, errors.Wrapf(err, "could not load x509 key pair (cert: %q, key: %q)", opts.CertFile, opts.KeyFile) + } + return nil, errors.Wrapf(err, "could not read x509 key pair (cert: %q, key: %q)", opts.CertFile, opts.KeyFile) + } + } + if !opts.InsecureSkipVerify && opts.CaCertFile != "" { + if pool, err = CertPoolFromFile(opts.CaCertFile); err != nil { + return nil, err + } + } + + cfg = &tls.Config{InsecureSkipVerify: opts.InsecureSkipVerify, Certificates: []tls.Certificate{*cert}, RootCAs: pool} + return cfg, nil +} diff --git a/vendor/helm.sh/helm/v3/internal/tlsutil/tls.go b/vendor/helm.sh/helm/v3/internal/tlsutil/tls.go new file mode 100644 index 0000000000000000000000000000000000000000..ed7795dbeae6510b16a04690284e3eca6282dcfe --- /dev/null +++ b/vendor/helm.sh/helm/v3/internal/tlsutil/tls.go @@ -0,0 +1,76 @@ +/* +Copyright The Helm 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 tlsutil + +import ( + "crypto/tls" + "crypto/x509" + "io/ioutil" + + "github.com/pkg/errors" +) + +// NewClientTLS returns tls.Config appropriate for client auth. +func NewClientTLS(certFile, keyFile, caFile string) (*tls.Config, error) { + config := tls.Config{} + + if certFile != "" && keyFile != "" { + cert, err := CertFromFilePair(certFile, keyFile) + if err != nil { + return nil, err + } + config.Certificates = []tls.Certificate{*cert} + } + + if caFile != "" { + cp, err := CertPoolFromFile(caFile) + if err != nil { + return nil, err + } + config.RootCAs = cp + } + + return &config, nil +} + +// CertPoolFromFile returns an x509.CertPool containing the certificates +// in the given PEM-encoded file. +// Returns an error if the file could not be read, a certificate could not +// be parsed, or if the file does not contain any certificates +func CertPoolFromFile(filename string) (*x509.CertPool, error) { + b, err := ioutil.ReadFile(filename) + if err != nil { + return nil, errors.Errorf("can't read CA file: %v", filename) + } + cp := x509.NewCertPool() + if !cp.AppendCertsFromPEM(b) { + return nil, errors.Errorf("failed to append certificates from file: %s", filename) + } + return cp, nil +} + +// CertFromFilePair returns an tls.Certificate containing the +// certificates public/private key pair from a pair of given PEM-encoded files. +// Returns an error if the file could not be read, a certificate could not +// be parsed, or if the file does not contain any certificates +func CertFromFilePair(certFile, keyFile string) (*tls.Certificate, error) { + cert, err := tls.LoadX509KeyPair(certFile, keyFile) + if err != nil { + return nil, errors.Wrapf(err, "can't load key pair from cert %s and key %s", certFile, keyFile) + } + return &cert, err +} diff --git a/vendor/helm.sh/helm/v3/internal/urlutil/urlutil.go b/vendor/helm.sh/helm/v3/internal/urlutil/urlutil.go new file mode 100644 index 0000000000000000000000000000000000000000..a8cf7398c07fe7c324febad0eb728be41cb14cc6 --- /dev/null +++ b/vendor/helm.sh/helm/v3/internal/urlutil/urlutil.go @@ -0,0 +1,73 @@ +/* +Copyright The Helm 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 urlutil + +import ( + "net/url" + "path" + "path/filepath" +) + +// URLJoin joins a base URL to one or more path components. +// +// It's like filepath.Join for URLs. If the baseURL is pathish, this will still +// perform a join. +// +// If the URL is unparsable, this returns an error. +func URLJoin(baseURL string, paths ...string) (string, error) { + u, err := url.Parse(baseURL) + if err != nil { + return "", err + } + // We want path instead of filepath because path always uses /. + all := []string{u.Path} + all = append(all, paths...) + u.Path = path.Join(all...) + return u.String(), nil +} + +// Equal normalizes two URLs and then compares for equality. +func Equal(a, b string) bool { + au, err := url.Parse(a) + if err != nil { + a = filepath.Clean(a) + b = filepath.Clean(b) + // If urls are paths, return true only if they are an exact match + return a == b + } + bu, err := url.Parse(b) + if err != nil { + return false + } + + for _, u := range []*url.URL{au, bu} { + if u.Path == "" { + u.Path = "/" + } + u.Path = filepath.Clean(u.Path) + } + return au.String() == bu.String() +} + +// ExtractHostname returns hostname from URL +func ExtractHostname(addr string) (string, error) { + u, err := url.Parse(addr) + if err != nil { + return "", err + } + return u.Hostname(), nil +} diff --git a/vendor/helm.sh/helm/v3/internal/version/version.go b/vendor/helm.sh/helm/v3/internal/version/version.go new file mode 100644 index 0000000000000000000000000000000000000000..712aae640388e45ffdca32db4b098b9fc5620247 --- /dev/null +++ b/vendor/helm.sh/helm/v3/internal/version/version.go @@ -0,0 +1,82 @@ +/* +Copyright The Helm 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 version // import "helm.sh/helm/v3/internal/version" + +import ( + "flag" + "runtime" + "strings" +) + +var ( + // version is the current version of Helm. + // Update this whenever making a new release. + // The version is of the format Major.Minor.Patch[-Prerelease][+BuildMetadata] + // + // Increment major number for new feature additions and behavioral changes. + // Increment minor number for bug fixes and performance enhancements. + // Increment patch number for critical fixes to existing releases. + version = "v3.3" + + // metadata is extra build time data + metadata = "" + // gitCommit is the git sha1 + gitCommit = "" + // gitTreeState is the state of the git tree + gitTreeState = "" +) + +// BuildInfo describes the compile time information. +type BuildInfo struct { + // Version is the current semver. + Version string `json:"version,omitempty"` + // GitCommit is the git sha1. + GitCommit string `json:"git_commit,omitempty"` + // GitTreeState is the state of the git tree. + GitTreeState string `json:"git_tree_state,omitempty"` + // GoVersion is the version of the Go compiler used. + GoVersion string `json:"go_version,omitempty"` +} + +// GetVersion returns the semver string of the version +func GetVersion() string { + if metadata == "" { + return version + } + return version + "+" + metadata +} + +// GetUserAgent returns a user agent for user with an HTTP client +func GetUserAgent() string { + return "Helm/" + strings.TrimPrefix(GetVersion(), "v") +} + +// Get returns build info +func Get() BuildInfo { + v := BuildInfo{ + Version: GetVersion(), + GitCommit: gitCommit, + GitTreeState: gitTreeState, + GoVersion: runtime.Version(), + } + + // HACK(bacongobbler): strip out GoVersion during a test run for consistent test output + if flag.Lookup("test.v") != nil { + v.GoVersion = "" + } + return v +} diff --git a/vendor/helm.sh/helm/v3/pkg/chart/chart.go b/vendor/helm.sh/helm/v3/pkg/chart/chart.go new file mode 100644 index 0000000000000000000000000000000000000000..bd75375a42f5093c2a2db4e52205ec13d7a32522 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/chart/chart.go @@ -0,0 +1,169 @@ +/* +Copyright The Helm 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 chart + +import ( + "path/filepath" + "strings" +) + +// APIVersionV1 is the API version number for version 1. +const APIVersionV1 = "v1" + +// APIVersionV2 is the API version number for version 2. +const APIVersionV2 = "v2" + +// Chart is a helm package that contains metadata, a default config, zero or more +// optionally parameterizable templates, and zero or more charts (dependencies). +type Chart struct { + // Raw contains the raw contents of the files originally contained in the chart archive. + // + // This should not be used except in special cases like `helm show values`, + // where we want to display the raw values, comments and all. + Raw []*File `json:"-"` + // Metadata is the contents of the Chartfile. + Metadata *Metadata `json:"metadata"` + // Lock is the contents of Chart.lock. + Lock *Lock `json:"lock"` + // Templates for this chart. + Templates []*File `json:"templates"` + // Values are default config for this chart. + Values map[string]interface{} `json:"values"` + // Schema is an optional JSON schema for imposing structure on Values + Schema []byte `json:"schema"` + // Files are miscellaneous files in a chart archive, + // e.g. README, LICENSE, etc. + Files []*File `json:"files"` + + parent *Chart + dependencies []*Chart +} + +type CRD struct { + // Name is the File.Name for the crd file + Name string + // Filename is the File obj Name including (sub-)chart.ChartFullPath + Filename string + // File is the File obj for the crd + File *File +} + +// SetDependencies replaces the chart dependencies. +func (ch *Chart) SetDependencies(charts ...*Chart) { + ch.dependencies = nil + ch.AddDependency(charts...) +} + +// Name returns the name of the chart. +func (ch *Chart) Name() string { + if ch.Metadata == nil { + return "" + } + return ch.Metadata.Name +} + +// AddDependency determines if the chart is a subchart. +func (ch *Chart) AddDependency(charts ...*Chart) { + for i, x := range charts { + charts[i].parent = ch + ch.dependencies = append(ch.dependencies, x) + } +} + +// Root finds the root chart. +func (ch *Chart) Root() *Chart { + if ch.IsRoot() { + return ch + } + return ch.Parent().Root() +} + +// Dependencies are the charts that this chart depends on. +func (ch *Chart) Dependencies() []*Chart { return ch.dependencies } + +// IsRoot determines if the chart is the root chart. +func (ch *Chart) IsRoot() bool { return ch.parent == nil } + +// Parent returns a subchart's parent chart. +func (ch *Chart) Parent() *Chart { return ch.parent } + +// ChartPath returns the full path to this chart in dot notation. +func (ch *Chart) ChartPath() string { + if !ch.IsRoot() { + return ch.Parent().ChartPath() + "." + ch.Name() + } + return ch.Name() +} + +// ChartFullPath returns the full path to this chart. +func (ch *Chart) ChartFullPath() string { + if !ch.IsRoot() { + return ch.Parent().ChartFullPath() + "/charts/" + ch.Name() + } + return ch.Name() +} + +// Validate validates the metadata. +func (ch *Chart) Validate() error { + return ch.Metadata.Validate() +} + +// AppVersion returns the appversion of the chart. +func (ch *Chart) AppVersion() string { + if ch.Metadata == nil { + return "" + } + return ch.Metadata.AppVersion +} + +// CRDs returns a list of File objects in the 'crds/' directory of a Helm chart. +// Deprecated: use CRDObjects() +func (ch *Chart) CRDs() []*File { + files := []*File{} + // Find all resources in the crds/ directory + for _, f := range ch.Files { + if strings.HasPrefix(f.Name, "crds/") && hasManifestExtension(f.Name) { + files = append(files, f) + } + } + // Get CRDs from dependencies, too. + for _, dep := range ch.Dependencies() { + files = append(files, dep.CRDs()...) + } + return files +} + +// CRDObjects returns a list of CRD objects in the 'crds/' directory of a Helm chart & subcharts +func (ch *Chart) CRDObjects() []CRD { + crds := []CRD{} + // Find all resources in the crds/ directory + for _, f := range ch.Files { + if strings.HasPrefix(f.Name, "crds/") && hasManifestExtension(f.Name) { + mycrd := CRD{Name: f.Name, Filename: filepath.Join(ch.ChartFullPath(), f.Name), File: f} + crds = append(crds, mycrd) + } + } + // Get CRDs from dependencies, too. + for _, dep := range ch.Dependencies() { + crds = append(crds, dep.CRDObjects()...) + } + return crds +} + +func hasManifestExtension(fname string) bool { + ext := filepath.Ext(fname) + return strings.EqualFold(ext, ".yaml") || strings.EqualFold(ext, ".yml") || strings.EqualFold(ext, ".json") +} diff --git a/vendor/helm.sh/helm/v3/pkg/chart/dependency.go b/vendor/helm.sh/helm/v3/pkg/chart/dependency.go new file mode 100644 index 0000000000000000000000000000000000000000..9ec4544c22e1b68ca3258f9c35f24fea0a471150 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/chart/dependency.go @@ -0,0 +1,62 @@ +/* +Copyright The Helm 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 chart + +import "time" + +// Dependency describes a chart upon which another chart depends. +// +// Dependencies can be used to express developer intent, or to capture the state +// of a chart. +type Dependency struct { + // Name is the name of the dependency. + // + // This must mach the name in the dependency's Chart.yaml. + Name string `json:"name"` + // Version is the version (range) of this chart. + // + // A lock file will always produce a single version, while a dependency + // may contain a semantic version range. + Version string `json:"version,omitempty"` + // The URL to the repository. + // + // Appending `index.yaml` to this string should result in a URL that can be + // used to fetch the repository index. + Repository string `json:"repository"` + // A yaml path that resolves to a boolean, used for enabling/disabling charts (e.g. subchart1.enabled ) + Condition string `json:"condition,omitempty"` + // Tags can be used to group charts for enabling/disabling together + Tags []string `json:"tags,omitempty"` + // Enabled bool determines if chart should be loaded + Enabled bool `json:"enabled,omitempty"` + // ImportValues holds the mapping of source values to parent key to be imported. Each item can be a + // string or pair of child/parent sublist items. + ImportValues []interface{} `json:"import-values,omitempty"` + // Alias usable alias to be used for the chart + Alias string `json:"alias,omitempty"` +} + +// Lock is a lock file for dependencies. +// +// It represents the state that the dependencies should be in. +type Lock struct { + // Generated is the date the lock file was last generated. + Generated time.Time `json:"generated"` + // Digest is a hash of the dependencies in Chart.yaml. + Digest string `json:"digest"` + // Dependencies is the list of dependencies that this lock file has locked. + Dependencies []*Dependency `json:"dependencies"` +} diff --git a/vendor/helm.sh/helm/v3/pkg/chart/errors.go b/vendor/helm.sh/helm/v3/pkg/chart/errors.go new file mode 100644 index 0000000000000000000000000000000000000000..4cb4189e6e9ae6ba637a789142eca06f7338d1de --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/chart/errors.go @@ -0,0 +1,23 @@ +/* +Copyright The Helm 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 chart + +// ValidationError represents a data validation error. +type ValidationError string + +func (v ValidationError) Error() string { + return "validation: " + string(v) +} diff --git a/vendor/helm.sh/helm/v3/pkg/chart/file.go b/vendor/helm.sh/helm/v3/pkg/chart/file.go new file mode 100644 index 0000000000000000000000000000000000000000..9dd7c08d5255d4476d7db7099e72d428a5476e6d --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/chart/file.go @@ -0,0 +1,27 @@ +/* +Copyright The Helm 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 chart + +// File represents a file as a name/value pair. +// +// By convention, name is a relative path within the scope of the chart's +// base directory. +type File struct { + // Name is the path-like name of the template. + Name string `json:"name"` + // Data is the template as byte data. + Data []byte `json:"data"` +} diff --git a/vendor/helm.sh/helm/v3/pkg/chart/loader/archive.go b/vendor/helm.sh/helm/v3/pkg/chart/loader/archive.go new file mode 100644 index 0000000000000000000000000000000000000000..8b38cb89f99f17cf9db23b83e0794fd0a64701da --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/chart/loader/archive.go @@ -0,0 +1,196 @@ +/* +Copyright The Helm 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 loader + +import ( + "archive/tar" + "bytes" + "compress/gzip" + "fmt" + "io" + "net/http" + "os" + "path" + "regexp" + "strings" + + "github.com/pkg/errors" + + "helm.sh/helm/v3/pkg/chart" +) + +var drivePathPattern = regexp.MustCompile(`^[a-zA-Z]:/`) + +// FileLoader loads a chart from a file +type FileLoader string + +// Load loads a chart +func (l FileLoader) Load() (*chart.Chart, error) { + return LoadFile(string(l)) +} + +// LoadFile loads from an archive file. +func LoadFile(name string) (*chart.Chart, error) { + if fi, err := os.Stat(name); err != nil { + return nil, err + } else if fi.IsDir() { + return nil, errors.New("cannot load a directory") + } + + raw, err := os.Open(name) + if err != nil { + return nil, err + } + defer raw.Close() + + err = ensureArchive(name, raw) + if err != nil { + return nil, err + } + + c, err := LoadArchive(raw) + if err != nil { + if err == gzip.ErrHeader { + return nil, fmt.Errorf("file '%s' does not appear to be a valid chart file (details: %s)", name, err) + } + } + return c, err +} + +// ensureArchive's job is to return an informative error if the file does not appear to be a gzipped archive. +// +// Sometimes users will provide a values.yaml for an argument where a chart is expected. One common occurrence +// of this is invoking `helm template values.yaml mychart` which would otherwise produce a confusing error +// if we didn't check for this. +func ensureArchive(name string, raw *os.File) error { + defer raw.Seek(0, 0) // reset read offset to allow archive loading to proceed. + + // Check the file format to give us a chance to provide the user with more actionable feedback. + buffer := make([]byte, 512) + _, err := raw.Read(buffer) + if err != nil && err != io.EOF { + return fmt.Errorf("file '%s' cannot be read: %s", name, err) + } + if contentType := http.DetectContentType(buffer); contentType != "application/x-gzip" { + // TODO: Is there a way to reliably test if a file content is YAML? ghodss/yaml accepts a wide + // variety of content (Makefile, .zshrc) as valid YAML without errors. + + // Wrong content type. Let's check if it's yaml and give an extra hint? + if strings.HasSuffix(name, ".yml") || strings.HasSuffix(name, ".yaml") { + return fmt.Errorf("file '%s' seems to be a YAML file, but expected a gzipped archive", name) + } + return fmt.Errorf("file '%s' does not appear to be a gzipped archive; got '%s'", name, contentType) + } + return nil +} + +// LoadArchiveFiles reads in files out of an archive into memory. This function +// performs important path security checks and should always be used before +// expanding a tarball +func LoadArchiveFiles(in io.Reader) ([]*BufferedFile, error) { + unzipped, err := gzip.NewReader(in) + if err != nil { + return nil, err + } + defer unzipped.Close() + + files := []*BufferedFile{} + tr := tar.NewReader(unzipped) + for { + b := bytes.NewBuffer(nil) + hd, err := tr.Next() + if err == io.EOF { + break + } + if err != nil { + return nil, err + } + + if hd.FileInfo().IsDir() { + // Use this instead of hd.Typeflag because we don't have to do any + // inference chasing. + continue + } + + switch hd.Typeflag { + // We don't want to process these extension header files. + case tar.TypeXGlobalHeader, tar.TypeXHeader: + continue + } + + // Archive could contain \ if generated on Windows + delimiter := "/" + if strings.ContainsRune(hd.Name, '\\') { + delimiter = "\\" + } + + parts := strings.Split(hd.Name, delimiter) + n := strings.Join(parts[1:], delimiter) + + // Normalize the path to the / delimiter + n = strings.ReplaceAll(n, delimiter, "/") + + if path.IsAbs(n) { + return nil, errors.New("chart illegally contains absolute paths") + } + + n = path.Clean(n) + if n == "." { + // In this case, the original path was relative when it should have been absolute. + return nil, errors.Errorf("chart illegally contains content outside the base directory: %q", hd.Name) + } + if strings.HasPrefix(n, "..") { + return nil, errors.New("chart illegally references parent directory") + } + + // In some particularly arcane acts of path creativity, it is possible to intermix + // UNIX and Windows style paths in such a way that you produce a result of the form + // c:/foo even after all the built-in absolute path checks. So we explicitly check + // for this condition. + if drivePathPattern.MatchString(n) { + return nil, errors.New("chart contains illegally named files") + } + + if parts[0] == "Chart.yaml" { + return nil, errors.New("chart yaml not in base directory") + } + + if _, err := io.Copy(b, tr); err != nil { + return nil, err + } + + data := bytes.TrimPrefix(b.Bytes(), utf8bom) + + files = append(files, &BufferedFile{Name: n, Data: data}) + b.Reset() + } + + if len(files) == 0 { + return nil, errors.New("no files in chart archive") + } + return files, nil +} + +// LoadArchive loads from a reader containing a compressed tar archive. +func LoadArchive(in io.Reader) (*chart.Chart, error) { + files, err := LoadArchiveFiles(in) + if err != nil { + return nil, err + } + + return LoadFiles(files) +} diff --git a/vendor/helm.sh/helm/v3/pkg/chart/loader/directory.go b/vendor/helm.sh/helm/v3/pkg/chart/loader/directory.go new file mode 100644 index 0000000000000000000000000000000000000000..bbe543870d1bc9630e4a61c379401bb6b89814d6 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/chart/loader/directory.go @@ -0,0 +1,120 @@ +/* +Copyright The Helm 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 loader + +import ( + "bytes" + "fmt" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/pkg/errors" + + "helm.sh/helm/v3/internal/ignore" + "helm.sh/helm/v3/internal/sympath" + "helm.sh/helm/v3/pkg/chart" +) + +var utf8bom = []byte{0xEF, 0xBB, 0xBF} + +// DirLoader loads a chart from a directory +type DirLoader string + +// Load loads the chart +func (l DirLoader) Load() (*chart.Chart, error) { + return LoadDir(string(l)) +} + +// LoadDir loads from a directory. +// +// This loads charts only from directories. +func LoadDir(dir string) (*chart.Chart, error) { + topdir, err := filepath.Abs(dir) + if err != nil { + return nil, err + } + + // Just used for errors. + c := &chart.Chart{} + + rules := ignore.Empty() + ifile := filepath.Join(topdir, ignore.HelmIgnore) + if _, err := os.Stat(ifile); err == nil { + r, err := ignore.ParseFile(ifile) + if err != nil { + return c, err + } + rules = r + } + rules.AddDefaults() + + files := []*BufferedFile{} + topdir += string(filepath.Separator) + + walk := func(name string, fi os.FileInfo, err error) error { + n := strings.TrimPrefix(name, topdir) + if n == "" { + // No need to process top level. Avoid bug with helmignore .* matching + // empty names. See issue 1779. + return nil + } + + // Normalize to / since it will also work on Windows + n = filepath.ToSlash(n) + + if err != nil { + return err + } + if fi.IsDir() { + // Directory-based ignore rules should involve skipping the entire + // contents of that directory. + if rules.Ignore(n, fi) { + return filepath.SkipDir + } + return nil + } + + // If a .helmignore file matches, skip this file. + if rules.Ignore(n, fi) { + return nil + } + + // Irregular files include devices, sockets, and other uses of files that + // are not regular files. In Go they have a file mode type bit set. + // See https://golang.org/pkg/os/#FileMode for examples. + if !fi.Mode().IsRegular() { + return fmt.Errorf("cannot load irregular file %s as it has file mode type bits set", name) + } + + data, err := ioutil.ReadFile(name) + if err != nil { + return errors.Wrapf(err, "error reading %s", n) + } + + data = bytes.TrimPrefix(data, utf8bom) + + files = append(files, &BufferedFile{Name: n, Data: data}) + return nil + } + if err = sympath.Walk(topdir, walk); err != nil { + return c, err + } + + return LoadFiles(files) +} diff --git a/vendor/helm.sh/helm/v3/pkg/chart/loader/load.go b/vendor/helm.sh/helm/v3/pkg/chart/loader/load.go new file mode 100644 index 0000000000000000000000000000000000000000..dd4fd2dff69881e4df7e277b64ed23ee2e9fecc1 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/chart/loader/load.go @@ -0,0 +1,185 @@ +/* +Copyright The Helm 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 loader + +import ( + "bytes" + "log" + "os" + "path/filepath" + "strings" + + "github.com/pkg/errors" + "sigs.k8s.io/yaml" + + "helm.sh/helm/v3/pkg/chart" +) + +// ChartLoader loads a chart. +type ChartLoader interface { + Load() (*chart.Chart, error) +} + +// Loader returns a new ChartLoader appropriate for the given chart name +func Loader(name string) (ChartLoader, error) { + fi, err := os.Stat(name) + if err != nil { + return nil, err + } + if fi.IsDir() { + return DirLoader(name), nil + } + return FileLoader(name), nil + +} + +// Load takes a string name, tries to resolve it to a file or directory, and then loads it. +// +// This is the preferred way to load a chart. It will discover the chart encoding +// and hand off to the appropriate chart reader. +// +// If a .helmignore file is present, the directory loader will skip loading any files +// matching it. But .helmignore is not evaluated when reading out of an archive. +func Load(name string) (*chart.Chart, error) { + l, err := Loader(name) + if err != nil { + return nil, err + } + return l.Load() +} + +// BufferedFile represents an archive file buffered for later processing. +type BufferedFile struct { + Name string + Data []byte +} + +// LoadFiles loads from in-memory files. +func LoadFiles(files []*BufferedFile) (*chart.Chart, error) { + c := new(chart.Chart) + subcharts := make(map[string][]*BufferedFile) + + for _, f := range files { + c.Raw = append(c.Raw, &chart.File{Name: f.Name, Data: f.Data}) + switch { + case f.Name == "Chart.yaml": + if c.Metadata == nil { + c.Metadata = new(chart.Metadata) + } + if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil { + return c, errors.Wrap(err, "cannot load Chart.yaml") + } + // NOTE(bacongobbler): while the chart specification says that APIVersion must be set, + // Helm 2 accepted charts that did not provide an APIVersion in their chart metadata. + // Because of that, if APIVersion is unset, we should assume we're loading a v1 chart. + if c.Metadata.APIVersion == "" { + c.Metadata.APIVersion = chart.APIVersionV1 + } + case f.Name == "Chart.lock": + c.Lock = new(chart.Lock) + if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil { + return c, errors.Wrap(err, "cannot load Chart.lock") + } + case f.Name == "values.yaml": + c.Values = make(map[string]interface{}) + if err := yaml.Unmarshal(f.Data, &c.Values); err != nil { + return c, errors.Wrap(err, "cannot load values.yaml") + } + case f.Name == "values.schema.json": + c.Schema = f.Data + + // Deprecated: requirements.yaml is deprecated use Chart.yaml. + // We will handle it for you because we are nice people + case f.Name == "requirements.yaml": + if c.Metadata == nil { + c.Metadata = new(chart.Metadata) + } + if c.Metadata.APIVersion != chart.APIVersionV1 { + log.Printf("Warning: Dependencies are handled in Chart.yaml since apiVersion \"v2\". We recommend migrating dependencies to Chart.yaml.") + } + if err := yaml.Unmarshal(f.Data, c.Metadata); err != nil { + return c, errors.Wrap(err, "cannot load requirements.yaml") + } + if c.Metadata.APIVersion == chart.APIVersionV1 { + c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data}) + } + // Deprecated: requirements.lock is deprecated use Chart.lock. + case f.Name == "requirements.lock": + c.Lock = new(chart.Lock) + if err := yaml.Unmarshal(f.Data, &c.Lock); err != nil { + return c, errors.Wrap(err, "cannot load requirements.lock") + } + if c.Metadata.APIVersion == chart.APIVersionV1 { + c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data}) + } + + case strings.HasPrefix(f.Name, "templates/"): + c.Templates = append(c.Templates, &chart.File{Name: f.Name, Data: f.Data}) + case strings.HasPrefix(f.Name, "charts/"): + if filepath.Ext(f.Name) == ".prov" { + c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data}) + continue + } + + fname := strings.TrimPrefix(f.Name, "charts/") + cname := strings.SplitN(fname, "/", 2)[0] + subcharts[cname] = append(subcharts[cname], &BufferedFile{Name: fname, Data: f.Data}) + default: + c.Files = append(c.Files, &chart.File{Name: f.Name, Data: f.Data}) + } + } + + if err := c.Validate(); err != nil { + return c, err + } + + for n, files := range subcharts { + var sc *chart.Chart + var err error + switch { + case strings.IndexAny(n, "_.") == 0: + continue + case filepath.Ext(n) == ".tgz": + file := files[0] + if file.Name != n { + return c, errors.Errorf("error unpacking tar in %s: expected %s, got %s", c.Name(), n, file.Name) + } + // Untar the chart and add to c.Dependencies + sc, err = LoadArchive(bytes.NewBuffer(file.Data)) + default: + // We have to trim the prefix off of every file, and ignore any file + // that is in charts/, but isn't actually a chart. + buff := make([]*BufferedFile, 0, len(files)) + for _, f := range files { + parts := strings.SplitN(f.Name, "/", 2) + if len(parts) < 2 { + continue + } + f.Name = parts[1] + buff = append(buff, f) + } + sc, err = LoadFiles(buff) + } + + if err != nil { + return c, errors.Wrapf(err, "error unpacking %s in %s", n, c.Name()) + } + c.AddDependency(sc) + } + + return c, nil +} diff --git a/vendor/helm.sh/helm/v3/pkg/chart/metadata.go b/vendor/helm.sh/helm/v3/pkg/chart/metadata.go new file mode 100644 index 0000000000000000000000000000000000000000..96a3965b9cf6560d4a2587ade5febe31c1195f9a --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/chart/metadata.go @@ -0,0 +1,94 @@ +/* +Copyright The Helm 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 chart + +// Maintainer describes a Chart maintainer. +type Maintainer struct { + // Name is a user name or organization name + Name string `json:"name,omitempty"` + // Email is an optional email address to contact the named maintainer + Email string `json:"email,omitempty"` + // URL is an optional URL to an address for the named maintainer + URL string `json:"url,omitempty"` +} + +// Metadata for a Chart file. This models the structure of a Chart.yaml file. +type Metadata struct { + // The name of the chart + Name string `json:"name,omitempty"` + // The URL to a relevant project page, git repo, or contact person + Home string `json:"home,omitempty"` + // Source is the URL to the source code of this chart + Sources []string `json:"sources,omitempty"` + // A SemVer 2 conformant version string of the chart + Version string `json:"version,omitempty"` + // A one-sentence description of the chart + Description string `json:"description,omitempty"` + // A list of string keywords + Keywords []string `json:"keywords,omitempty"` + // A list of name and URL/email address combinations for the maintainer(s) + Maintainers []*Maintainer `json:"maintainers,omitempty"` + // The URL to an icon file. + Icon string `json:"icon,omitempty"` + // The API Version of this chart. + APIVersion string `json:"apiVersion,omitempty"` + // The condition to check to enable chart + Condition string `json:"condition,omitempty"` + // The tags to check to enable chart + Tags string `json:"tags,omitempty"` + // The version of the application enclosed inside of this chart. + AppVersion string `json:"appVersion,omitempty"` + // Whether or not this chart is deprecated + Deprecated bool `json:"deprecated,omitempty"` + // Annotations are additional mappings uninterpreted by Helm, + // made available for inspection by other applications. + Annotations map[string]string `json:"annotations,omitempty"` + // KubeVersion is a SemVer constraint specifying the version of Kubernetes required. + KubeVersion string `json:"kubeVersion,omitempty"` + // Dependencies are a list of dependencies for a chart. + Dependencies []*Dependency `json:"dependencies,omitempty"` + // Specifies the chart type: application or library + Type string `json:"type,omitempty"` +} + +// Validate checks the metadata for known issues, returning an error if metadata is not correct +func (md *Metadata) Validate() error { + if md == nil { + return ValidationError("chart.metadata is required") + } + if md.APIVersion == "" { + return ValidationError("chart.metadata.apiVersion is required") + } + if md.Name == "" { + return ValidationError("chart.metadata.name is required") + } + if md.Version == "" { + return ValidationError("chart.metadata.version is required") + } + if !isValidChartType(md.Type) { + return ValidationError("chart.metadata.type must be application or library") + } + // TODO validate valid semver here? + return nil +} + +func isValidChartType(in string) bool { + switch in { + case "", "application", "library": + return true + } + return false +} diff --git a/vendor/helm.sh/helm/v3/pkg/cli/environment.go b/vendor/helm.sh/helm/v3/pkg/cli/environment.go new file mode 100644 index 0000000000000000000000000000000000000000..d62f57a55907bcc3d17d34c5a096032142d4fb1f --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/cli/environment.go @@ -0,0 +1,140 @@ +/* +Copyright The Helm 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 cli describes the operating environment for the Helm CLI. + +Helm's environment encapsulates all of the service dependencies Helm has. +These dependencies are expressed as interfaces so that alternate implementations +(mocks, etc.) can be easily generated. +*/ +package cli + +import ( + "fmt" + "os" + "strconv" + + "github.com/spf13/pflag" + "k8s.io/cli-runtime/pkg/genericclioptions" + + "helm.sh/helm/v3/pkg/helmpath" +) + +// EnvSettings describes all of the environment settings. +type EnvSettings struct { + namespace string + config *genericclioptions.ConfigFlags + + // KubeConfig is the path to the kubeconfig file + KubeConfig string + // KubeContext is the name of the kubeconfig context. + KubeContext string + // Bearer KubeToken used for authentication + KubeToken string + // Kubernetes API Server Endpoint for authentication + KubeAPIServer string + // Debug indicates whether or not Helm is running in Debug mode. + Debug bool + // RegistryConfig is the path to the registry config file. + RegistryConfig string + // RepositoryConfig is the path to the repositories file. + RepositoryConfig string + // RepositoryCache is the path to the repository cache directory. + RepositoryCache string + // PluginsDirectory is the path to the plugins directory. + PluginsDirectory string +} + +func New() *EnvSettings { + env := &EnvSettings{ + namespace: os.Getenv("HELM_NAMESPACE"), + KubeContext: os.Getenv("HELM_KUBECONTEXT"), + KubeToken: os.Getenv("HELM_KUBETOKEN"), + KubeAPIServer: os.Getenv("HELM_KUBEAPISERVER"), + PluginsDirectory: envOr("HELM_PLUGINS", helmpath.DataPath("plugins")), + RegistryConfig: envOr("HELM_REGISTRY_CONFIG", helmpath.ConfigPath("registry.json")), + RepositoryConfig: envOr("HELM_REPOSITORY_CONFIG", helmpath.ConfigPath("repositories.yaml")), + RepositoryCache: envOr("HELM_REPOSITORY_CACHE", helmpath.CachePath("repository")), + } + env.Debug, _ = strconv.ParseBool(os.Getenv("HELM_DEBUG")) + + // bind to kubernetes config flags + env.config = &genericclioptions.ConfigFlags{ + Namespace: &env.namespace, + Context: &env.KubeContext, + BearerToken: &env.KubeToken, + APIServer: &env.KubeAPIServer, + KubeConfig: &env.KubeConfig, + } + return env +} + +// AddFlags binds flags to the given flagset. +func (s *EnvSettings) AddFlags(fs *pflag.FlagSet) { + fs.StringVarP(&s.namespace, "namespace", "n", s.namespace, "namespace scope for this request") + fs.StringVar(&s.KubeConfig, "kubeconfig", "", "path to the kubeconfig file") + fs.StringVar(&s.KubeContext, "kube-context", s.KubeContext, "name of the kubeconfig context to use") + fs.StringVar(&s.KubeToken, "kube-token", s.KubeToken, "bearer token used for authentication") + fs.StringVar(&s.KubeAPIServer, "kube-apiserver", s.KubeAPIServer, "the address and the port for the Kubernetes API server") + fs.BoolVar(&s.Debug, "debug", s.Debug, "enable verbose output") + fs.StringVar(&s.RegistryConfig, "registry-config", s.RegistryConfig, "path to the registry config file") + fs.StringVar(&s.RepositoryConfig, "repository-config", s.RepositoryConfig, "path to the file containing repository names and URLs") + fs.StringVar(&s.RepositoryCache, "repository-cache", s.RepositoryCache, "path to the file containing cached repository indexes") +} + +func envOr(name, def string) string { + if v, ok := os.LookupEnv(name); ok { + return v + } + return def +} + +func (s *EnvSettings) EnvVars() map[string]string { + envvars := map[string]string{ + "HELM_BIN": os.Args[0], + "HELM_CACHE_HOME": helmpath.CachePath(""), + "HELM_CONFIG_HOME": helmpath.ConfigPath(""), + "HELM_DATA_HOME": helmpath.DataPath(""), + "HELM_DEBUG": fmt.Sprint(s.Debug), + "HELM_PLUGINS": s.PluginsDirectory, + "HELM_REGISTRY_CONFIG": s.RegistryConfig, + "HELM_REPOSITORY_CACHE": s.RepositoryCache, + "HELM_REPOSITORY_CONFIG": s.RepositoryConfig, + "HELM_NAMESPACE": s.Namespace(), + + // broken, these are populated from helm flags and not kubeconfig. + "HELM_KUBECONTEXT": s.KubeContext, + "HELM_KUBETOKEN": s.KubeToken, + "HELM_KUBEAPISERVER": s.KubeAPIServer, + } + if s.KubeConfig != "" { + envvars["KUBECONFIG"] = s.KubeConfig + } + return envvars +} + +// Namespace gets the namespace from the configuration +func (s *EnvSettings) Namespace() string { + if ns, _, err := s.config.ToRawKubeConfigLoader().Namespace(); err == nil { + return ns + } + return "default" +} + +// RESTClientGetter gets the kubeconfig from EnvSettings +func (s *EnvSettings) RESTClientGetter() genericclioptions.RESTClientGetter { + return s.config +} diff --git a/vendor/helm.sh/helm/v3/pkg/getter/doc.go b/vendor/helm.sh/helm/v3/pkg/getter/doc.go new file mode 100644 index 0000000000000000000000000000000000000000..c53ef1ae02be77b1983f677339d7719e8d519cf0 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/getter/doc.go @@ -0,0 +1,21 @@ +/* +Copyright The Helm 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 getter provides a generalize tool for fetching data by scheme. + +This provides a method by which the plugin system can load arbitrary protocol +handlers based upon a URL scheme. +*/ +package getter diff --git a/vendor/helm.sh/helm/v3/pkg/getter/getter.go b/vendor/helm.sh/helm/v3/pkg/getter/getter.go new file mode 100644 index 0000000000000000000000000000000000000000..8ee08cb7fde1550644f6ce146d137e863d6b6666 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/getter/getter.go @@ -0,0 +1,150 @@ +/* +Copyright The Helm 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 getter + +import ( + "bytes" + "time" + + "github.com/pkg/errors" + + "helm.sh/helm/v3/pkg/cli" +) + +// options are generic parameters to be provided to the getter during instantiation. +// +// Getters may or may not ignore these parameters as they are passed in. +type options struct { + url string + certFile string + keyFile string + caFile string + insecureSkipVerifyTLS bool + username string + password string + userAgent string + timeout time.Duration +} + +// Option allows specifying various settings configurable by the user for overriding the defaults +// used when performing Get operations with the Getter. +type Option func(*options) + +// WithURL informs the getter the server name that will be used when fetching objects. Used in conjunction with +// WithTLSClientConfig to set the TLSClientConfig's server name. +func WithURL(url string) Option { + return func(opts *options) { + opts.url = url + } +} + +// WithBasicAuth sets the request's Authorization header to use the provided credentials +func WithBasicAuth(username, password string) Option { + return func(opts *options) { + opts.username = username + opts.password = password + } +} + +// WithUserAgent sets the request's User-Agent header to use the provided agent name. +func WithUserAgent(userAgent string) Option { + return func(opts *options) { + opts.userAgent = userAgent + } +} + +// WithInsecureSkipVerifyTLS determines if a TLS Certificate will be checked +func WithInsecureSkipVerifyTLS(insecureSkipVerifyTLS bool) Option { + return func(opts *options) { + opts.insecureSkipVerifyTLS = insecureSkipVerifyTLS + } +} + +// WithTLSClientConfig sets the client auth with the provided credentials. +func WithTLSClientConfig(certFile, keyFile, caFile string) Option { + return func(opts *options) { + opts.certFile = certFile + opts.keyFile = keyFile + opts.caFile = caFile + } +} + +// WithTimeout sets the timeout for requests +func WithTimeout(timeout time.Duration) Option { + return func(opts *options) { + opts.timeout = timeout + } +} + +// Getter is an interface to support GET to the specified URL. +type Getter interface { + // Get file content by url string + Get(url string, options ...Option) (*bytes.Buffer, error) +} + +// Constructor is the function for every getter which creates a specific instance +// according to the configuration +type Constructor func(options ...Option) (Getter, error) + +// Provider represents any getter and the schemes that it supports. +// +// For example, an HTTP provider may provide one getter that handles both +// 'http' and 'https' schemes. +type Provider struct { + Schemes []string + New Constructor +} + +// Provides returns true if the given scheme is supported by this Provider. +func (p Provider) Provides(scheme string) bool { + for _, i := range p.Schemes { + if i == scheme { + return true + } + } + return false +} + +// Providers is a collection of Provider objects. +type Providers []Provider + +// ByScheme returns a Provider that handles the given scheme. +// +// If no provider handles this scheme, this will return an error. +func (p Providers) ByScheme(scheme string) (Getter, error) { + for _, pp := range p { + if pp.Provides(scheme) { + return pp.New() + } + } + return nil, errors.Errorf("scheme %q not supported", scheme) +} + +var httpProvider = Provider{ + Schemes: []string{"http", "https"}, + New: NewHTTPGetter, +} + +// All finds all of the registered getters as a list of Provider instances. +// Currently, the built-in getters and the discovered plugins with downloader +// notations are collected. +func All(settings *cli.EnvSettings) Providers { + result := Providers{httpProvider} + pluginDownloaders, _ := collectPlugins(settings) + result = append(result, pluginDownloaders...) + return result +} diff --git a/vendor/helm.sh/helm/v3/pkg/getter/httpgetter.go b/vendor/helm.sh/helm/v3/pkg/getter/httpgetter.go new file mode 100644 index 0000000000000000000000000000000000000000..c100b2cc023ccea4eb11d734c875871e84dc5170 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/getter/httpgetter.go @@ -0,0 +1,126 @@ +/* +Copyright The Helm 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 getter + +import ( + "bytes" + "crypto/tls" + "io" + "net/http" + + "github.com/pkg/errors" + + "helm.sh/helm/v3/internal/tlsutil" + "helm.sh/helm/v3/internal/urlutil" + "helm.sh/helm/v3/internal/version" +) + +// HTTPGetter is the default HTTP(/S) backend handler +type HTTPGetter struct { + opts options +} + +//Get performs a Get from repo.Getter and returns the body. +func (g *HTTPGetter) Get(href string, options ...Option) (*bytes.Buffer, error) { + for _, opt := range options { + opt(&g.opts) + } + return g.get(href) +} + +func (g *HTTPGetter) get(href string) (*bytes.Buffer, error) { + buf := bytes.NewBuffer(nil) + + // Set a helm specific user agent so that a repo server and metrics can + // separate helm calls from other tools interacting with repos. + req, err := http.NewRequest("GET", href, nil) + if err != nil { + return buf, err + } + + req.Header.Set("User-Agent", version.GetUserAgent()) + if g.opts.userAgent != "" { + req.Header.Set("User-Agent", g.opts.userAgent) + } + + if g.opts.username != "" && g.opts.password != "" { + req.SetBasicAuth(g.opts.username, g.opts.password) + } + + client, err := g.httpClient() + if err != nil { + return nil, err + } + + resp, err := client.Do(req) + if err != nil { + return buf, err + } + if resp.StatusCode != 200 { + return buf, errors.Errorf("failed to fetch %s : %s", href, resp.Status) + } + + _, err = io.Copy(buf, resp.Body) + resp.Body.Close() + return buf, err +} + +// NewHTTPGetter constructs a valid http/https client as a Getter +func NewHTTPGetter(options ...Option) (Getter, error) { + var client HTTPGetter + + for _, opt := range options { + opt(&client.opts) + } + + return &client, nil +} + +func (g *HTTPGetter) httpClient() (*http.Client, error) { + transport := &http.Transport{ + DisableCompression: true, + Proxy: http.ProxyFromEnvironment, + } + if (g.opts.certFile != "" && g.opts.keyFile != "") || g.opts.caFile != "" { + tlsConf, err := tlsutil.NewClientTLS(g.opts.certFile, g.opts.keyFile, g.opts.caFile) + if err != nil { + return nil, errors.Wrap(err, "can't create TLS config for client") + } + tlsConf.BuildNameToCertificate() + + sni, err := urlutil.ExtractHostname(g.opts.url) + if err != nil { + return nil, err + } + tlsConf.ServerName = sni + + transport.TLSClientConfig = tlsConf + } + + if g.opts.insecureSkipVerifyTLS { + transport.TLSClientConfig = &tls.Config{ + InsecureSkipVerify: true, + } + + } + + client := &http.Client{ + Transport: transport, + Timeout: g.opts.timeout, + } + + return client, nil +} diff --git a/vendor/helm.sh/helm/v3/pkg/getter/plugingetter.go b/vendor/helm.sh/helm/v3/pkg/getter/plugingetter.go new file mode 100644 index 0000000000000000000000000000000000000000..0d13ade570750963e2fee6e35271e108982dadb2 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/getter/plugingetter.go @@ -0,0 +1,102 @@ +/* +Copyright The Helm 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 getter + +import ( + "bytes" + "os" + "os/exec" + "path/filepath" + "strings" + + "github.com/pkg/errors" + + "helm.sh/helm/v3/pkg/cli" + "helm.sh/helm/v3/pkg/plugin" +) + +// collectPlugins scans for getter plugins. +// This will load plugins according to the cli. +func collectPlugins(settings *cli.EnvSettings) (Providers, error) { + plugins, err := plugin.FindPlugins(settings.PluginsDirectory) + if err != nil { + return nil, err + } + var result Providers + for _, plugin := range plugins { + for _, downloader := range plugin.Metadata.Downloaders { + result = append(result, Provider{ + Schemes: downloader.Protocols, + New: NewPluginGetter( + downloader.Command, + settings, + plugin.Metadata.Name, + plugin.Dir, + ), + }) + } + } + return result, nil +} + +// pluginGetter is a generic type to invoke custom downloaders, +// implemented in plugins. +type pluginGetter struct { + command string + settings *cli.EnvSettings + name string + base string + opts options +} + +// Get runs downloader plugin command +func (p *pluginGetter) Get(href string, options ...Option) (*bytes.Buffer, error) { + for _, opt := range options { + opt(&p.opts) + } + commands := strings.Split(p.command, " ") + argv := append(commands[1:], p.opts.certFile, p.opts.keyFile, p.opts.caFile, href) + prog := exec.Command(filepath.Join(p.base, commands[0]), argv...) + plugin.SetupPluginEnv(p.settings, p.name, p.base) + prog.Env = os.Environ() + buf := bytes.NewBuffer(nil) + prog.Stdout = buf + prog.Stderr = os.Stderr + if err := prog.Run(); err != nil { + if eerr, ok := err.(*exec.ExitError); ok { + os.Stderr.Write(eerr.Stderr) + return nil, errors.Errorf("plugin %q exited with error", p.command) + } + return nil, err + } + return buf, nil +} + +// NewPluginGetter constructs a valid plugin getter +func NewPluginGetter(command string, settings *cli.EnvSettings, name, base string) Constructor { + return func(options ...Option) (Getter, error) { + result := &pluginGetter{ + command: command, + settings: settings, + name: name, + base: base, + } + for _, opt := range options { + opt(&result.opts) + } + return result, nil + } +} diff --git a/vendor/helm.sh/helm/v3/pkg/helmpath/home.go b/vendor/helm.sh/helm/v3/pkg/helmpath/home.go new file mode 100644 index 0000000000000000000000000000000000000000..bd43e8890c8f1eca79de939d33e3507d7426e3d8 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/helmpath/home.go @@ -0,0 +1,44 @@ +// Copyright The Helm 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 helmpath calculates filesystem paths to Helm's configuration, cache and data. +package helmpath + +// This helper builds paths to Helm's configuration, cache and data paths. +const lp = lazypath("helm") + +// ConfigPath returns the path where Helm stores configuration. +func ConfigPath(elem ...string) string { return lp.configPath(elem...) } + +// CachePath returns the path where Helm stores cached objects. +func CachePath(elem ...string) string { return lp.cachePath(elem...) } + +// DataPath returns the path where Helm stores data. +func DataPath(elem ...string) string { return lp.dataPath(elem...) } + +// CacheIndexFile returns the path to an index for the given named repository. +func CacheIndexFile(name string) string { + if name != "" { + name += "-" + } + return name + "index.yaml" +} + +// CacheChartsFile returns the path to a text file listing all the charts +// within the given named repository. +func CacheChartsFile(name string) string { + if name != "" { + name += "-" + } + return name + "charts.txt" +} diff --git a/vendor/helm.sh/helm/v3/pkg/helmpath/lazypath.go b/vendor/helm.sh/helm/v3/pkg/helmpath/lazypath.go new file mode 100644 index 0000000000000000000000000000000000000000..22d7bf0a1b85a5834d29e2898ce67ace79eebcd8 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/helmpath/lazypath.go @@ -0,0 +1,72 @@ +// Copyright The Helm 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 helmpath + +import ( + "os" + "path/filepath" + + "helm.sh/helm/v3/pkg/helmpath/xdg" +) + +const ( + // CacheHomeEnvVar is the environment variable used by Helm + // for the cache directory. When no value is set a default is used. + CacheHomeEnvVar = "HELM_CACHE_HOME" + + // ConfigHomeEnvVar is the environment variable used by Helm + // for the config directory. When no value is set a default is used. + ConfigHomeEnvVar = "HELM_CONFIG_HOME" + + // DataHomeEnvVar is the environment variable used by Helm + // for the data directory. When no value is set a default is used. + DataHomeEnvVar = "HELM_DATA_HOME" +) + +// lazypath is an lazy-loaded path buffer for the XDG base directory specification. +type lazypath string + +func (l lazypath) path(helmEnvVar, xdgEnvVar string, defaultFn func() string, elem ...string) string { + + // There is an order to checking for a path. + // 1. See if a Helm specific environment variable has been set. + // 2. Check if an XDG environment variable is set + // 3. Fall back to a default + base := os.Getenv(helmEnvVar) + if base != "" { + return filepath.Join(base, filepath.Join(elem...)) + } + base = os.Getenv(xdgEnvVar) + if base == "" { + base = defaultFn() + } + return filepath.Join(base, string(l), filepath.Join(elem...)) +} + +// cachePath defines the base directory relative to which user specific non-essential data files +// should be stored. +func (l lazypath) cachePath(elem ...string) string { + return l.path(CacheHomeEnvVar, xdg.CacheHomeEnvVar, cacheHome, filepath.Join(elem...)) +} + +// configPath defines the base directory relative to which user specific configuration files should +// be stored. +func (l lazypath) configPath(elem ...string) string { + return l.path(ConfigHomeEnvVar, xdg.ConfigHomeEnvVar, configHome, filepath.Join(elem...)) +} + +// dataPath defines the base directory relative to which user specific data files should be stored. +func (l lazypath) dataPath(elem ...string) string { + return l.path(DataHomeEnvVar, xdg.DataHomeEnvVar, dataHome, filepath.Join(elem...)) +} diff --git a/vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_darwin.go b/vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_darwin.go new file mode 100644 index 0000000000000000000000000000000000000000..e112b8337e498edd86e2b0ae8f86fc519ed1b469 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_darwin.go @@ -0,0 +1,34 @@ +// Copyright The Helm 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. + +// +build darwin + +package helmpath + +import ( + "path/filepath" + + "k8s.io/client-go/util/homedir" +) + +func dataHome() string { + return filepath.Join(homedir.HomeDir(), "Library") +} + +func configHome() string { + return filepath.Join(homedir.HomeDir(), "Library", "Preferences") +} + +func cacheHome() string { + return filepath.Join(homedir.HomeDir(), "Library", "Caches") +} diff --git a/vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_unix.go b/vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_unix.go new file mode 100644 index 0000000000000000000000000000000000000000..b4eae9f664e95872f535f1daff012ad1c6321079 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_unix.go @@ -0,0 +1,45 @@ +// Copyright The Helm 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. + +// +build !windows,!darwin + +package helmpath + +import ( + "path/filepath" + + "k8s.io/client-go/util/homedir" +) + +// dataHome defines the base directory relative to which user specific data files should be stored. +// +// If $XDG_DATA_HOME is either not set or empty, a default equal to $HOME/.local/share is used. +func dataHome() string { + return filepath.Join(homedir.HomeDir(), ".local", "share") +} + +// configHome defines the base directory relative to which user specific configuration files should +// be stored. +// +// If $XDG_CONFIG_HOME is either not set or empty, a default equal to $HOME/.config is used. +func configHome() string { + return filepath.Join(homedir.HomeDir(), ".config") +} + +// cacheHome defines the base directory relative to which user specific non-essential data files +// should be stored. +// +// If $XDG_CACHE_HOME is either not set or empty, a default equal to $HOME/.cache is used. +func cacheHome() string { + return filepath.Join(homedir.HomeDir(), ".cache") +} diff --git a/vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_windows.go b/vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_windows.go new file mode 100644 index 0000000000000000000000000000000000000000..057a3af1408eb7ac901aea88d451613b3f1ea5ee --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/helmpath/lazypath_windows.go @@ -0,0 +1,24 @@ +// Copyright The Helm 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. + +// +build windows + +package helmpath + +import "os" + +func dataHome() string { return configHome() } + +func configHome() string { return os.Getenv("APPDATA") } + +func cacheHome() string { return os.Getenv("TEMP") } diff --git a/vendor/helm.sh/helm/v3/pkg/helmpath/xdg/xdg.go b/vendor/helm.sh/helm/v3/pkg/helmpath/xdg/xdg.go new file mode 100644 index 0000000000000000000000000000000000000000..eaa3e68643479feb9bd70c127f9655d91982161f --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/helmpath/xdg/xdg.go @@ -0,0 +1,34 @@ +/* +Copyright The Helm 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 xdg holds constants pertaining to XDG Base Directory Specification. +// +// The XDG Base Directory Specification https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html +// specifies the environment variables that define user-specific base directories for various categories of files. +package xdg + +const ( + // CacheHomeEnvVar is the environment variable used by the + // XDG base directory specification for the cache directory. + CacheHomeEnvVar = "XDG_CACHE_HOME" + + // ConfigHomeEnvVar is the environment variable used by the + // XDG base directory specification for the config directory. + ConfigHomeEnvVar = "XDG_CONFIG_HOME" + + // DataHomeEnvVar is the environment variable used by the + // XDG base directory specification for the data directory. + DataHomeEnvVar = "XDG_DATA_HOME" +) diff --git a/vendor/helm.sh/helm/v3/pkg/plugin/hooks.go b/vendor/helm.sh/helm/v3/pkg/plugin/hooks.go new file mode 100644 index 0000000000000000000000000000000000000000..e3481515f066ca83b3a03a3c8ff53fd5cd93c7c9 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/plugin/hooks.go @@ -0,0 +1,29 @@ +/* +Copyright The Helm 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 plugin // import "helm.sh/helm/v3/pkg/plugin" + +// Types of hooks +const ( + // Install is executed after the plugin is added. + Install = "install" + // Delete is executed after the plugin is removed. + Delete = "delete" + // Update is executed after the plugin is updated. + Update = "update" +) + +// Hooks is a map of events to commands. +type Hooks map[string]string diff --git a/vendor/helm.sh/helm/v3/pkg/plugin/plugin.go b/vendor/helm.sh/helm/v3/pkg/plugin/plugin.go new file mode 100644 index 0000000000000000000000000000000000000000..caa34fbd3445199da4f02564630eb29889fd07b5 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/plugin/plugin.go @@ -0,0 +1,225 @@ +/* +Copyright The Helm 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 plugin // import "helm.sh/helm/v3/pkg/plugin" + +import ( + "fmt" + "io/ioutil" + "os" + "path/filepath" + "runtime" + "strings" + + "sigs.k8s.io/yaml" + + "helm.sh/helm/v3/pkg/cli" +) + +const PluginFileName = "plugin.yaml" + +// Downloaders represents the plugins capability if it can retrieve +// charts from special sources +type Downloaders struct { + // Protocols are the list of schemes from the charts URL. + Protocols []string `json:"protocols"` + // Command is the executable path with which the plugin performs + // the actual download for the corresponding Protocols + Command string `json:"command"` +} + +// PlatformCommand represents a command for a particular operating system and architecture +type PlatformCommand struct { + OperatingSystem string `json:"os"` + Architecture string `json:"arch"` + Command string `json:"command"` +} + +// Metadata describes a plugin. +// +// This is the plugin equivalent of a chart.Metadata. +type Metadata struct { + // Name is the name of the plugin + Name string `json:"name"` + + // Version is a SemVer 2 version of the plugin. + Version string `json:"version"` + + // Usage is the single-line usage text shown in help + Usage string `json:"usage"` + + // Description is a long description shown in places like `helm help` + Description string `json:"description"` + + // Command is the command, as a single string. + // + // The command will be passed through environment expansion, so env vars can + // be present in this command. Unless IgnoreFlags is set, this will + // also merge the flags passed from Helm. + // + // Note that command is not executed in a shell. To do so, we suggest + // pointing the command to a shell script. + // + // The following rules will apply to processing commands: + // - If platformCommand is present, it will be searched first + // - If both OS and Arch match the current platform, search will stop and the command will be executed + // - If OS matches and there is no more specific match, the command will be executed + // - If no OS/Arch match is found, the default command will be executed + // - If no command is present and no matches are found in platformCommand, Helm will exit with an error + PlatformCommand []PlatformCommand `json:"platformCommand"` + Command string `json:"command"` + + // IgnoreFlags ignores any flags passed in from Helm + // + // For example, if the plugin is invoked as `helm --debug myplugin`, if this + // is false, `--debug` will be appended to `--command`. If this is true, + // the `--debug` flag will be discarded. + IgnoreFlags bool `json:"ignoreFlags"` + + // Hooks are commands that will run on events. + Hooks Hooks + + // Downloaders field is used if the plugin supply downloader mechanism + // for special protocols. + Downloaders []Downloaders `json:"downloaders"` +} + +// Plugin represents a plugin. +type Plugin struct { + // Metadata is a parsed representation of a plugin.yaml + Metadata *Metadata + // Dir is the string path to the directory that holds the plugin. + Dir string +} + +// The following rules will apply to processing the Plugin.PlatformCommand.Command: +// - If both OS and Arch match the current platform, search will stop and the command will be prepared for execution +// - If OS matches and there is no more specific match, the command will be prepared for execution +// - If no OS/Arch match is found, return nil +func getPlatformCommand(cmds []PlatformCommand) []string { + var command []string + eq := strings.EqualFold + for _, c := range cmds { + if eq(c.OperatingSystem, runtime.GOOS) { + command = strings.Split(os.ExpandEnv(c.Command), " ") + } + if eq(c.OperatingSystem, runtime.GOOS) && eq(c.Architecture, runtime.GOARCH) { + return strings.Split(os.ExpandEnv(c.Command), " ") + } + } + return command +} + +// PrepareCommand takes a Plugin.PlatformCommand.Command, a Plugin.Command and will applying the following processing: +// - If platformCommand is present, it will be searched first +// - If both OS and Arch match the current platform, search will stop and the command will be prepared for execution +// - If OS matches and there is no more specific match, the command will be prepared for execution +// - If no OS/Arch match is found, the default command will be prepared for execution +// - If no command is present and no matches are found in platformCommand, will exit with an error +// +// It merges extraArgs into any arguments supplied in the plugin. It +// returns the name of the command and an args array. +// +// The result is suitable to pass to exec.Command. +func (p *Plugin) PrepareCommand(extraArgs []string) (string, []string, error) { + var parts []string + platCmdLen := len(p.Metadata.PlatformCommand) + if platCmdLen > 0 { + parts = getPlatformCommand(p.Metadata.PlatformCommand) + } + if platCmdLen == 0 || parts == nil { + parts = strings.Split(os.ExpandEnv(p.Metadata.Command), " ") + } + if len(parts) == 0 || parts[0] == "" { + return "", nil, fmt.Errorf("No plugin command is applicable") + } + + main := parts[0] + baseArgs := []string{} + if len(parts) > 1 { + baseArgs = parts[1:] + } + if !p.Metadata.IgnoreFlags { + baseArgs = append(baseArgs, extraArgs...) + } + return main, baseArgs, nil +} + +// LoadDir loads a plugin from the given directory. +func LoadDir(dirname string) (*Plugin, error) { + data, err := ioutil.ReadFile(filepath.Join(dirname, PluginFileName)) + if err != nil { + return nil, err + } + + plug := &Plugin{Dir: dirname} + if err := yaml.Unmarshal(data, &plug.Metadata); err != nil { + return nil, err + } + return plug, nil +} + +// LoadAll loads all plugins found beneath the base directory. +// +// This scans only one directory level. +func LoadAll(basedir string) ([]*Plugin, error) { + plugins := []*Plugin{} + // We want basedir/*/plugin.yaml + scanpath := filepath.Join(basedir, "*", PluginFileName) + matches, err := filepath.Glob(scanpath) + if err != nil { + return plugins, err + } + + if matches == nil { + return plugins, nil + } + + for _, yaml := range matches { + dir := filepath.Dir(yaml) + p, err := LoadDir(dir) + if err != nil { + return plugins, err + } + plugins = append(plugins, p) + } + return plugins, nil +} + +// FindPlugins returns a list of YAML files that describe plugins. +func FindPlugins(plugdirs string) ([]*Plugin, error) { + found := []*Plugin{} + // Let's get all UNIXy and allow path separators + for _, p := range filepath.SplitList(plugdirs) { + matches, err := LoadAll(p) + if err != nil { + return matches, err + } + found = append(found, matches...) + } + return found, nil +} + +// SetupPluginEnv prepares os.Env for plugins. It operates on os.Env because +// the plugin subsystem itself needs access to the environment variables +// created here. +func SetupPluginEnv(settings *cli.EnvSettings, name, base string) { + env := settings.EnvVars() + env["HELM_PLUGIN_NAME"] = name + env["HELM_PLUGIN_DIR"] = base + for key, val := range env { + os.Setenv(key, val) + } +} diff --git a/vendor/helm.sh/helm/v3/pkg/provenance/doc.go b/vendor/helm.sh/helm/v3/pkg/provenance/doc.go new file mode 100644 index 0000000000000000000000000000000000000000..3d2d0ea971ac395ab6e20b1dcb24cd9c66f87d50 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/provenance/doc.go @@ -0,0 +1,37 @@ +/* +Copyright The Helm 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 provenance provides tools for establishing the authenticity of a chart. + +In Helm, provenance is established via several factors. The primary factor is the +cryptographic signature of a chart. Chart authors may sign charts, which in turn +provide the necessary metadata to ensure the integrity of the chart file, the +Chart.yaml, and the referenced Docker images. + +A provenance file is clear-signed. This provides cryptographic verification that +a particular block of information (Chart.yaml, archive file, images) have not +been tampered with or altered. To learn more, read the GnuPG documentation on +clear signatures: +https://www.gnupg.org/gph/en/manual/x135.html + +The cryptography used by Helm should be compatible with OpenGPG. For example, +you should be able to verify a signature by importing the desired public key +and using `gpg --verify`, `keybase pgp verify`, or similar: + + $ gpg --verify some.sig + gpg: Signature made Mon Jul 25 17:23:44 2016 MDT using RSA key ID 1FC18762 + gpg: Good signature from "Helm Testing (This key should only be used for testing. DO NOT TRUST.) " [ultimate] +*/ +package provenance // import "helm.sh/helm/v3/pkg/provenance" diff --git a/vendor/helm.sh/helm/v3/pkg/provenance/sign.go b/vendor/helm.sh/helm/v3/pkg/provenance/sign.go new file mode 100644 index 0000000000000000000000000000000000000000..5d16779f1077e8b83d2870c6981d66b4e379fca4 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/provenance/sign.go @@ -0,0 +1,409 @@ +/* +Copyright The Helm 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 provenance + +import ( + "bytes" + "crypto" + "encoding/hex" + "io" + "io/ioutil" + "os" + "path/filepath" + "strings" + + "github.com/pkg/errors" + "golang.org/x/crypto/openpgp" + "golang.org/x/crypto/openpgp/clearsign" + "golang.org/x/crypto/openpgp/packet" + "sigs.k8s.io/yaml" + + hapi "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chart/loader" +) + +var defaultPGPConfig = packet.Config{ + DefaultHash: crypto.SHA512, +} + +// SumCollection represents a collection of file and image checksums. +// +// Files are of the form: +// FILENAME: "sha256:SUM" +// Images are of the form: +// "IMAGE:TAG": "sha256:SUM" +// Docker optionally supports sha512, and if this is the case, the hash marker +// will be 'sha512' instead of 'sha256'. +type SumCollection struct { + Files map[string]string `json:"files"` + Images map[string]string `json:"images,omitempty"` +} + +// Verification contains information about a verification operation. +type Verification struct { + // SignedBy contains the entity that signed a chart. + SignedBy *openpgp.Entity + // FileHash is the hash, prepended with the scheme, for the file that was verified. + FileHash string + // FileName is the name of the file that FileHash verifies. + FileName string +} + +// Signatory signs things. +// +// Signatories can be constructed from a PGP private key file using NewFromFiles +// or they can be constructed manually by setting the Entity to a valid +// PGP entity. +// +// The same Signatory can be used to sign or validate multiple charts. +type Signatory struct { + // The signatory for this instance of Helm. This is used for signing. + Entity *openpgp.Entity + // The keyring for this instance of Helm. This is used for verification. + KeyRing openpgp.EntityList +} + +// NewFromFiles constructs a new Signatory from the PGP key in the given filename. +// +// This will emit an error if it cannot find a valid GPG keyfile (entity) at the +// given location. +// +// Note that the keyfile may have just a public key, just a private key, or +// both. The Signatory methods may have different requirements of the keys. For +// example, ClearSign must have a valid `openpgp.Entity.PrivateKey` before it +// can sign something. +func NewFromFiles(keyfile, keyringfile string) (*Signatory, error) { + e, err := loadKey(keyfile) + if err != nil { + return nil, err + } + + ring, err := loadKeyRing(keyringfile) + if err != nil { + return nil, err + } + + return &Signatory{ + Entity: e, + KeyRing: ring, + }, nil +} + +// NewFromKeyring reads a keyring file and creates a Signatory. +// +// If id is not the empty string, this will also try to find an Entity in the +// keyring whose name matches, and set that as the signing entity. It will return +// an error if the id is not empty and also not found. +func NewFromKeyring(keyringfile, id string) (*Signatory, error) { + ring, err := loadKeyRing(keyringfile) + if err != nil { + return nil, err + } + + s := &Signatory{KeyRing: ring} + + // If the ID is empty, we can return now. + if id == "" { + return s, nil + } + + // We're gonna go all GnuPG on this and look for a string that _contains_. If + // two or more keys contain the string and none are a direct match, we error + // out. + var candidate *openpgp.Entity + vague := false + for _, e := range ring { + for n := range e.Identities { + if n == id { + s.Entity = e + return s, nil + } + if strings.Contains(n, id) { + if candidate != nil { + vague = true + } + candidate = e + } + } + } + if vague { + return s, errors.Errorf("more than one key contain the id %q", id) + } + + s.Entity = candidate + return s, nil +} + +// PassphraseFetcher returns a passphrase for decrypting keys. +// +// This is used as a callback to read a passphrase from some other location. The +// given name is the Name field on the key, typically of the form: +// +// USER_NAME (COMMENT) +type PassphraseFetcher func(name string) ([]byte, error) + +// DecryptKey decrypts a private key in the Signatory. +// +// If the key is not encrypted, this will return without error. +// +// If the key does not exist, this will return an error. +// +// If the key exists, but cannot be unlocked with the passphrase returned by +// the PassphraseFetcher, this will return an error. +// +// If the key is successfully unlocked, it will return nil. +func (s *Signatory) DecryptKey(fn PassphraseFetcher) error { + if s.Entity == nil { + return errors.New("private key not found") + } else if s.Entity.PrivateKey == nil { + return errors.New("provided key is not a private key. Try providing a keyring with secret keys") + } + + // Nothing else to do if key is not encrypted. + if !s.Entity.PrivateKey.Encrypted { + return nil + } + + fname := "Unknown" + for i := range s.Entity.Identities { + if i != "" { + fname = i + break + } + } + + p, err := fn(fname) + if err != nil { + return err + } + + return s.Entity.PrivateKey.Decrypt(p) +} + +// ClearSign signs a chart with the given key. +// +// This takes the path to a chart archive file and a key, and it returns a clear signature. +// +// The Signatory must have a valid Entity.PrivateKey for this to work. If it does +// not, an error will be returned. +func (s *Signatory) ClearSign(chartpath string) (string, error) { + if s.Entity == nil { + return "", errors.New("private key not found") + } else if s.Entity.PrivateKey == nil { + return "", errors.New("provided key is not a private key. Try providing a keyring with secret keys") + } + + if fi, err := os.Stat(chartpath); err != nil { + return "", err + } else if fi.IsDir() { + return "", errors.New("cannot sign a directory") + } + + out := bytes.NewBuffer(nil) + + b, err := messageBlock(chartpath) + if err != nil { + return "", nil + } + + // Sign the buffer + w, err := clearsign.Encode(out, s.Entity.PrivateKey, &defaultPGPConfig) + if err != nil { + return "", err + } + _, err = io.Copy(w, b) + w.Close() + return out.String(), err +} + +// Verify checks a signature and verifies that it is legit for a chart. +func (s *Signatory) Verify(chartpath, sigpath string) (*Verification, error) { + ver := &Verification{} + for _, fname := range []string{chartpath, sigpath} { + if fi, err := os.Stat(fname); err != nil { + return ver, err + } else if fi.IsDir() { + return ver, errors.Errorf("%s cannot be a directory", fname) + } + } + + // First verify the signature + sig, err := s.decodeSignature(sigpath) + if err != nil { + return ver, errors.Wrap(err, "failed to decode signature") + } + + by, err := s.verifySignature(sig) + if err != nil { + return ver, err + } + ver.SignedBy = by + + // Second, verify the hash of the tarball. + sum, err := DigestFile(chartpath) + if err != nil { + return ver, err + } + _, sums, err := parseMessageBlock(sig.Plaintext) + if err != nil { + return ver, err + } + + sum = "sha256:" + sum + basename := filepath.Base(chartpath) + if sha, ok := sums.Files[basename]; !ok { + return ver, errors.Errorf("provenance does not contain a SHA for a file named %q", basename) + } else if sha != sum { + return ver, errors.Errorf("sha256 sum does not match for %s: %q != %q", basename, sha, sum) + } + ver.FileHash = sum + ver.FileName = basename + + // TODO: when image signing is added, verify that here. + + return ver, nil +} + +func (s *Signatory) decodeSignature(filename string) (*clearsign.Block, error) { + data, err := ioutil.ReadFile(filename) + if err != nil { + return nil, err + } + + block, _ := clearsign.Decode(data) + if block == nil { + // There was no sig in the file. + return nil, errors.New("signature block not found") + } + + return block, nil +} + +// verifySignature verifies that the given block is validly signed, and returns the signer. +func (s *Signatory) verifySignature(block *clearsign.Block) (*openpgp.Entity, error) { + return openpgp.CheckDetachedSignature( + s.KeyRing, + bytes.NewBuffer(block.Bytes), + block.ArmoredSignature.Body, + ) +} + +func messageBlock(chartpath string) (*bytes.Buffer, error) { + var b *bytes.Buffer + // Checksum the archive + chash, err := DigestFile(chartpath) + if err != nil { + return b, err + } + + base := filepath.Base(chartpath) + sums := &SumCollection{ + Files: map[string]string{ + base: "sha256:" + chash, + }, + } + + // Load the archive into memory. + chart, err := loader.LoadFile(chartpath) + if err != nil { + return b, err + } + + // Buffer a hash + checksums YAML file + data, err := yaml.Marshal(chart.Metadata) + if err != nil { + return b, err + } + + // FIXME: YAML uses ---\n as a file start indicator, but this is not legal in a PGP + // clearsign block. So we use ...\n, which is the YAML document end marker. + // http://yaml.org/spec/1.2/spec.html#id2800168 + b = bytes.NewBuffer(data) + b.WriteString("\n...\n") + + data, err = yaml.Marshal(sums) + if err != nil { + return b, err + } + b.Write(data) + + return b, nil +} + +// parseMessageBlock +func parseMessageBlock(data []byte) (*hapi.Metadata, *SumCollection, error) { + // This sucks. + parts := bytes.Split(data, []byte("\n...\n")) + if len(parts) < 2 { + return nil, nil, errors.New("message block must have at least two parts") + } + + md := &hapi.Metadata{} + sc := &SumCollection{} + + if err := yaml.Unmarshal(parts[0], md); err != nil { + return md, sc, err + } + err := yaml.Unmarshal(parts[1], sc) + return md, sc, err +} + +// loadKey loads a GPG key found at a particular path. +func loadKey(keypath string) (*openpgp.Entity, error) { + f, err := os.Open(keypath) + if err != nil { + return nil, err + } + defer f.Close() + + pr := packet.NewReader(f) + return openpgp.ReadEntity(pr) +} + +func loadKeyRing(ringpath string) (openpgp.EntityList, error) { + f, err := os.Open(ringpath) + if err != nil { + return nil, err + } + defer f.Close() + return openpgp.ReadKeyRing(f) +} + +// DigestFile calculates a SHA256 hash (like Docker) for a given file. +// +// It takes the path to the archive file, and returns a string representation of +// the SHA256 sum. +// +// The intended use of this function is to generate a sum of a chart TGZ file. +func DigestFile(filename string) (string, error) { + f, err := os.Open(filename) + if err != nil { + return "", err + } + defer f.Close() + return Digest(f) +} + +// Digest hashes a reader and returns a SHA256 digest. +// +// Helm uses SHA256 as its default hash for all non-cryptographic applications. +func Digest(in io.Reader) (string, error) { + hash := crypto.SHA256.New() + if _, err := io.Copy(hash, in); err != nil { + return "", nil + } + return hex.EncodeToString(hash.Sum(nil)), nil +} diff --git a/vendor/helm.sh/helm/v3/pkg/repo/chartrepo.go b/vendor/helm.sh/helm/v3/pkg/repo/chartrepo.go new file mode 100644 index 0000000000000000000000000000000000000000..c2c366a1ee715a3b8f09045cb61d7458587146cf --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/repo/chartrepo.go @@ -0,0 +1,285 @@ +/* +Copyright The Helm 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 repo // import "helm.sh/helm/v3/pkg/repo" + +import ( + "crypto/rand" + "encoding/base64" + "encoding/json" + "fmt" + "io/ioutil" + "log" + "net/url" + "os" + "path" + "path/filepath" + "strings" + + "github.com/pkg/errors" + "sigs.k8s.io/yaml" + + "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/getter" + "helm.sh/helm/v3/pkg/helmpath" + "helm.sh/helm/v3/pkg/provenance" +) + +// Entry represents a collection of parameters for chart repository +type Entry struct { + Name string `json:"name"` + URL string `json:"url"` + 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"` +} + +// ChartRepository represents a chart repository +type ChartRepository struct { + Config *Entry + ChartPaths []string + IndexFile *IndexFile + Client getter.Getter + CachePath string +} + +// NewChartRepository constructs ChartRepository +func NewChartRepository(cfg *Entry, getters getter.Providers) (*ChartRepository, error) { + u, err := url.Parse(cfg.URL) + if err != nil { + return nil, errors.Errorf("invalid chart URL format: %s", cfg.URL) + } + + client, err := getters.ByScheme(u.Scheme) + if err != nil { + return nil, errors.Errorf("could not find protocol handler for: %s", u.Scheme) + } + + return &ChartRepository{ + Config: cfg, + IndexFile: NewIndexFile(), + Client: client, + CachePath: helmpath.CachePath("repository"), + }, nil +} + +// Load loads a directory of charts as if it were a repository. +// +// It requires the presence of an index.yaml file in the directory. +func (r *ChartRepository) Load() error { + dirInfo, err := os.Stat(r.Config.Name) + if err != nil { + return err + } + if !dirInfo.IsDir() { + return errors.Errorf("%q is not a directory", r.Config.Name) + } + + // FIXME: Why are we recursively walking directories? + // FIXME: Why are we not reading the repositories.yaml to figure out + // what repos to use? + filepath.Walk(r.Config.Name, func(path string, f os.FileInfo, err error) error { + if !f.IsDir() { + if strings.Contains(f.Name(), "-index.yaml") { + i, err := LoadIndexFile(path) + if err != nil { + return nil + } + r.IndexFile = i + } else if strings.HasSuffix(f.Name(), ".tgz") { + r.ChartPaths = append(r.ChartPaths, path) + } + } + return nil + }) + return nil +} + +// DownloadIndexFile fetches the index from a repository. +func (r *ChartRepository) DownloadIndexFile() (string, error) { + parsedURL, err := url.Parse(r.Config.URL) + if err != nil { + return "", err + } + parsedURL.RawPath = path.Join(parsedURL.RawPath, "index.yaml") + parsedURL.Path = path.Join(parsedURL.Path, "index.yaml") + + indexURL := parsedURL.String() + // TODO add user-agent + resp, err := r.Client.Get(indexURL, + getter.WithURL(r.Config.URL), + getter.WithInsecureSkipVerifyTLS(r.Config.InsecureSkipTLSverify), + getter.WithTLSClientConfig(r.Config.CertFile, r.Config.KeyFile, r.Config.CAFile), + getter.WithBasicAuth(r.Config.Username, r.Config.Password), + ) + if err != nil { + return "", err + } + + index, err := ioutil.ReadAll(resp) + if err != nil { + return "", err + } + + indexFile, err := loadIndex(index) + if err != nil { + return "", err + } + + // Create the chart list file in the cache directory + var charts strings.Builder + for name := range indexFile.Entries { + fmt.Fprintln(&charts, name) + } + chartsFile := filepath.Join(r.CachePath, helmpath.CacheChartsFile(r.Config.Name)) + os.MkdirAll(filepath.Dir(chartsFile), 0755) + ioutil.WriteFile(chartsFile, []byte(charts.String()), 0644) + + // Create the index file in the cache directory + fname := filepath.Join(r.CachePath, helmpath.CacheIndexFile(r.Config.Name)) + os.MkdirAll(filepath.Dir(fname), 0755) + return fname, ioutil.WriteFile(fname, index, 0644) +} + +// Index generates an index for the chart repository and writes an index.yaml file. +func (r *ChartRepository) Index() error { + err := r.generateIndex() + if err != nil { + return err + } + return r.saveIndexFile() +} + +func (r *ChartRepository) saveIndexFile() error { + index, err := yaml.Marshal(r.IndexFile) + if err != nil { + return err + } + return ioutil.WriteFile(filepath.Join(r.Config.Name, indexPath), index, 0644) +} + +func (r *ChartRepository) generateIndex() error { + for _, path := range r.ChartPaths { + ch, err := loader.Load(path) + if err != nil { + return err + } + + digest, err := provenance.DigestFile(path) + if err != nil { + return err + } + + if !r.IndexFile.Has(ch.Name(), ch.Metadata.Version) { + r.IndexFile.Add(ch.Metadata, path, r.Config.URL, digest) + } + // TODO: If a chart exists, but has a different Digest, should we error? + } + r.IndexFile.SortEntries() + return nil +} + +// FindChartInRepoURL finds chart in chart repository pointed by repoURL +// without adding repo to repositories +func FindChartInRepoURL(repoURL, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) { + return FindChartInAuthRepoURL(repoURL, "", "", chartName, chartVersion, certFile, keyFile, caFile, getters) +} + +// FindChartInAuthRepoURL finds chart in chart repository pointed by repoURL +// without adding repo to repositories, like FindChartInRepoURL, +// but it also receives credentials for the chart repository. +func FindChartInAuthRepoURL(repoURL, username, password, chartName, chartVersion, certFile, keyFile, caFile string, getters getter.Providers) (string, error) { + + // Download and write the index file to a temporary location + buf := make([]byte, 20) + rand.Read(buf) + name := strings.ReplaceAll(base64.StdEncoding.EncodeToString(buf), "/", "-") + + c := Entry{ + URL: repoURL, + Username: username, + Password: password, + CertFile: certFile, + KeyFile: keyFile, + CAFile: caFile, + Name: name, + } + r, err := NewChartRepository(&c, getters) + if err != nil { + return "", err + } + idx, err := r.DownloadIndexFile() + if err != nil { + return "", errors.Wrapf(err, "looks like %q is not a valid chart repository or cannot be reached", repoURL) + } + + // Read the index file for the repository to get chart information and return chart URL + repoIndex, err := LoadIndexFile(idx) + if err != nil { + return "", err + } + + errMsg := fmt.Sprintf("chart %q", chartName) + if chartVersion != "" { + errMsg = fmt.Sprintf("%s version %q", errMsg, chartVersion) + } + cv, err := repoIndex.Get(chartName, chartVersion) + if err != nil { + return "", errors.Errorf("%s not found in %s repository", errMsg, repoURL) + } + + if len(cv.URLs) == 0 { + return "", errors.Errorf("%s has no downloadable URLs", errMsg) + } + + chartURL := cv.URLs[0] + + absoluteChartURL, err := ResolveReferenceURL(repoURL, chartURL) + if err != nil { + return "", errors.Wrap(err, "failed to make chart URL absolute") + } + + return absoluteChartURL, nil +} + +// ResolveReferenceURL resolves refURL relative to baseURL. +// If refURL is absolute, it simply returns refURL. +func ResolveReferenceURL(baseURL, refURL string) (string, error) { + parsedBaseURL, err := url.Parse(baseURL) + if err != nil { + return "", errors.Wrapf(err, "failed to parse %s as URL", baseURL) + } + + parsedRefURL, err := url.Parse(refURL) + if err != nil { + return "", errors.Wrapf(err, "failed to parse %s as URL", refURL) + } + + // We need a trailing slash for ResolveReference to work, but make sure there isn't already one + parsedBaseURL.Path = strings.TrimSuffix(parsedBaseURL.Path, "/") + "/" + return parsedBaseURL.ResolveReference(parsedRefURL).String(), nil +} + +func (e *Entry) String() string { + buf, err := json.Marshal(e) + if err != nil { + log.Panic(err) + } + return string(buf) +} diff --git a/vendor/helm.sh/helm/v3/pkg/repo/doc.go b/vendor/helm.sh/helm/v3/pkg/repo/doc.go new file mode 100644 index 0000000000000000000000000000000000000000..05650100b9c2ffa7ccb322ba7583b72a2359d4af --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/repo/doc.go @@ -0,0 +1,93 @@ +/* +Copyright The Helm 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 repo implements the Helm Chart Repository. + +A chart repository is an HTTP server that provides information on charts. A local +repository cache is an on-disk representation of a chart repository. + +There are two important file formats for chart repositories. + +The first is the 'index.yaml' format, which is expressed like this: + + apiVersion: v1 + entries: + frobnitz: + - created: 2016-09-29T12:14:34.830161306-06:00 + description: This is a frobnitz. + digest: 587bd19a9bd9d2bc4a6d25ab91c8c8e7042c47b4ac246e37bf8e1e74386190f4 + home: http://example.com + keywords: + - frobnitz + - sprocket + - dodad + maintainers: + - email: helm@example.com + name: The Helm Team + - email: nobody@example.com + name: Someone Else + name: frobnitz + urls: + - http://example-charts.com/testdata/repository/frobnitz-1.2.3.tgz + version: 1.2.3 + sprocket: + - created: 2016-09-29T12:14:34.830507606-06:00 + description: This is a sprocket" + digest: 8505ff813c39502cc849a38e1e4a8ac24b8e6e1dcea88f4c34ad9b7439685ae6 + home: http://example.com + keywords: + - frobnitz + - sprocket + - dodad + maintainers: + - email: helm@example.com + name: The Helm Team + - email: nobody@example.com + name: Someone Else + name: sprocket + urls: + - http://example-charts.com/testdata/repository/sprocket-1.2.0.tgz + version: 1.2.0 + generated: 2016-09-29T12:14:34.829721375-06:00 + +An index.yaml file contains the necessary descriptive information about what +charts are available in a repository, and how to get them. + +The second file format is the repositories.yaml file format. This file is for +facilitating local cached copies of one or more chart repositories. + +The format of a repository.yaml file is: + + apiVersion: v1 + generated: TIMESTAMP + repositories: + - name: stable + url: http://example.com/charts + cache: stable-index.yaml + - name: incubator + url: http://example.com/incubator + cache: incubator-index.yaml + +This file maps three bits of information about a repository: + + - The name the user uses to refer to it + - The fully qualified URL to the repository (index.yaml will be appended) + - The name of the local cachefile + +The format for both files was changed after Helm v2.0.0-Alpha.4. Helm is not +backwards compatible with those earlier versions. +*/ +package repo diff --git a/vendor/helm.sh/helm/v3/pkg/repo/index.go b/vendor/helm.sh/helm/v3/pkg/repo/index.go new file mode 100644 index 0000000000000000000000000000000000000000..6ef2cf8b5dfe07474afbe468d5d792c808f9d1b5 --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/repo/index.go @@ -0,0 +1,292 @@ +/* +Copyright The Helm 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 repo + +import ( + "bytes" + "io/ioutil" + "os" + "path" + "path/filepath" + "sort" + "strings" + "time" + + "github.com/Masterminds/semver/v3" + "github.com/pkg/errors" + "sigs.k8s.io/yaml" + + "helm.sh/helm/v3/internal/fileutil" + "helm.sh/helm/v3/internal/urlutil" + "helm.sh/helm/v3/pkg/chart" + "helm.sh/helm/v3/pkg/chart/loader" + "helm.sh/helm/v3/pkg/provenance" +) + +var indexPath = "index.yaml" + +// APIVersionV1 is the v1 API version for index and repository files. +const APIVersionV1 = "v1" + +var ( + // ErrNoAPIVersion indicates that an API version was not specified. + ErrNoAPIVersion = errors.New("no API version specified") + // ErrNoChartVersion indicates that a chart with the given version is not found. + ErrNoChartVersion = errors.New("no chart version found") + // ErrNoChartName indicates that a chart with the given name is not found. + ErrNoChartName = errors.New("no chart name found") +) + +// ChartVersions is a list of versioned chart references. +// Implements a sorter on Version. +type ChartVersions []*ChartVersion + +// Len returns the length. +func (c ChartVersions) Len() int { return len(c) } + +// Swap swaps the position of two items in the versions slice. +func (c ChartVersions) Swap(i, j int) { c[i], c[j] = c[j], c[i] } + +// Less returns true if the version of entry a is less than the version of entry b. +func (c ChartVersions) Less(a, b int) bool { + // Failed parse pushes to the back. + i, err := semver.NewVersion(c[a].Version) + if err != nil { + return true + } + j, err := semver.NewVersion(c[b].Version) + if err != nil { + return false + } + return i.LessThan(j) +} + +// IndexFile represents the index file in a chart repository +type IndexFile struct { + APIVersion string `json:"apiVersion"` + Generated time.Time `json:"generated"` + Entries map[string]ChartVersions `json:"entries"` + PublicKeys []string `json:"publicKeys,omitempty"` +} + +// NewIndexFile initializes an index. +func NewIndexFile() *IndexFile { + return &IndexFile{ + APIVersion: APIVersionV1, + Generated: time.Now(), + Entries: map[string]ChartVersions{}, + PublicKeys: []string{}, + } +} + +// LoadIndexFile takes a file at the given path and returns an IndexFile object +func LoadIndexFile(path string) (*IndexFile, error) { + b, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + return loadIndex(b) +} + +// Add adds a file to the index +// This can leave the index in an unsorted state +func (i IndexFile) Add(md *chart.Metadata, filename, baseURL, digest string) { + u := filename + if baseURL != "" { + var err error + _, file := filepath.Split(filename) + u, err = urlutil.URLJoin(baseURL, file) + if err != nil { + u = path.Join(baseURL, file) + } + } + cr := &ChartVersion{ + URLs: []string{u}, + Metadata: md, + Digest: digest, + Created: time.Now(), + } + if ee, ok := i.Entries[md.Name]; !ok { + i.Entries[md.Name] = ChartVersions{cr} + } else { + i.Entries[md.Name] = append(ee, cr) + } +} + +// Has returns true if the index has an entry for a chart with the given name and exact version. +func (i IndexFile) Has(name, version string) bool { + _, err := i.Get(name, version) + return err == nil +} + +// SortEntries sorts the entries by version in descending order. +// +// In canonical form, the individual version records should be sorted so that +// the most recent release for every version is in the 0th slot in the +// Entries.ChartVersions array. That way, tooling can predict the newest +// version without needing to parse SemVers. +func (i IndexFile) SortEntries() { + for _, versions := range i.Entries { + sort.Sort(sort.Reverse(versions)) + } +} + +// Get returns the ChartVersion for the given name. +// +// If version is empty, this will return the chart with the latest stable version, +// prerelease versions will be skipped. +func (i IndexFile) Get(name, version string) (*ChartVersion, error) { + vs, ok := i.Entries[name] + if !ok { + return nil, ErrNoChartName + } + if len(vs) == 0 { + return nil, ErrNoChartVersion + } + + var constraint *semver.Constraints + if version == "" { + constraint, _ = semver.NewConstraint("*") + } else { + var err error + constraint, err = semver.NewConstraint(version) + if err != nil { + return nil, err + } + } + + // when customer input exact version, check whether have exact match one first + if len(version) != 0 { + for _, ver := range vs { + if version == ver.Version { + return ver, nil + } + } + } + + for _, ver := range vs { + test, err := semver.NewVersion(ver.Version) + if err != nil { + continue + } + + if constraint.Check(test) { + return ver, nil + } + } + return nil, errors.Errorf("no chart version found for %s-%s", name, version) +} + +// WriteFile writes an index file to the given destination path. +// +// The mode on the file is set to 'mode'. +func (i IndexFile) WriteFile(dest string, mode os.FileMode) error { + b, err := yaml.Marshal(i) + if err != nil { + return err + } + return fileutil.AtomicWriteFile(dest, bytes.NewReader(b), mode) +} + +// Merge merges the given index file into this index. +// +// This merges by name and version. +// +// If one of the entries in the given index does _not_ already exist, it is added. +// In all other cases, the existing record is preserved. +// +// This can leave the index in an unsorted state +func (i *IndexFile) Merge(f *IndexFile) { + for _, cvs := range f.Entries { + for _, cv := range cvs { + if !i.Has(cv.Name, cv.Version) { + e := i.Entries[cv.Name] + i.Entries[cv.Name] = append(e, cv) + } + } + } +} + +// ChartVersion represents a chart entry in the IndexFile +type ChartVersion struct { + *chart.Metadata + URLs []string `json:"urls"` + Created time.Time `json:"created,omitempty"` + Removed bool `json:"removed,omitempty"` + Digest string `json:"digest,omitempty"` +} + +// IndexDirectory reads a (flat) directory and generates an index. +// +// It indexes only charts that have been packaged (*.tgz). +// +// The index returned will be in an unsorted state +func IndexDirectory(dir, baseURL string) (*IndexFile, error) { + archives, err := filepath.Glob(filepath.Join(dir, "*.tgz")) + if err != nil { + return nil, err + } + moreArchives, err := filepath.Glob(filepath.Join(dir, "**/*.tgz")) + if err != nil { + return nil, err + } + archives = append(archives, moreArchives...) + + index := NewIndexFile() + for _, arch := range archives { + fname, err := filepath.Rel(dir, arch) + if err != nil { + return index, err + } + + var parentDir string + parentDir, fname = filepath.Split(fname) + // filepath.Split appends an extra slash to the end of parentDir. We want to strip that out. + parentDir = strings.TrimSuffix(parentDir, string(os.PathSeparator)) + parentURL, err := urlutil.URLJoin(baseURL, parentDir) + if err != nil { + parentURL = path.Join(baseURL, parentDir) + } + + c, err := loader.Load(arch) + if err != nil { + // Assume this is not a chart. + continue + } + hash, err := provenance.DigestFile(arch) + if err != nil { + return index, err + } + index.Add(c.Metadata, fname, parentURL, hash) + } + return index, nil +} + +// loadIndex loads an index file and does minimal validity checking. +// +// This will fail if API Version is not set (ErrNoAPIVersion) or if the unmarshal fails. +func loadIndex(data []byte) (*IndexFile, error) { + i := &IndexFile{} + if err := yaml.Unmarshal(data, i); err != nil { + return i, err + } + i.SortEntries() + if i.APIVersion == "" { + return i, ErrNoAPIVersion + } + return i, nil +} diff --git a/vendor/helm.sh/helm/v3/pkg/repo/repo.go b/vendor/helm.sh/helm/v3/pkg/repo/repo.go new file mode 100644 index 0000000000000000000000000000000000000000..6f1e90dad2478f6cdc358c877328546e184f429f --- /dev/null +++ b/vendor/helm.sh/helm/v3/pkg/repo/repo.go @@ -0,0 +1,123 @@ +/* +Copyright The Helm 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 repo // import "helm.sh/helm/v3/pkg/repo" + +import ( + "io/ioutil" + "os" + "path/filepath" + "time" + + "github.com/pkg/errors" + "sigs.k8s.io/yaml" +) + +// File represents the repositories.yaml file +type File struct { + APIVersion string `json:"apiVersion"` + Generated time.Time `json:"generated"` + Repositories []*Entry `json:"repositories"` +} + +// NewFile generates an empty repositories file. +// +// Generated and APIVersion are automatically set. +func NewFile() *File { + return &File{ + APIVersion: APIVersionV1, + Generated: time.Now(), + Repositories: []*Entry{}, + } +} + +// LoadFile takes a file at the given path and returns a File object +func LoadFile(path string) (*File, error) { + r := new(File) + b, err := ioutil.ReadFile(path) + if err != nil { + return r, errors.Wrapf(err, "couldn't load repositories file (%s)", path) + } + + err = yaml.Unmarshal(b, r) + return r, err +} + +// Add adds one or more repo entries to a repo file. +func (r *File) Add(re ...*Entry) { + r.Repositories = append(r.Repositories, re...) +} + +// Update attempts to replace one or more repo entries in a repo file. If an +// entry with the same name doesn't exist in the repo file it will add it. +func (r *File) Update(re ...*Entry) { + for _, target := range re { + r.update(target) + } +} + +func (r *File) update(e *Entry) { + for j, repo := range r.Repositories { + if repo.Name == e.Name { + r.Repositories[j] = e + return + } + } + r.Add(e) +} + +// Has returns true if the given name is already a repository name. +func (r *File) Has(name string) bool { + entry := r.Get(name) + return entry != nil +} + +// Get returns an entry with the given name if it exists, otherwise returns nil +func (r *File) Get(name string) *Entry { + for _, entry := range r.Repositories { + if entry.Name == name { + return entry + } + } + return nil +} + +// Remove removes the entry from the list of repositories. +func (r *File) Remove(name string) bool { + cp := []*Entry{} + found := false + for _, rf := range r.Repositories { + if rf.Name == name { + found = true + continue + } + cp = append(cp, rf) + } + r.Repositories = cp + return found +} + +// WriteFile writes a repositories file to the given path. +func (r *File) WriteFile(path string, perm os.FileMode) error { + data, err := yaml.Marshal(r) + if err != nil { + return err + } + if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil { + return err + } + return ioutil.WriteFile(path, data, perm) +} diff --git a/vendor/modules.txt b/vendor/modules.txt index c6183d0c8da996b4e9cee4e879751d9a3059038e..d91b05d828bc481d583d80d20825074b4a19aa5f 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -5,7 +5,11 @@ github.com/Azure/go-ansiterm github.com/Azure/go-ansiterm/winterm # github.com/BurntSushi/toml v0.3.1 => github.com/BurntSushi/toml v0.3.1 github.com/BurntSushi/toml -# github.com/Microsoft/go-winio v0.4.12 => github.com/Microsoft/go-winio v0.4.12 +# github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd => github.com/MakeNowJust/heredoc v0.0.0-20171113091838-e9091a26100e +github.com/MakeNowJust/heredoc +# github.com/Masterminds/semver/v3 v3.1.0 => github.com/Masterminds/semver/v3 v3.0.1 +github.com/Masterminds/semver/v3 +# github.com/Microsoft/go-winio v0.4.11 => github.com/Microsoft/go-winio v0.4.12 github.com/Microsoft/go-winio # github.com/NYTimes/gziphandler v1.1.1 => github.com/NYTimes/gziphandler v1.1.1 github.com/NYTimes/gziphandler @@ -24,7 +28,7 @@ github.com/alecthomas/template/parse github.com/alecthomas/units # github.com/andybalholm/cascadia v1.0.0 => github.com/andybalholm/cascadia v1.0.0 github.com/andybalholm/cascadia -# github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 => github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 +# github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 => github.com/asaskevich/govalidator v0.0.0-20200108200545-475eaeb16496 github.com/asaskevich/govalidator # github.com/aws/aws-sdk-go v1.33.12 => github.com/aws/aws-sdk-go v1.30.12 github.com/aws/aws-sdk-go/aws @@ -83,6 +87,8 @@ github.com/cespare/xxhash github.com/cespare/xxhash/v2 # github.com/container-storage-interface/spec v1.2.0 => github.com/container-storage-interface/spec v1.2.0 github.com/container-storage-interface/spec/lib/go/csi +# github.com/containerd/containerd v1.3.4 => github.com/containerd/containerd v1.3.0 +github.com/containerd/containerd/errdefs # github.com/containernetworking/cni v0.8.0 => github.com/containernetworking/cni v0.8.0 github.com/containernetworking/cni/pkg/types github.com/containernetworking/cni/pkg/types/020 @@ -105,7 +111,7 @@ github.com/docker/distribution/manifest github.com/docker/distribution/manifest/schema2 github.com/docker/distribution/reference github.com/docker/distribution/registry/api/errcode -# github.com/docker/docker v1.4.2-0.20190822205725-ed20165a37b4 => github.com/docker/engine v1.4.2-0.20190822205725-ed20165a37b4 +# github.com/docker/docker v1.4.2-0.20200203170920-46ec8731fbce => github.com/docker/engine v1.4.2-0.20200203170920-46ec8731fbce github.com/docker/docker/api github.com/docker/docker/api/types github.com/docker/docker/api/types/blkiodev @@ -133,7 +139,7 @@ github.com/docker/go-connections/sockets github.com/docker/go-connections/tlsconfig # github.com/docker/go-units v0.4.0 => github.com/docker/go-units v0.4.0 github.com/docker/go-units -# github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c => github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c +# github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96 => github.com/docker/spdystream v0.0.0-20181023171402-6480d4af844c github.com/docker/spdystream github.com/docker/spdystream/spdy # github.com/edsrzf/mmap-go v1.0.0 => github.com/edsrzf/mmap-go v1.0.0 @@ -155,9 +161,9 @@ github.com/elastic/go-elasticsearch/v7/estransport github.com/elastic/go-elasticsearch/v7/internal/version # github.com/emicklei/go-restful v2.14.3+incompatible => github.com/emicklei/go-restful v2.14.3+incompatible github.com/emicklei/go-restful +github.com/emicklei/go-restful/log # github.com/emicklei/go-restful-openapi v1.4.1 => github.com/emicklei/go-restful-openapi v1.4.1 github.com/emicklei/go-restful-openapi -github.com/emicklei/go-restful/log # github.com/emirpasic/gods v1.12.0 => github.com/emirpasic/gods v1.12.0 github.com/emirpasic/gods/containers github.com/emirpasic/gods/lists @@ -167,8 +173,8 @@ github.com/emirpasic/gods/trees/binaryheap github.com/emirpasic/gods/utils # github.com/evanphx/json-patch v4.9.0+incompatible => github.com/evanphx/json-patch v4.9.0+incompatible github.com/evanphx/json-patch -# github.com/fatih/camelcase v1.0.0 => github.com/fatih/camelcase v1.0.0 -github.com/fatih/camelcase +# github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d => github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d +github.com/exponent-io/jsonpath # github.com/fatih/color v1.9.0 => github.com/fatih/color v1.9.0 github.com/fatih/color # github.com/fatih/structs v1.1.0 => github.com/fatih/structs v1.1.0 @@ -269,6 +275,8 @@ github.com/golang/protobuf/ptypes/timestamp github.com/golang/protobuf/ptypes/wrappers # github.com/golang/snappy v0.0.1 => github.com/golang/snappy v0.0.1 github.com/golang/snappy +# github.com/google/btree v1.0.0 => github.com/google/btree v1.0.0 +github.com/google/btree # github.com/google/go-cmp v0.5.0 => github.com/google/go-cmp v0.4.0 github.com/google/go-cmp/cmp github.com/google/go-cmp/cmp/internal/diff @@ -287,10 +295,9 @@ github.com/googleapis/gnostic/compiler github.com/googleapis/gnostic/extensions # github.com/gorilla/websocket v1.4.1 => github.com/gorilla/websocket v1.4.1 github.com/gorilla/websocket -# github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 => github.com/grpc-ecosystem/go-grpc-middleware v1.1.0 -github.com/grpc-ecosystem/go-grpc-middleware -github.com/grpc-ecosystem/go-grpc-middleware/recovery -github.com/grpc-ecosystem/go-grpc-middleware/validator +# github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 => github.com/gregjones/httpcache v0.0.0-20181110185634-c63ab54fda8f +github.com/gregjones/httpcache +github.com/gregjones/httpcache/diskcache # github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 => github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 github.com/grpc-ecosystem/go-grpc-prometheus # github.com/grpc-ecosystem/grpc-gateway v1.14.4 => github.com/grpc-ecosystem/grpc-gateway v1.14.4 @@ -324,8 +331,6 @@ github.com/jmespath/go-jmespath github.com/json-iterator/go # github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e => github.com/kevinburke/ssh_config v0.0.0-20180830205328-81db2a75821e github.com/kevinburke/ssh_config -# github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7 => github.com/koding/multiconfig v0.0.0-20171124222453-69c27309b2d7 -github.com/koding/multiconfig # github.com/konsorten/go-windows-terminal-sequences v1.0.2 => github.com/konsorten/go-windows-terminal-sequences v1.0.2 github.com/konsorten/go-windows-terminal-sequences # github.com/kubernetes-csi/external-snapshotter/client/v3 v3.0.0 => github.com/kubernetes-csi/external-snapshotter/client/v3 v3.0.0 @@ -358,6 +363,8 @@ github.com/mattn/go-isatty github.com/matttproud/golang_protobuf_extensions/pbutil # github.com/mitchellh/go-homedir v1.1.0 => github.com/mitchellh/go-homedir v1.1.0 github.com/mitchellh/go-homedir +# github.com/mitchellh/go-wordwrap v1.0.0 => github.com/mitchellh/go-wordwrap v1.0.0 +github.com/mitchellh/go-wordwrap # github.com/mitchellh/mapstructure v1.2.2 => github.com/mitchellh/mapstructure v1.2.2 github.com/mitchellh/mapstructure # github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd => github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd @@ -446,7 +453,7 @@ github.com/open-policy-agent/opa/topdown/internal/jwx/jws/verify github.com/open-policy-agent/opa/types github.com/open-policy-agent/opa/util github.com/open-policy-agent/opa/version -# github.com/opencontainers/go-digest v1.0.0-rc1 => github.com/opencontainers/go-digest v1.0.0-rc1 +# github.com/opencontainers/go-digest v1.0.0 => github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/go-digest # github.com/opencontainers/image-spec v1.0.1 => github.com/opencontainers/image-spec v1.0.1 github.com/opencontainers/image-spec/specs-go @@ -461,6 +468,8 @@ github.com/patrickmn/go-cache github.com/pelletier/go-buffruneio # github.com/pelletier/go-toml v1.7.0 => github.com/pelletier/go-toml v1.7.0 github.com/pelletier/go-toml +# github.com/peterbourgon/diskv v2.0.1+incompatible => github.com/peterbourgon/diskv v2.0.1+incompatible +github.com/peterbourgon/diskv # github.com/pkg/errors v0.9.1 => github.com/pkg/errors v0.9.1 github.com/pkg/errors # github.com/pmezard/go-difflib v1.0.0 => github.com/pmezard/go-difflib v1.0.0 @@ -492,9 +501,6 @@ github.com/projectcalico/libcalico-go/lib/set # github.com/prometheus-community/prom-label-proxy v0.2.0 => github.com/prometheus-community/prom-label-proxy v0.2.0 github.com/prometheus-community/prom-label-proxy/injectproxy # github.com/prometheus-operator/prometheus-operator v0.42.2-0.20200928114327-fbd01683839a => github.com/prometheus-operator/prometheus-operator v0.42.2-0.20200928114327-fbd01683839a -# github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.42.1 => github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.42.1 -github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring -github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1 github.com/prometheus-operator/prometheus-operator/pkg/client/informers/externalversions github.com/prometheus-operator/prometheus-operator/pkg/client/informers/externalversions/internalinterfaces github.com/prometheus-operator/prometheus-operator/pkg/client/informers/externalversions/monitoring @@ -505,6 +511,9 @@ github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/fake github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/scheme github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1 github.com/prometheus-operator/prometheus-operator/pkg/client/versioned/typed/monitoring/v1/fake +# github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.42.1 => github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring v0.42.1 +github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring +github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1 # github.com/prometheus/alertmanager v0.21.0 => github.com/prometheus/alertmanager v0.20.0 github.com/prometheus/alertmanager/api/v2/client github.com/prometheus/alertmanager/api/v2/client/alert @@ -563,6 +572,8 @@ github.com/prometheus/prometheus/util/teststorage github.com/prometheus/prometheus/util/testutil # github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a => github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a github.com/rcrowley/go-metrics +# github.com/russross/blackfriday v1.5.2 => github.com/russross/blackfriday v1.5.2 +github.com/russross/blackfriday # github.com/sergi/go-diff v1.0.0 => github.com/sergi/go-diff v1.0.0 github.com/sergi/go-diff/diffmatchpatch # github.com/sirupsen/logrus v1.6.0 => github.com/sirupsen/logrus v1.4.2 @@ -652,20 +663,20 @@ go.uber.org/zap/internal/bufferpool go.uber.org/zap/internal/color go.uber.org/zap/internal/exit go.uber.org/zap/zapcore -# golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de => golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2 golang.org/x/crypto/bcrypt golang.org/x/crypto/blowfish golang.org/x/crypto/cast5 +golang.org/x/crypto/chacha20 golang.org/x/crypto/cryptobyte golang.org/x/crypto/cryptobyte/asn1 golang.org/x/crypto/curve25519 golang.org/x/crypto/ed25519 golang.org/x/crypto/ed25519/internal/edwards25519 -golang.org/x/crypto/internal/chacha20 golang.org/x/crypto/internal/subtle golang.org/x/crypto/nacl/secretbox golang.org/x/crypto/openpgp golang.org/x/crypto/openpgp/armor +golang.org/x/crypto/openpgp/clearsign golang.org/x/crypto/openpgp/elgamal golang.org/x/crypto/openpgp/errors golang.org/x/crypto/openpgp/packet @@ -675,6 +686,7 @@ golang.org/x/crypto/poly1305 golang.org/x/crypto/salsa20/salsa golang.org/x/crypto/ssh golang.org/x/crypto/ssh/agent +golang.org/x/crypto/ssh/internal/bcrypt_pbkdf golang.org/x/crypto/ssh/knownhosts golang.org/x/crypto/ssh/terminal # golang.org/x/lint v0.0.0-20200302205851-738671d3881b => golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f @@ -799,8 +811,6 @@ google.golang.org/grpc/keepalive google.golang.org/grpc/metadata google.golang.org/grpc/naming google.golang.org/grpc/peer -google.golang.org/grpc/reflection -google.golang.org/grpc/reflection/grpc_reflection_v1alpha google.golang.org/grpc/resolver google.golang.org/grpc/resolver/dns google.golang.org/grpc/resolver/passthrough @@ -923,6 +933,23 @@ gotest.tools/assert/cmp gotest.tools/internal/difflib gotest.tools/internal/format gotest.tools/internal/source +# helm.sh/helm/v3 v3.3.0 => helm.sh/helm/v3 v3.3.0 +helm.sh/helm/v3/internal/fileutil +helm.sh/helm/v3/internal/ignore +helm.sh/helm/v3/internal/sympath +helm.sh/helm/v3/internal/third_party/dep/fs +helm.sh/helm/v3/internal/tlsutil +helm.sh/helm/v3/internal/urlutil +helm.sh/helm/v3/internal/version +helm.sh/helm/v3/pkg/chart +helm.sh/helm/v3/pkg/chart/loader +helm.sh/helm/v3/pkg/cli +helm.sh/helm/v3/pkg/getter +helm.sh/helm/v3/pkg/helmpath +helm.sh/helm/v3/pkg/helmpath/xdg +helm.sh/helm/v3/pkg/plugin +helm.sh/helm/v3/pkg/provenance +helm.sh/helm/v3/pkg/repo # honnef.co/go/tools v0.0.1-2020.1.3 => honnef.co/go/tools v0.0.1-2020.1.3 honnef.co/go/tools/arg honnef.co/go/tools/cmd/staticcheck @@ -1028,6 +1055,7 @@ k8s.io/api/discovery/v1beta1 k8s.io/api/events/v1beta1 k8s.io/api/extensions/v1beta1 k8s.io/api/flowcontrol/v1alpha1 +k8s.io/api/imagepolicy/v1alpha1 k8s.io/api/networking/v1 k8s.io/api/networking/v1beta1 k8s.io/api/node/v1alpha1 @@ -1072,6 +1100,7 @@ k8s.io/apimachinery/pkg/apis/meta/internalversion k8s.io/apimachinery/pkg/apis/meta/internalversion/scheme k8s.io/apimachinery/pkg/apis/meta/v1 k8s.io/apimachinery/pkg/apis/meta/v1/unstructured +k8s.io/apimachinery/pkg/apis/meta/v1/unstructured/unstructuredscheme k8s.io/apimachinery/pkg/apis/meta/v1/validation k8s.io/apimachinery/pkg/apis/meta/v1beta1 k8s.io/apimachinery/pkg/apis/meta/v1beta1/validation @@ -1242,9 +1271,21 @@ k8s.io/apiserver/plugin/pkg/audit/webhook k8s.io/apiserver/plugin/pkg/authenticator/token/webhook k8s.io/apiserver/plugin/pkg/authorizer/webhook # k8s.io/cli-runtime v0.18.6 => k8s.io/cli-runtime v0.18.6 +k8s.io/cli-runtime/pkg/genericclioptions +k8s.io/cli-runtime/pkg/kustomize +k8s.io/cli-runtime/pkg/kustomize/k8sdeps +k8s.io/cli-runtime/pkg/kustomize/k8sdeps/configmapandsecret +k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kunstruct +k8s.io/cli-runtime/pkg/kustomize/k8sdeps/kv +k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer +k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/hash +k8s.io/cli-runtime/pkg/kustomize/k8sdeps/transformer/patch +k8s.io/cli-runtime/pkg/kustomize/k8sdeps/validator k8s.io/cli-runtime/pkg/printers +k8s.io/cli-runtime/pkg/resource # k8s.io/client-go v12.0.0+incompatible => k8s.io/client-go v0.18.6 k8s.io/client-go/discovery +k8s.io/client-go/discovery/cached/disk k8s.io/client-go/discovery/fake k8s.io/client-go/dynamic k8s.io/client-go/informers @@ -1432,6 +1473,14 @@ k8s.io/client-go/plugin/pkg/client/auth/exec k8s.io/client-go/rest k8s.io/client-go/rest/watch k8s.io/client-go/restmapper +k8s.io/client-go/scale +k8s.io/client-go/scale/scheme +k8s.io/client-go/scale/scheme/appsint +k8s.io/client-go/scale/scheme/appsv1beta1 +k8s.io/client-go/scale/scheme/appsv1beta2 +k8s.io/client-go/scale/scheme/autoscalingv1 +k8s.io/client-go/scale/scheme/extensionsint +k8s.io/client-go/scale/scheme/extensionsv1beta1 k8s.io/client-go/testing k8s.io/client-go/third_party/forked/golang/template k8s.io/client-go/tools/auth @@ -1511,8 +1560,14 @@ k8s.io/kube-openapi/pkg/handler k8s.io/kube-openapi/pkg/schemaconv k8s.io/kube-openapi/pkg/util k8s.io/kube-openapi/pkg/util/proto +k8s.io/kube-openapi/pkg/util/proto/validation k8s.io/kube-openapi/pkg/util/sets # k8s.io/kubectl v0.18.6 => k8s.io/kubectl v0.18.6 +k8s.io/kubectl/pkg/cmd/util +k8s.io/kubectl/pkg/scheme +k8s.io/kubectl/pkg/util/interrupt +k8s.io/kubectl/pkg/util/openapi +k8s.io/kubectl/pkg/util/openapi/validation k8s.io/kubectl/pkg/util/resource # k8s.io/metrics v0.18.6 => k8s.io/metrics v0.18.6 k8s.io/metrics/pkg/apis/metrics @@ -1527,29 +1582,18 @@ k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1 k8s.io/metrics/pkg/client/clientset/versioned/typed/metrics/v1beta1/fake # k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 => k8s.io/utils v0.0.0-20200603063816-c1c6865ac451 k8s.io/utils/buffer +k8s.io/utils/exec k8s.io/utils/integer k8s.io/utils/net k8s.io/utils/path k8s.io/utils/pointer +k8s.io/utils/strings k8s.io/utils/trace # kubesphere.io/client-go v0.0.0 => ./staging/src/kubesphere.io/client-go kubesphere.io/client-go/client kubesphere.io/client-go/client/generic # openpitrix.io/openpitrix v0.4.9-0.20200611125425-ae07f141e797 => openpitrix.io/openpitrix v0.4.9-0.20200611125425-ae07f141e797 -openpitrix.io/openpitrix/pkg/config -openpitrix.io/openpitrix/pkg/constants -openpitrix.io/openpitrix/pkg/db -openpitrix.io/openpitrix/pkg/gerr -openpitrix.io/openpitrix/pkg/logger -openpitrix.io/openpitrix/pkg/manager openpitrix.io/openpitrix/pkg/pb -openpitrix.io/openpitrix/pkg/sender -openpitrix.io/openpitrix/pkg/util/ctxutil -openpitrix.io/openpitrix/pkg/util/pbutil -openpitrix.io/openpitrix/pkg/util/reflectutil -openpitrix.io/openpitrix/pkg/util/stringutil -openpitrix.io/openpitrix/pkg/util/yamlutil -openpitrix.io/openpitrix/pkg/version # sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7 => sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.7 sigs.k8s.io/apiserver-network-proxy/konnectivity-client/pkg/client sigs.k8s.io/apiserver-network-proxy/konnectivity-client/proto/client @@ -1626,6 +1670,29 @@ sigs.k8s.io/kubefed/pkg/controller/util sigs.k8s.io/kubefed/pkg/kubefedctl/options sigs.k8s.io/kubefed/pkg/kubefedctl/util sigs.k8s.io/kubefed/pkg/metrics +# sigs.k8s.io/kustomize v2.0.3+incompatible => sigs.k8s.io/kustomize v2.0.3+incompatible +sigs.k8s.io/kustomize/pkg/commands/build +sigs.k8s.io/kustomize/pkg/constants +sigs.k8s.io/kustomize/pkg/expansion +sigs.k8s.io/kustomize/pkg/factory +sigs.k8s.io/kustomize/pkg/fs +sigs.k8s.io/kustomize/pkg/git +sigs.k8s.io/kustomize/pkg/gvk +sigs.k8s.io/kustomize/pkg/ifc +sigs.k8s.io/kustomize/pkg/ifc/transformer +sigs.k8s.io/kustomize/pkg/image +sigs.k8s.io/kustomize/pkg/internal/error +sigs.k8s.io/kustomize/pkg/loader +sigs.k8s.io/kustomize/pkg/patch +sigs.k8s.io/kustomize/pkg/patch/transformer +sigs.k8s.io/kustomize/pkg/resid +sigs.k8s.io/kustomize/pkg/resmap +sigs.k8s.io/kustomize/pkg/resource +sigs.k8s.io/kustomize/pkg/target +sigs.k8s.io/kustomize/pkg/transformers +sigs.k8s.io/kustomize/pkg/transformers/config +sigs.k8s.io/kustomize/pkg/transformers/config/defaultconfig +sigs.k8s.io/kustomize/pkg/types # sigs.k8s.io/structured-merge-diff/v3 v3.0.0 => sigs.k8s.io/structured-merge-diff/v3 v3.0.0 sigs.k8s.io/structured-merge-diff/v3/fieldpath sigs.k8s.io/structured-merge-diff/v3/merge