diff --git a/.github/workflows/dockerhub-latest-image.yml b/.github/workflows/dockerhub-latest-image.yml index 58b205281..9b496741a 100644 --- a/.github/workflows/dockerhub-latest-image.yml +++ b/.github/workflows/dockerhub-latest-image.yml @@ -21,6 +21,7 @@ jobs: - karmada-scheduler-estimator - karmada-interpreter-webhook-example - karmada-aggregated-apiserver + - karmada-search runs-on: ubuntu-18.04 steps: - name: checkout code diff --git a/.github/workflows/dockerhub-released-image.yml b/.github/workflows/dockerhub-released-image.yml index 8931263d4..7c17e911a 100644 --- a/.github/workflows/dockerhub-released-image.yml +++ b/.github/workflows/dockerhub-released-image.yml @@ -17,6 +17,7 @@ jobs: - karmada-scheduler-estimator - karmada-interpreter-webhook-example - karmada-aggregated-apiserver + - karmada-search runs-on: ubuntu-18.04 steps: - name: checkout code diff --git a/.gitignore b/.gitignore index a91416540..3e655372b 100644 --- a/.gitignore +++ b/.gitignore @@ -30,6 +30,7 @@ _output/ /karmada-scheduler-estimator /karmada-webhook /kubectl-karmada +/karmada-search # OSX trash .DS_Store diff --git a/Makefile b/Makefile index ee8c2b61c..6a346f366 100644 --- a/Makefile +++ b/Makefile @@ -28,7 +28,8 @@ TARGETS := karmada-aggregated-apiserver \ karmada-webhook \ karmada-agent \ karmada-scheduler-estimator \ - karmada-interpreter-webhook-example + karmada-interpreter-webhook-example \ + karmada-search CTL_TARGETS := karmadactl kubectl-karmada @@ -122,3 +123,4 @@ endif docker push ${REGISTRY}/karmada-scheduler-estimator:${VERSION} docker push ${REGISTRY}/karmada-interpreter-webhook-example:${VERSION} docker push ${REGISTRY}/karmada-aggregated-apiserver:${VERSION} + docker push ${REGISTRY}/karmada-search:${VERSION} diff --git a/artifacts/deploy/apiservice.yaml b/artifacts/deploy/karmada-aggregated-apiserver-apiservice.yaml similarity index 100% rename from artifacts/deploy/apiservice.yaml rename to artifacts/deploy/karmada-aggregated-apiserver-apiservice.yaml diff --git a/artifacts/deploy/karmada-search-apiservice.yaml b/artifacts/deploy/karmada-search-apiservice.yaml new file mode 100644 index 000000000..449a325b8 --- /dev/null +++ b/artifacts/deploy/karmada-search-apiservice.yaml @@ -0,0 +1,25 @@ +apiVersion: apiregistration.k8s.io/v1 +kind: APIService +metadata: + name: v1alpha1.search.karmada.io + labels: + app: karmada-search + apiserver: "true" +spec: + insecureSkipTLSVerify: true + group: search.karmada.io + groupPriorityMinimum: 2000 + service: + name: karmada-search + namespace: karmada-system + version: v1alpha1 + versionPriority: 10 +--- +apiVersion: v1 +kind: Service +metadata: + name: karmada-search + namespace: karmada-system +spec: + type: ExternalName + externalName: karmada-search.karmada-system.svc.cluster.local diff --git a/artifacts/deploy/karmada-search.yaml b/artifacts/deploy/karmada-search.yaml new file mode 100644 index 000000000..d2dc13f9c --- /dev/null +++ b/artifacts/deploy/karmada-search.yaml @@ -0,0 +1,74 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: karmada-search + namespace: karmada-system + labels: + app: karmada-search + apiserver: "true" +spec: + selector: + matchLabels: + app: karmada-search + apiserver: "true" + replicas: 2 + template: + metadata: + labels: + app: karmada-search + apiserver: "true" + spec: + automountServiceAccountToken: false + containers: + - name: karmada-search + image: swr.ap-southeast-1.myhuaweicloud.com/karmada/karmada-search:latest + imagePullPolicy: IfNotPresent + volumeMounts: + - name: k8s-certs + mountPath: /etc/kubernetes/pki + readOnly: true + - name: kubeconfig + subPath: kubeconfig + mountPath: /etc/kubeconfig + command: + - /bin/karmada-search + - --kubeconfig=/etc/kubeconfig + - --authentication-kubeconfig=/etc/kubeconfig + - --authorization-kubeconfig=/etc/kubeconfig + - --etcd-servers=https://etcd-client.karmada-system.svc.cluster.local:2379 + - --etcd-cafile=/etc/kubernetes/pki/server-ca.crt + - --etcd-certfile=/etc/kubernetes/pki/karmada.crt + - --etcd-keyfile=/etc/kubernetes/pki/karmada.key + - --tls-cert-file=/etc/kubernetes/pki/karmada.crt + - --tls-private-key-file=/etc/kubernetes/pki/karmada.key + - --audit-log-path=- + - --feature-gates=APIPriorityAndFairness=false + - --audit-log-maxage=0 + - --audit-log-maxbackup=0 + resources: + requests: + cpu: 100m + volumes: + - name: k8s-certs + secret: + secretName: karmada-cert-secret + - name: kubeconfig + secret: + secretName: kubeconfig +--- +apiVersion: v1 +kind: Service +metadata: + name: karmada-search + namespace: karmada-system + labels: + app: karmada-search + apiserver: "true" +spec: + ports: + - port: 443 + protocol: TCP + targetPort: 443 + selector: + app: karmada-search diff --git a/charts/_crds/bases/search.karmada.io_resourceregistries.yaml b/charts/_crds/bases/search.karmada.io_resourceregistries.yaml deleted file mode 100644 index b172773c0..000000000 --- a/charts/_crds/bases/search.karmada.io_resourceregistries.yaml +++ /dev/null @@ -1,253 +0,0 @@ ---- -apiVersion: apiextensions.k8s.io/v1 -kind: CustomResourceDefinition -metadata: - annotations: - controller-gen.kubebuilder.io/version: v0.8.0 - creationTimestamp: null - name: resourceregistries.search.karmada.io -spec: - group: search.karmada.io - names: - kind: ResourceRegistry - listKind: ResourceRegistryList - plural: resourceregistries - singular: resourceregistry - scope: Cluster - versions: - - name: v1alpha1 - schema: - openAPIV3Schema: - description: ResourceRegistry defines a list of member cluster to be cached. - 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: Spec represents the desired behavior of ResourceRegistry. - properties: - clusterSelectors: - description: ClusterSelectors represents the filter to select clusters. - items: - description: ClusterSelector represents the filter to select clusters. - properties: - clusterNames: - description: ClusterNames is the list of clusters to be selected. - items: - type: string - type: array - exclude: - description: ExcludedClusters is the list of clusters to be - ignored. - items: - type: string - type: array - fieldSelector: - description: FieldSelector is a filter to select member clusters - by fields. If non-nil and non-empty, only the clusters match - this filter will be selected. - properties: - matchExpressions: - description: A list of field selector requirements. - items: - description: A node selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. - properties: - key: - description: The label key that the selector applies - to. - type: string - operator: - description: Represents a key's relationship to a - set of values. Valid operators are In, NotIn, Exists, - DoesNotExist. Gt, and Lt. - type: string - values: - description: An array of string values. If the operator - is In or NotIn, the values array must be non-empty. - If the operator is Exists or DoesNotExist, the values - array must be empty. If the operator is Gt or Lt, - the values array must have a single element, which - will be interpreted as an integer. This array is - replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - type: object - labelSelector: - description: LabelSelector is a filter to select member clusters - by labels. If non-nil and non-empty, only the clusters match - this filter will be selected. - properties: - matchExpressions: - description: matchExpressions is a list of label selector - requirements. The requirements are ANDed. - items: - description: A label selector requirement is a selector - that contains values, a key, and an operator that relates - the key and values. - properties: - key: - description: key is the label key that the selector - applies to. - type: string - operator: - description: operator represents a key's relationship - to a set of values. Valid operators are In, NotIn, - Exists and DoesNotExist. - type: string - values: - description: values is an array of string values. - If the operator is In or NotIn, the values array - must be non-empty. If the operator is Exists or - DoesNotExist, the values array must be empty. This - array is replaced during a strategic merge patch. - items: - type: string - type: array - required: - - key - - operator - type: object - type: array - matchLabels: - additionalProperties: - type: string - description: matchLabels is a map of {key,value} pairs. - A single {key,value} in the matchLabels map is equivalent - to an element of matchExpressions, whose key field is - "key", the operator is "In", and the values array contains - only "value". The requirements are ANDed. - type: object - type: object - type: object - type: array - resourceSelectors: - description: ResourceSelectors used to select resources. - items: - description: ResourceSelector the resources will be selected. - properties: - apiVersion: - description: APIVersion represents the API version of the target - resources. - type: string - kind: - description: Kind represents the Kind of the target resources. - type: string - namespace: - description: Namespace of the target resource. Default is empty, - which means all namespaces. - type: string - required: - - apiVersion - - kind - type: object - type: array - statusUpdatePeriodSeconds: - description: StatusUpdatePeriodSeconds is the period to update the - status of the resource. default is 10s. - format: int32 - type: integer - required: - - clusterSelectors - - resourceSelectors - type: object - status: - description: Status represents the status of ResoruceRegistry. - properties: - conditions: - description: Conditions contain the different condition statuses. - items: - description: "Condition contains details for one aspect of the current - state of this API Resource. --- This struct is intended for direct - use as an array at the field path .status.conditions. For example, - type FooStatus struct{ // Represents the observations of a foo's - current state. // Known .status.conditions.type are: \"Available\", - \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge - // +listType=map // +listMapKey=type Conditions []metav1.Condition - `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" - protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" - properties: - lastTransitionTime: - description: lastTransitionTime is the last time the condition - transitioned from one status to another. This should be when - the underlying condition changed. If that is not known, then - using the time when the API field changed is acceptable. - format: date-time - type: string - message: - description: message is a human readable message indicating - details about the transition. This may be an empty string. - maxLength: 32768 - type: string - observedGeneration: - description: observedGeneration represents the .metadata.generation - that the condition was set based upon. For instance, if .metadata.generation - is currently 12, but the .status.conditions[x].observedGeneration - is 9, the condition is out of date with respect to the current - state of the instance. - format: int64 - minimum: 0 - type: integer - reason: - description: reason contains a programmatic identifier indicating - the reason for the condition's last transition. Producers - of specific condition types may define expected values and - meanings for this field, and whether the values are considered - a guaranteed API. The value should be a CamelCase string. - This field may not be empty. - maxLength: 1024 - minLength: 1 - pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ - type: string - status: - description: status of the condition, one of True, False, Unknown. - enum: - - "True" - - "False" - - Unknown - type: string - type: - description: type of condition in CamelCase or in foo.example.com/CamelCase. - --- Many .condition.type values are consistent across resources - like Available, but because arbitrary conditions can be useful - (see .node.status.conditions), the ability to deconflict is - important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) - maxLength: 316 - pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ - type: string - required: - - lastTransitionTime - - message - - reason - - status - - type - type: object - type: array - type: object - type: object - served: true - storage: true - subresources: - status: {} -status: - acceptedNames: - kind: "" - plural: "" - conditions: [] - storedVersions: [] diff --git a/charts/templates/pre-install-job.yaml b/charts/templates/pre-install-job.yaml index 70b784ba1..07da2d844 100644 --- a/charts/templates/pre-install-job.yaml +++ b/charts/templates/pre-install-job.yaml @@ -80,7 +80,7 @@ data: {{- include "karmada.webhook.configuration" . | nindent 8 }} {{- print "system-namespace.yaml: " | nindent 6 }} |- {{- include "karmada.systemNamespace" . | nindent 8 }} - {{- print "apiservice.yaml: " | nindent 6 }} |- + {{- print "karmada-aggregated-apiserver-apiservice.yaml: " | nindent 6 }} |- {{- include "karmada.apiservice" . | nindent 8 }} {{- print "cluster-proxy-admin-rbac.yaml: " | nindent 6 }} |- {{- include "karmada.proxyRbac" . | nindent 8 }} diff --git a/cmd/karmada-search/app/karmada-search.go b/cmd/karmada-search/app/karmada-search.go new file mode 100644 index 000000000..625a38fc2 --- /dev/null +++ b/cmd/karmada-search/app/karmada-search.go @@ -0,0 +1,54 @@ +package app + +import ( + "context" + "os" + + "github.com/spf13/cobra" + cliflag "k8s.io/component-base/cli/flag" + "k8s.io/component-base/term" + + "github.com/karmada-io/karmada/cmd/karmada-search/app/options" + "github.com/karmada-io/karmada/pkg/sharedcli" + "github.com/karmada-io/karmada/pkg/sharedcli/klogflag" + "github.com/karmada-io/karmada/pkg/version/sharedcommand" +) + +// NewKarmadaSearchCommand creates a *cobra.Command object with default parameters +func NewKarmadaSearchCommand(ctx context.Context) *cobra.Command { + opts := options.NewOptions() + + cmd := &cobra.Command{ + Use: "karmada-search", + Long: `Launch the karmada-search`, + RunE: func(cmd *cobra.Command, args []string) error { + if err := opts.Complete(); err != nil { + return err + } + if err := opts.Validate(); err != nil { + return err + } + if err := opts.Run(ctx); err != nil { + return err + } + return nil + }, + } + + fss := cliflag.NamedFlagSets{} + + genericFlagSet := fss.FlagSet("generic") + opts.AddFlags(genericFlagSet) + + // Set klog flags + logsFlagSet := fss.FlagSet("logs") + klogflag.Add(logsFlagSet) + + cmd.AddCommand(sharedcommand.NewCmdVersion(os.Stdout, "karmada-search")) + cmd.Flags().AddFlagSet(genericFlagSet) + cmd.Flags().AddFlagSet(logsFlagSet) + + cols, _, _ := term.TerminalSize(cmd.OutOrStdout()) + sharedcli.SetUsageAndHelpFunc(cmd, fss, cols) + return cmd +} diff --git a/cmd/karmada-search/app/options/options.go b/cmd/karmada-search/app/options/options.go new file mode 100644 index 000000000..5895acc6d --- /dev/null +++ b/cmd/karmada-search/app/options/options.go @@ -0,0 +1,115 @@ +package options + +import ( + "context" + "fmt" + "net" + + "github.com/spf13/pflag" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + utilerrors "k8s.io/apimachinery/pkg/util/errors" + "k8s.io/apiserver/pkg/endpoints/openapi" + "k8s.io/apiserver/pkg/features" + genericapiserver "k8s.io/apiserver/pkg/server" + genericoptions "k8s.io/apiserver/pkg/server/options" + utilfeature "k8s.io/apiserver/pkg/util/feature" + "k8s.io/client-go/kubernetes" + netutils "k8s.io/utils/net" + + searchv1alpha1 "github.com/karmada-io/karmada/pkg/apis/search/v1alpha1" + generatedopenapi "github.com/karmada-io/karmada/pkg/generated/openapi" + "github.com/karmada-io/karmada/pkg/search" +) + +const defaultEtcdPathPrefix = "/registry" + +// Options contains everything necessary to create and run karmada-search. +type Options struct { + RecommendedOptions *genericoptions.RecommendedOptions + + // KubeAPIQPS is the QPS to use while talking with karmada-search. + KubeAPIQPS float32 + // KubeAPIBurst is the burst to allow while talking with karmada-search. + KubeAPIBurst int +} + +// NewOptions returns a new Options. +func NewOptions() *Options { + o := &Options{ + RecommendedOptions: genericoptions.NewRecommendedOptions( + defaultEtcdPathPrefix, + search.Codecs.LegacyCodec(searchv1alpha1.SchemeGroupVersion)), + } + o.RecommendedOptions.Etcd.StorageConfig.EncodeVersioner = runtime.NewMultiGroupVersioner(searchv1alpha1.SchemeGroupVersion, + schema.GroupKind{Group: searchv1alpha1.GroupName}) + o.RecommendedOptions.Etcd.StorageConfig.Paging = utilfeature.DefaultFeatureGate.Enabled(features.APIListChunking) + return o +} + +// AddFlags adds flags to the specified FlagSet. +func (o *Options) AddFlags(flags *pflag.FlagSet) { + o.RecommendedOptions.AddFlags(flags) + flags.Lookup("kubeconfig").Usage = "Path to karmada control plane kubeconfig file." + + flags.Float32Var(&o.KubeAPIQPS, "kube-api-qps", 40.0, "QPS to use while talking with karmada-apiserver. Doesn't cover events and node heartbeat apis which rate limiting is controlled by a different set of flags.") + flags.IntVar(&o.KubeAPIBurst, "kube-api-burst", 60, "Burst to use while talking with karmada-apiserver. Doesn't cover events and node heartbeat apis which rate limiting is controlled by a different set of flags.") + utilfeature.DefaultMutableFeatureGate.AddFlag(flags) +} + +// Complete fills in fields required to have valid data. +func (o *Options) Complete() error { + return nil +} + +// Validate validates Options. +func (o *Options) Validate() error { + var errs []error + errs = append(errs, o.RecommendedOptions.Validate()...) + return utilerrors.NewAggregate(errs) +} + +// Run runs the aggregated-apiserver with options. This should never exit. +func (o *Options) Run(ctx context.Context) error { + config, err := o.Config() + if err != nil { + return err + } + + restConfig := config.GenericConfig.ClientConfig + restConfig.QPS, restConfig.Burst = o.KubeAPIQPS, o.KubeAPIBurst + kubeClientSet := kubernetes.NewForConfigOrDie(restConfig) + + server, err := config.Complete().New(kubeClientSet) + if err != nil { + return err + } + + server.GenericAPIServer.AddPostStartHookOrDie("start-karmada-search-informers", func(context genericapiserver.PostStartHookContext) error { + config.GenericConfig.SharedInformerFactory.Start(context.StopCh) + return nil + }) + + return server.GenericAPIServer.PrepareRun().Run(ctx.Done()) +} + +// Config returns config for the api server given Options +func (o *Options) Config() (*search.Config, error) { + // TODO have a "real" external address + if err := o.RecommendedOptions.SecureServing.MaybeDefaultWithSelfSignedCerts("localhost", nil, []net.IP{netutils.ParseIPSloppy("127.0.0.1")}); err != nil { + return nil, fmt.Errorf("error creating self-signed certificates: %v", err) + } + + serverConfig := genericapiserver.NewRecommendedConfig(search.Codecs) + serverConfig.OpenAPIConfig = genericapiserver.DefaultOpenAPIConfig(generatedopenapi.GetOpenAPIDefinitions, openapi.NewDefinitionNamer(search.Scheme)) + serverConfig.OpenAPIConfig.Info.Title = "karmada-search" + if err := o.RecommendedOptions.ApplyTo(serverConfig); err != nil { + return nil, err + } + + config := &search.Config{ + GenericConfig: serverConfig, + ExtraConfig: search.ExtraConfig{}, + } + return config, nil +} diff --git a/cmd/karmada-search/main.go b/cmd/karmada-search/main.go new file mode 100644 index 000000000..c796dd1f3 --- /dev/null +++ b/cmd/karmada-search/main.go @@ -0,0 +1,28 @@ +package main + +import ( + "os" + + apiserver "k8s.io/apiserver/pkg/server" + "k8s.io/component-base/logs" + + "github.com/karmada-io/karmada/cmd/karmada-search/app" +) + +func main() { + if err := runKarmadaSearchCmd(); err != nil { + os.Exit(1) + } +} + +func runKarmadaSearchCmd() error { + logs.InitLogs() + defer logs.FlushLogs() + + ctx := apiserver.SetupSignalContext() + if err := app.NewKarmadaSearchCommand(ctx).Execute(); err != nil { + return err + } + + return nil +} diff --git a/hack/deploy-karmada.sh b/hack/deploy-karmada.sh index 39bd141cd..de0b3a9e3 100755 --- a/hack/deploy-karmada.sh +++ b/hack/deploy-karmada.sh @@ -208,6 +208,9 @@ kubectl apply -f "${REPO_ROOT}/artifacts/deploy/kube-controller-manager.yaml" # deploy aggregated-apiserver on host cluster kubectl apply -f "${REPO_ROOT}/artifacts/deploy/karmada-aggregated-apiserver.yaml" util::wait_pod_ready "${KARMADA_AGGREGATION_APISERVER_LABEL}" "${KARMADA_SYSTEM_NAMESPACE}" +# deploy karmada-search on host cluster +kubectl apply -f "${REPO_ROOT}/artifacts/deploy/karmada-search.yaml" +util::wait_pod_ready "${KARMADA_SEARCH_LABEL}" "${KARMADA_SYSTEM_NAMESPACE}" # install CRD APIs on karmada apiserver. if ! kubectl config use-context karmada-apiserver > /dev/null 2>&1; @@ -228,10 +231,15 @@ rm -rf "${TEMP_PATH_CRDS}" util::deploy_webhook_configuration "${ROOT_CA_FILE}" "${REPO_ROOT}/artifacts/deploy/webhook-configuration.yaml" # deploy APIService on karmada apiserver for karmada-aggregated-apiserver -kubectl apply -f "${REPO_ROOT}/artifacts/deploy/apiservice.yaml" +kubectl apply -f "${REPO_ROOT}/artifacts/deploy/karmada-aggregated-apiserver-apiservice.yaml" # make sure apiservice for v1alpha1.cluster.karmada.io is Available util::wait_apiservice_ready "${KARMADA_AGGREGATION_APISERVER_LABEL}" +# deploy APIService on karmada apiserver for karmada-search +kubectl apply -f "${REPO_ROOT}/artifacts/deploy/karmada-search-apiservice.yaml" +# make sure apiservice for v1alpha1.search.karmada.io is Available +util::wait_apiservice_ready "${KARMADA_SEARCH_LABEL}" + # deploy cluster proxy rbac for admin kubectl apply -f "${REPO_ROOT}/artifacts/deploy/cluster-proxy-admin-rbac.yaml" diff --git a/hack/local-up-karmada.sh b/hack/local-up-karmada.sh index c9adf2a67..c8f35c5e8 100755 --- a/hack/local-up-karmada.sh +++ b/hack/local-up-karmada.sh @@ -124,6 +124,7 @@ kind load docker-image "${REGISTRY}/karmada-descheduler:${VERSION}" --name="${HO kind load docker-image "${REGISTRY}/karmada-webhook:${VERSION}" --name="${HOST_CLUSTER_NAME}" kind load docker-image "${REGISTRY}/karmada-scheduler-estimator:${VERSION}" --name="${HOST_CLUSTER_NAME}" kind load docker-image "${REGISTRY}/karmada-aggregated-apiserver:${VERSION}" --name="${HOST_CLUSTER_NAME}" +kind load docker-image "${REGISTRY}/karmada-search:${VERSION}" --name="${HOST_CLUSTER_NAME}" #step5. install karmada control plane components "${REPO_ROOT}"/hack/deploy-karmada.sh "${MAIN_KUBECONFIG}" "${HOST_CLUSTER_NAME}" diff --git a/hack/update-codegen.sh b/hack/update-codegen.sh index 82e3ff439..4a3ac813d 100755 --- a/hack/update-codegen.sh +++ b/hack/update-codegen.sh @@ -76,6 +76,11 @@ deepcopy-gen \ --input-dirs=github.com/karmada-io/karmada/pkg/apis/search/v1alpha1 \ --output-package=github.com/karmada-io/karmada/pkg/apis/search/v1alpha1 \ --output-file-base=zz_generated.deepcopy +deepcopy-gen \ + --go-header-file hack/boilerplate/boilerplate.go.txt \ + --input-dirs=github.com/karmada-io/karmada/pkg/apis/search \ + --output-package=github.com/karmada-io/karmada/pkg/apis/search \ + --output-file-base=zz_generated.deepcopy echo "Generating with register-gen" register-gen \ @@ -125,6 +130,11 @@ conversion-gen \ --input-dirs=github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1 \ --output-package=github.com/karmada-io/karmada/pkg/apis/cluster/v1alpha1 \ --output-file-base=zz_generated.conversion +conversion-gen \ + --go-header-file hack/boilerplate/boilerplate.go.txt \ + --input-dirs=github.com/karmada-io/karmada/pkg/apis/search/v1alpha1 \ + --output-package=github.com/karmada-io/karmada/pkg/apis/search/v1alpha1 \ + --output-file-base=zz_generated.conversion echo "Generating with client-gen" client-gen \ diff --git a/hack/update-crdgen.sh b/hack/update-crdgen.sh index 4effd32a7..f289aab44 100755 --- a/hack/update-crdgen.sh +++ b/hack/update-crdgen.sh @@ -18,4 +18,3 @@ controller-gen crd paths=./pkg/apis/policy/... output:crd:dir=./charts/_crds/bas controller-gen crd paths=./pkg/apis/work/... output:crd:dir=./charts/_crds/bases controller-gen crd paths=./pkg/apis/networking/... output:crd:dir=./charts/_crds/bases controller-gen crd paths=./examples/customresourceinterpreter/apis/... output:crd:dir=./examples/customresourceinterpreter/apis/ -controller-gen crd paths=./pkg/apis/search/... output:crd:dir=./charts/_crds/bases diff --git a/hack/util.sh b/hack/util.sh index b44d987f2..af74fa1a4 100755 --- a/hack/util.sh +++ b/hack/util.sh @@ -16,6 +16,7 @@ KARMADA_SCHEDULER_LABEL="karmada-scheduler" KARMADA_WEBHOOK_LABEL="karmada-webhook" AGENT_POD_LABEL="karmada-agent" INTERPRETER_WEBHOOK_EXAMPLE_LABEL="karmada-interpreter-webhook-example" +KARMADA_SEARCH_LABEL="karmada-search" KARMADA_GO_PACKAGE="github.com/karmada-io/karmada" @@ -32,6 +33,7 @@ KARMADA_TARGET_SOURCE=( karmada-agent=cmd/agent karmada-scheduler-estimator=cmd/scheduler-estimator karmada-interpreter-webhook-example=examples/customresourceinterpreter/webhook + karmada-search=cmd/karmada-search ) #https://textkool.com/en/ascii-art-generator?hl=default&vl=default&font=DOS%20Rebel&text=KARMADA diff --git a/pkg/apis/search/cache_types.go b/pkg/apis/search/cache_types.go new file mode 100644 index 000000000..36020ee86 --- /dev/null +++ b/pkg/apis/search/cache_types.go @@ -0,0 +1,107 @@ +package search + +import ( + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ResourceRegistry defines a list of member cluster to be cached. +type ResourceRegistry struct { + metav1.TypeMeta + metav1.ObjectMeta + + // Spec represents the desired behavior of ResourceRegistry. + Spec ResourceRegistrySpec + + // Status represents the status of ResoruceRegistry. + // +optional + Status ResourceRegistryStatus +} + +// ResourceRegistrySpec defines the desired state of ResourceRegistry. +type ResourceRegistrySpec struct { + // ClusterSelectors represents the filter to select clusters. + // +required + ClusterSelectors []ClusterSelector + + // ResourceSelectors used to select resources. + // +required + ResourceSelectors []ResourceSelector + + // StatusUpdatePeriodSeconds is the period to update the status of the resource. + // default is 10s. + // +optional + StatusUpdatePeriodSeconds uint32 +} + +// ClusterSelector represents the filter to select clusters. +type ClusterSelector struct { + // LabelSelector is a filter to select member clusters by labels. + // If non-nil and non-empty, only the clusters match this filter will be selected. + // +optional + LabelSelector *metav1.LabelSelector + + // FieldSelector is a filter to select member clusters by fields. + // If non-nil and non-empty, only the clusters match this filter will be selected. + // +optional + FieldSelector *FieldSelector + + // ClusterNames is the list of clusters to be selected. + // +optional + ClusterNames []string + + // ExcludedClusters is the list of clusters to be ignored. + // +optional + ExcludeClusters []string +} + +// FieldSelector is a field filter. +type FieldSelector struct { + // A list of field selector requirements. + MatchExpressions []corev1.NodeSelectorRequirement +} + +// ResourceSelector the resources will be selected. +type ResourceSelector struct { + // APIVersion represents the API version of the target resources. + // +required + APIVersion string + + // Kind represents the Kind of the target resources. + // +required + Kind string + + // Namespace of the target resource. + // Default is empty, which means all namespaces. + // +optional + Namespace string +} + +// ResourceRegistryStatus defines the observed state of ResourceRegistry +type ResourceRegistryStatus struct { + // Conditions contain the different condition statuses. + // +optional + Conditions []metav1.Condition +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// ResourceRegistryList if a collection of ResourceRegistry. +type ResourceRegistryList struct { + metav1.TypeMeta + metav1.ListMeta + + // Items holds a list of ResourceRegistry. + Items []ResourceRegistry +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Search define a flag for resource search that do not have actual resources. +type Search struct { + metav1.TypeMeta +} diff --git a/pkg/apis/search/doc.go b/pkg/apis/search/doc.go new file mode 100644 index 000000000..9c240b498 --- /dev/null +++ b/pkg/apis/search/doc.go @@ -0,0 +1,4 @@ +// Package search is the internal version of the API. +// +k8s:deepcopy-gen=package +// +groupName=search.karmada.io +package search diff --git a/pkg/apis/search/install/install.go b/pkg/apis/search/install/install.go new file mode 100644 index 000000000..5fe81ad0b --- /dev/null +++ b/pkg/apis/search/install/install.go @@ -0,0 +1,16 @@ +package install + +import ( + "k8s.io/apimachinery/pkg/runtime" + utilruntime "k8s.io/apimachinery/pkg/util/runtime" + + "github.com/karmada-io/karmada/pkg/apis/search" + searchv1alpha1 "github.com/karmada-io/karmada/pkg/apis/search/v1alpha1" +) + +// Install registers the API group and adds types to a scheme. +func Install(scheme *runtime.Scheme) { + utilruntime.Must(search.AddToScheme(scheme)) + utilruntime.Must(searchv1alpha1.AddToScheme(scheme)) + utilruntime.Must(scheme.SetVersionPriority(searchv1alpha1.SchemeGroupVersion)) +} diff --git a/pkg/apis/search/register.go b/pkg/apis/search/register.go new file mode 100644 index 000000000..aab33702e --- /dev/null +++ b/pkg/apis/search/register.go @@ -0,0 +1,39 @@ +package search + +import ( + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName specifies the group name used to register the objects. +const GroupName = "search.karmada.io" + +// SchemeGroupVersion is group version used to register these objects +var SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: runtime.APIVersionInternal} + +// Resource takes an unqualified resource and returns a Group qualified GroupResource +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +// Kind takes an unqualified kind and returns a Group qualified GroupKind +func Kind(kind string) schema.GroupKind { + return SchemeGroupVersion.WithKind(kind).GroupKind() +} + +var ( + // SchemeBuilder is the scheme builder with scheme init functions to run for this API package + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme is a common registration function for mapping packaged scoped group & version keys to a scheme + AddToScheme = SchemeBuilder.AddToScheme +) + +// Adds the list of known types to Scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &ResourceRegistry{}, + &ResourceRegistryList{}, + &Search{}, + ) + return nil +} diff --git a/pkg/apis/search/v1alpha1/cache_types.go b/pkg/apis/search/v1alpha1/cache_types.go index b0c031c88..2524a6e8a 100644 --- a/pkg/apis/search/v1alpha1/cache_types.go +++ b/pkg/apis/search/v1alpha1/cache_types.go @@ -17,9 +17,8 @@ const ( ) // +genclient +// +genclient:nonNamespaced // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object -// +kubebuilder:subresource:status -// +kubebuilder:resource:scope="Cluster" // ResourceRegistry defines a list of member cluster to be cached. type ResourceRegistry struct { @@ -111,3 +110,10 @@ type ResourceRegistryList struct { // Items holds a list of ResourceRegistry. Items []ResourceRegistry `json:"items"` } + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// Search define a flag for resource search that do not have actual resources. +type Search struct { + metav1.TypeMeta `json:",inline"` +} diff --git a/pkg/apis/search/v1alpha1/doc.go b/pkg/apis/search/v1alpha1/doc.go index 2fbfcbcec..61a573b8e 100644 --- a/pkg/apis/search/v1alpha1/doc.go +++ b/pkg/apis/search/v1alpha1/doc.go @@ -1,5 +1,6 @@ // Package v1alpha1 is the v1alpha1 version of the API. // +k8s:deepcopy-gen=package,register // +k8s:openapi-gen=true +// +k8s:conversion-gen=github.com/karmada-io/karmada/pkg/apis/search // +groupName=search.karmada.io package v1alpha1 diff --git a/pkg/apis/search/v1alpha1/zz_generated.conversion.go b/pkg/apis/search/v1alpha1/zz_generated.conversion.go new file mode 100644 index 000000000..c8eed11f9 --- /dev/null +++ b/pkg/apis/search/v1alpha1/zz_generated.conversion.go @@ -0,0 +1,292 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Code generated by conversion-gen. DO NOT EDIT. + +package v1alpha1 + +import ( + unsafe "unsafe" + + search "github.com/karmada-io/karmada/pkg/apis/search" + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + conversion "k8s.io/apimachinery/pkg/conversion" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +func init() { + localSchemeBuilder.Register(RegisterConversions) +} + +// RegisterConversions adds conversion functions to the given scheme. +// Public to allow building arbitrary schemes. +func RegisterConversions(s *runtime.Scheme) error { + if err := s.AddGeneratedConversionFunc((*ClusterSelector)(nil), (*search.ClusterSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ClusterSelector_To_search_ClusterSelector(a.(*ClusterSelector), b.(*search.ClusterSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*search.ClusterSelector)(nil), (*ClusterSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_search_ClusterSelector_To_v1alpha1_ClusterSelector(a.(*search.ClusterSelector), b.(*ClusterSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*FieldSelector)(nil), (*search.FieldSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_FieldSelector_To_search_FieldSelector(a.(*FieldSelector), b.(*search.FieldSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*search.FieldSelector)(nil), (*FieldSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_search_FieldSelector_To_v1alpha1_FieldSelector(a.(*search.FieldSelector), b.(*FieldSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*ResourceRegistry)(nil), (*search.ResourceRegistry)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ResourceRegistry_To_search_ResourceRegistry(a.(*ResourceRegistry), b.(*search.ResourceRegistry), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*search.ResourceRegistry)(nil), (*ResourceRegistry)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_search_ResourceRegistry_To_v1alpha1_ResourceRegistry(a.(*search.ResourceRegistry), b.(*ResourceRegistry), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*ResourceRegistryList)(nil), (*search.ResourceRegistryList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ResourceRegistryList_To_search_ResourceRegistryList(a.(*ResourceRegistryList), b.(*search.ResourceRegistryList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*search.ResourceRegistryList)(nil), (*ResourceRegistryList)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_search_ResourceRegistryList_To_v1alpha1_ResourceRegistryList(a.(*search.ResourceRegistryList), b.(*ResourceRegistryList), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*ResourceRegistrySpec)(nil), (*search.ResourceRegistrySpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ResourceRegistrySpec_To_search_ResourceRegistrySpec(a.(*ResourceRegistrySpec), b.(*search.ResourceRegistrySpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*search.ResourceRegistrySpec)(nil), (*ResourceRegistrySpec)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_search_ResourceRegistrySpec_To_v1alpha1_ResourceRegistrySpec(a.(*search.ResourceRegistrySpec), b.(*ResourceRegistrySpec), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*ResourceRegistryStatus)(nil), (*search.ResourceRegistryStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ResourceRegistryStatus_To_search_ResourceRegistryStatus(a.(*ResourceRegistryStatus), b.(*search.ResourceRegistryStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*search.ResourceRegistryStatus)(nil), (*ResourceRegistryStatus)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_search_ResourceRegistryStatus_To_v1alpha1_ResourceRegistryStatus(a.(*search.ResourceRegistryStatus), b.(*ResourceRegistryStatus), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*ResourceSelector)(nil), (*search.ResourceSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_ResourceSelector_To_search_ResourceSelector(a.(*ResourceSelector), b.(*search.ResourceSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*search.ResourceSelector)(nil), (*ResourceSelector)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_search_ResourceSelector_To_v1alpha1_ResourceSelector(a.(*search.ResourceSelector), b.(*ResourceSelector), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*Search)(nil), (*search.Search)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_v1alpha1_Search_To_search_Search(a.(*Search), b.(*search.Search), scope) + }); err != nil { + return err + } + if err := s.AddGeneratedConversionFunc((*search.Search)(nil), (*Search)(nil), func(a, b interface{}, scope conversion.Scope) error { + return Convert_search_Search_To_v1alpha1_Search(a.(*search.Search), b.(*Search), scope) + }); err != nil { + return err + } + return nil +} + +func autoConvert_v1alpha1_ClusterSelector_To_search_ClusterSelector(in *ClusterSelector, out *search.ClusterSelector, s conversion.Scope) error { + out.LabelSelector = (*v1.LabelSelector)(unsafe.Pointer(in.LabelSelector)) + out.FieldSelector = (*search.FieldSelector)(unsafe.Pointer(in.FieldSelector)) + out.ClusterNames = *(*[]string)(unsafe.Pointer(&in.ClusterNames)) + out.ExcludeClusters = *(*[]string)(unsafe.Pointer(&in.ExcludeClusters)) + return nil +} + +// Convert_v1alpha1_ClusterSelector_To_search_ClusterSelector is an autogenerated conversion function. +func Convert_v1alpha1_ClusterSelector_To_search_ClusterSelector(in *ClusterSelector, out *search.ClusterSelector, s conversion.Scope) error { + return autoConvert_v1alpha1_ClusterSelector_To_search_ClusterSelector(in, out, s) +} + +func autoConvert_search_ClusterSelector_To_v1alpha1_ClusterSelector(in *search.ClusterSelector, out *ClusterSelector, s conversion.Scope) error { + out.LabelSelector = (*v1.LabelSelector)(unsafe.Pointer(in.LabelSelector)) + out.FieldSelector = (*FieldSelector)(unsafe.Pointer(in.FieldSelector)) + out.ClusterNames = *(*[]string)(unsafe.Pointer(&in.ClusterNames)) + out.ExcludeClusters = *(*[]string)(unsafe.Pointer(&in.ExcludeClusters)) + return nil +} + +// Convert_search_ClusterSelector_To_v1alpha1_ClusterSelector is an autogenerated conversion function. +func Convert_search_ClusterSelector_To_v1alpha1_ClusterSelector(in *search.ClusterSelector, out *ClusterSelector, s conversion.Scope) error { + return autoConvert_search_ClusterSelector_To_v1alpha1_ClusterSelector(in, out, s) +} + +func autoConvert_v1alpha1_FieldSelector_To_search_FieldSelector(in *FieldSelector, out *search.FieldSelector, s conversion.Scope) error { + out.MatchExpressions = *(*[]corev1.NodeSelectorRequirement)(unsafe.Pointer(&in.MatchExpressions)) + return nil +} + +// Convert_v1alpha1_FieldSelector_To_search_FieldSelector is an autogenerated conversion function. +func Convert_v1alpha1_FieldSelector_To_search_FieldSelector(in *FieldSelector, out *search.FieldSelector, s conversion.Scope) error { + return autoConvert_v1alpha1_FieldSelector_To_search_FieldSelector(in, out, s) +} + +func autoConvert_search_FieldSelector_To_v1alpha1_FieldSelector(in *search.FieldSelector, out *FieldSelector, s conversion.Scope) error { + out.MatchExpressions = *(*[]corev1.NodeSelectorRequirement)(unsafe.Pointer(&in.MatchExpressions)) + return nil +} + +// Convert_search_FieldSelector_To_v1alpha1_FieldSelector is an autogenerated conversion function. +func Convert_search_FieldSelector_To_v1alpha1_FieldSelector(in *search.FieldSelector, out *FieldSelector, s conversion.Scope) error { + return autoConvert_search_FieldSelector_To_v1alpha1_FieldSelector(in, out, s) +} + +func autoConvert_v1alpha1_ResourceRegistry_To_search_ResourceRegistry(in *ResourceRegistry, out *search.ResourceRegistry, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_v1alpha1_ResourceRegistrySpec_To_search_ResourceRegistrySpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_v1alpha1_ResourceRegistryStatus_To_search_ResourceRegistryStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_v1alpha1_ResourceRegistry_To_search_ResourceRegistry is an autogenerated conversion function. +func Convert_v1alpha1_ResourceRegistry_To_search_ResourceRegistry(in *ResourceRegistry, out *search.ResourceRegistry, s conversion.Scope) error { + return autoConvert_v1alpha1_ResourceRegistry_To_search_ResourceRegistry(in, out, s) +} + +func autoConvert_search_ResourceRegistry_To_v1alpha1_ResourceRegistry(in *search.ResourceRegistry, out *ResourceRegistry, s conversion.Scope) error { + out.ObjectMeta = in.ObjectMeta + if err := Convert_search_ResourceRegistrySpec_To_v1alpha1_ResourceRegistrySpec(&in.Spec, &out.Spec, s); err != nil { + return err + } + if err := Convert_search_ResourceRegistryStatus_To_v1alpha1_ResourceRegistryStatus(&in.Status, &out.Status, s); err != nil { + return err + } + return nil +} + +// Convert_search_ResourceRegistry_To_v1alpha1_ResourceRegistry is an autogenerated conversion function. +func Convert_search_ResourceRegistry_To_v1alpha1_ResourceRegistry(in *search.ResourceRegistry, out *ResourceRegistry, s conversion.Scope) error { + return autoConvert_search_ResourceRegistry_To_v1alpha1_ResourceRegistry(in, out, s) +} + +func autoConvert_v1alpha1_ResourceRegistryList_To_search_ResourceRegistryList(in *ResourceRegistryList, out *search.ResourceRegistryList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]search.ResourceRegistry)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_v1alpha1_ResourceRegistryList_To_search_ResourceRegistryList is an autogenerated conversion function. +func Convert_v1alpha1_ResourceRegistryList_To_search_ResourceRegistryList(in *ResourceRegistryList, out *search.ResourceRegistryList, s conversion.Scope) error { + return autoConvert_v1alpha1_ResourceRegistryList_To_search_ResourceRegistryList(in, out, s) +} + +func autoConvert_search_ResourceRegistryList_To_v1alpha1_ResourceRegistryList(in *search.ResourceRegistryList, out *ResourceRegistryList, s conversion.Scope) error { + out.ListMeta = in.ListMeta + out.Items = *(*[]ResourceRegistry)(unsafe.Pointer(&in.Items)) + return nil +} + +// Convert_search_ResourceRegistryList_To_v1alpha1_ResourceRegistryList is an autogenerated conversion function. +func Convert_search_ResourceRegistryList_To_v1alpha1_ResourceRegistryList(in *search.ResourceRegistryList, out *ResourceRegistryList, s conversion.Scope) error { + return autoConvert_search_ResourceRegistryList_To_v1alpha1_ResourceRegistryList(in, out, s) +} + +func autoConvert_v1alpha1_ResourceRegistrySpec_To_search_ResourceRegistrySpec(in *ResourceRegistrySpec, out *search.ResourceRegistrySpec, s conversion.Scope) error { + out.ClusterSelectors = *(*[]search.ClusterSelector)(unsafe.Pointer(&in.ClusterSelectors)) + out.ResourceSelectors = *(*[]search.ResourceSelector)(unsafe.Pointer(&in.ResourceSelectors)) + out.StatusUpdatePeriodSeconds = in.StatusUpdatePeriodSeconds + return nil +} + +// Convert_v1alpha1_ResourceRegistrySpec_To_search_ResourceRegistrySpec is an autogenerated conversion function. +func Convert_v1alpha1_ResourceRegistrySpec_To_search_ResourceRegistrySpec(in *ResourceRegistrySpec, out *search.ResourceRegistrySpec, s conversion.Scope) error { + return autoConvert_v1alpha1_ResourceRegistrySpec_To_search_ResourceRegistrySpec(in, out, s) +} + +func autoConvert_search_ResourceRegistrySpec_To_v1alpha1_ResourceRegistrySpec(in *search.ResourceRegistrySpec, out *ResourceRegistrySpec, s conversion.Scope) error { + out.ClusterSelectors = *(*[]ClusterSelector)(unsafe.Pointer(&in.ClusterSelectors)) + out.ResourceSelectors = *(*[]ResourceSelector)(unsafe.Pointer(&in.ResourceSelectors)) + out.StatusUpdatePeriodSeconds = in.StatusUpdatePeriodSeconds + return nil +} + +// Convert_search_ResourceRegistrySpec_To_v1alpha1_ResourceRegistrySpec is an autogenerated conversion function. +func Convert_search_ResourceRegistrySpec_To_v1alpha1_ResourceRegistrySpec(in *search.ResourceRegistrySpec, out *ResourceRegistrySpec, s conversion.Scope) error { + return autoConvert_search_ResourceRegistrySpec_To_v1alpha1_ResourceRegistrySpec(in, out, s) +} + +func autoConvert_v1alpha1_ResourceRegistryStatus_To_search_ResourceRegistryStatus(in *ResourceRegistryStatus, out *search.ResourceRegistryStatus, s conversion.Scope) error { + out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_v1alpha1_ResourceRegistryStatus_To_search_ResourceRegistryStatus is an autogenerated conversion function. +func Convert_v1alpha1_ResourceRegistryStatus_To_search_ResourceRegistryStatus(in *ResourceRegistryStatus, out *search.ResourceRegistryStatus, s conversion.Scope) error { + return autoConvert_v1alpha1_ResourceRegistryStatus_To_search_ResourceRegistryStatus(in, out, s) +} + +func autoConvert_search_ResourceRegistryStatus_To_v1alpha1_ResourceRegistryStatus(in *search.ResourceRegistryStatus, out *ResourceRegistryStatus, s conversion.Scope) error { + out.Conditions = *(*[]v1.Condition)(unsafe.Pointer(&in.Conditions)) + return nil +} + +// Convert_search_ResourceRegistryStatus_To_v1alpha1_ResourceRegistryStatus is an autogenerated conversion function. +func Convert_search_ResourceRegistryStatus_To_v1alpha1_ResourceRegistryStatus(in *search.ResourceRegistryStatus, out *ResourceRegistryStatus, s conversion.Scope) error { + return autoConvert_search_ResourceRegistryStatus_To_v1alpha1_ResourceRegistryStatus(in, out, s) +} + +func autoConvert_v1alpha1_ResourceSelector_To_search_ResourceSelector(in *ResourceSelector, out *search.ResourceSelector, s conversion.Scope) error { + out.APIVersion = in.APIVersion + out.Kind = in.Kind + out.Namespace = in.Namespace + return nil +} + +// Convert_v1alpha1_ResourceSelector_To_search_ResourceSelector is an autogenerated conversion function. +func Convert_v1alpha1_ResourceSelector_To_search_ResourceSelector(in *ResourceSelector, out *search.ResourceSelector, s conversion.Scope) error { + return autoConvert_v1alpha1_ResourceSelector_To_search_ResourceSelector(in, out, s) +} + +func autoConvert_search_ResourceSelector_To_v1alpha1_ResourceSelector(in *search.ResourceSelector, out *ResourceSelector, s conversion.Scope) error { + out.APIVersion = in.APIVersion + out.Kind = in.Kind + out.Namespace = in.Namespace + return nil +} + +// Convert_search_ResourceSelector_To_v1alpha1_ResourceSelector is an autogenerated conversion function. +func Convert_search_ResourceSelector_To_v1alpha1_ResourceSelector(in *search.ResourceSelector, out *ResourceSelector, s conversion.Scope) error { + return autoConvert_search_ResourceSelector_To_v1alpha1_ResourceSelector(in, out, s) +} + +func autoConvert_v1alpha1_Search_To_search_Search(in *Search, out *search.Search, s conversion.Scope) error { + return nil +} + +// Convert_v1alpha1_Search_To_search_Search is an autogenerated conversion function. +func Convert_v1alpha1_Search_To_search_Search(in *Search, out *search.Search, s conversion.Scope) error { + return autoConvert_v1alpha1_Search_To_search_Search(in, out, s) +} + +func autoConvert_search_Search_To_v1alpha1_Search(in *search.Search, out *Search, s conversion.Scope) error { + return nil +} + +// Convert_search_Search_To_v1alpha1_Search is an autogenerated conversion function. +func Convert_search_Search_To_v1alpha1_Search(in *search.Search, out *Search, s conversion.Scope) error { + return autoConvert_search_Search_To_v1alpha1_Search(in, out, s) +} diff --git a/pkg/apis/search/v1alpha1/zz_generated.deepcopy.go b/pkg/apis/search/v1alpha1/zz_generated.deepcopy.go index 8e56b7df1..5dcf308d0 100644 --- a/pkg/apis/search/v1alpha1/zz_generated.deepcopy.go +++ b/pkg/apis/search/v1alpha1/zz_generated.deepcopy.go @@ -197,3 +197,28 @@ func (in *ResourceSelector) DeepCopy() *ResourceSelector { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Search) DeepCopyInto(out *Search) { + *out = *in + out.TypeMeta = in.TypeMeta + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Search. +func (in *Search) DeepCopy() *Search { + if in == nil { + return nil + } + out := new(Search) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Search) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/pkg/apis/search/v1alpha1/zz_generated.register.go b/pkg/apis/search/v1alpha1/zz_generated.register.go index 8066f49f5..70eb13117 100644 --- a/pkg/apis/search/v1alpha1/zz_generated.register.go +++ b/pkg/apis/search/v1alpha1/zz_generated.register.go @@ -44,6 +44,7 @@ func addKnownTypes(scheme *runtime.Scheme) error { scheme.AddKnownTypes(SchemeGroupVersion, &ResourceRegistry{}, &ResourceRegistryList{}, + &Search{}, ) // AddToGroupVersion allows the serialization of client types like ListOptions. v1.AddToGroupVersion(scheme, SchemeGroupVersion) diff --git a/pkg/apis/search/zz_generated.deepcopy.go b/pkg/apis/search/zz_generated.deepcopy.go new file mode 100644 index 000000000..f341490b0 --- /dev/null +++ b/pkg/apis/search/zz_generated.deepcopy.go @@ -0,0 +1,224 @@ +//go:build !ignore_autogenerated +// +build !ignore_autogenerated + +// Code generated by deepcopy-gen. DO NOT EDIT. + +package search + +import ( + corev1 "k8s.io/api/core/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + 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 *ClusterSelector) DeepCopyInto(out *ClusterSelector) { + *out = *in + if in.LabelSelector != nil { + in, out := &in.LabelSelector, &out.LabelSelector + *out = new(v1.LabelSelector) + (*in).DeepCopyInto(*out) + } + if in.FieldSelector != nil { + in, out := &in.FieldSelector, &out.FieldSelector + *out = new(FieldSelector) + (*in).DeepCopyInto(*out) + } + if in.ClusterNames != nil { + in, out := &in.ClusterNames, &out.ClusterNames + *out = make([]string, len(*in)) + copy(*out, *in) + } + if in.ExcludeClusters != nil { + in, out := &in.ExcludeClusters, &out.ExcludeClusters + *out = make([]string, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ClusterSelector. +func (in *ClusterSelector) DeepCopy() *ClusterSelector { + if in == nil { + return nil + } + out := new(ClusterSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *FieldSelector) DeepCopyInto(out *FieldSelector) { + *out = *in + if in.MatchExpressions != nil { + in, out := &in.MatchExpressions, &out.MatchExpressions + *out = make([]corev1.NodeSelectorRequirement, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new FieldSelector. +func (in *FieldSelector) DeepCopy() *FieldSelector { + if in == nil { + return nil + } + out := new(FieldSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceRegistry) DeepCopyInto(out *ResourceRegistry) { + *out = *in + out.TypeMeta = in.TypeMeta + 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 ResourceRegistry. +func (in *ResourceRegistry) DeepCopy() *ResourceRegistry { + if in == nil { + return nil + } + out := new(ResourceRegistry) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ResourceRegistry) 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 *ResourceRegistryList) DeepCopyInto(out *ResourceRegistryList) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ListMeta.DeepCopyInto(&out.ListMeta) + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]ResourceRegistry, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceRegistryList. +func (in *ResourceRegistryList) DeepCopy() *ResourceRegistryList { + if in == nil { + return nil + } + out := new(ResourceRegistryList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *ResourceRegistryList) 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 *ResourceRegistrySpec) DeepCopyInto(out *ResourceRegistrySpec) { + *out = *in + if in.ClusterSelectors != nil { + in, out := &in.ClusterSelectors, &out.ClusterSelectors + *out = make([]ClusterSelector, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + if in.ResourceSelectors != nil { + in, out := &in.ResourceSelectors, &out.ResourceSelectors + *out = make([]ResourceSelector, len(*in)) + copy(*out, *in) + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceRegistrySpec. +func (in *ResourceRegistrySpec) DeepCopy() *ResourceRegistrySpec { + if in == nil { + return nil + } + out := new(ResourceRegistrySpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceRegistryStatus) DeepCopyInto(out *ResourceRegistryStatus) { + *out = *in + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]v1.Condition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceRegistryStatus. +func (in *ResourceRegistryStatus) DeepCopy() *ResourceRegistryStatus { + if in == nil { + return nil + } + out := new(ResourceRegistryStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ResourceSelector) DeepCopyInto(out *ResourceSelector) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceSelector. +func (in *ResourceSelector) DeepCopy() *ResourceSelector { + if in == nil { + return nil + } + out := new(ResourceSelector) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *Search) DeepCopyInto(out *Search) { + *out = *in + out.TypeMeta = in.TypeMeta + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new Search. +func (in *Search) DeepCopy() *Search { + if in == nil { + return nil + } + out := new(Search) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *Search) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} diff --git a/pkg/generated/clientset/versioned/typed/search/v1alpha1/fake/fake_resourceregistry.go b/pkg/generated/clientset/versioned/typed/search/v1alpha1/fake/fake_resourceregistry.go index a21f38962..28829ece2 100644 --- a/pkg/generated/clientset/versioned/typed/search/v1alpha1/fake/fake_resourceregistry.go +++ b/pkg/generated/clientset/versioned/typed/search/v1alpha1/fake/fake_resourceregistry.go @@ -17,7 +17,6 @@ import ( // FakeResourceRegistries implements ResourceRegistryInterface type FakeResourceRegistries struct { Fake *FakeSearchV1alpha1 - ns string } var resourceregistriesResource = schema.GroupVersionResource{Group: "search.karmada.io", Version: "v1alpha1", Resource: "resourceregistries"} @@ -27,8 +26,7 @@ var resourceregistriesKind = schema.GroupVersionKind{Group: "search.karmada.io", // Get takes name of the resourceRegistry, and returns the corresponding resourceRegistry object, and an error if there is any. func (c *FakeResourceRegistries) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ResourceRegistry, err error) { obj, err := c.Fake. - Invokes(testing.NewGetAction(resourceregistriesResource, c.ns, name), &v1alpha1.ResourceRegistry{}) - + Invokes(testing.NewRootGetAction(resourceregistriesResource, name), &v1alpha1.ResourceRegistry{}) if obj == nil { return nil, err } @@ -38,8 +36,7 @@ func (c *FakeResourceRegistries) Get(ctx context.Context, name string, options v // List takes label and field selectors, and returns the list of ResourceRegistries that match those selectors. func (c *FakeResourceRegistries) List(ctx context.Context, opts v1.ListOptions) (result *v1alpha1.ResourceRegistryList, err error) { obj, err := c.Fake. - Invokes(testing.NewListAction(resourceregistriesResource, resourceregistriesKind, c.ns, opts), &v1alpha1.ResourceRegistryList{}) - + Invokes(testing.NewRootListAction(resourceregistriesResource, resourceregistriesKind, opts), &v1alpha1.ResourceRegistryList{}) if obj == nil { return nil, err } @@ -60,15 +57,13 @@ func (c *FakeResourceRegistries) List(ctx context.Context, opts v1.ListOptions) // Watch returns a watch.Interface that watches the requested resourceRegistries. func (c *FakeResourceRegistries) Watch(ctx context.Context, opts v1.ListOptions) (watch.Interface, error) { return c.Fake. - InvokesWatch(testing.NewWatchAction(resourceregistriesResource, c.ns, opts)) - + InvokesWatch(testing.NewRootWatchAction(resourceregistriesResource, opts)) } // Create takes the representation of a resourceRegistry and creates it. Returns the server's representation of the resourceRegistry, and an error, if there is any. func (c *FakeResourceRegistries) Create(ctx context.Context, resourceRegistry *v1alpha1.ResourceRegistry, opts v1.CreateOptions) (result *v1alpha1.ResourceRegistry, err error) { obj, err := c.Fake. - Invokes(testing.NewCreateAction(resourceregistriesResource, c.ns, resourceRegistry), &v1alpha1.ResourceRegistry{}) - + Invokes(testing.NewRootCreateAction(resourceregistriesResource, resourceRegistry), &v1alpha1.ResourceRegistry{}) if obj == nil { return nil, err } @@ -78,8 +73,7 @@ func (c *FakeResourceRegistries) Create(ctx context.Context, resourceRegistry *v // Update takes the representation of a resourceRegistry and updates it. Returns the server's representation of the resourceRegistry, and an error, if there is any. func (c *FakeResourceRegistries) Update(ctx context.Context, resourceRegistry *v1alpha1.ResourceRegistry, opts v1.UpdateOptions) (result *v1alpha1.ResourceRegistry, err error) { obj, err := c.Fake. - Invokes(testing.NewUpdateAction(resourceregistriesResource, c.ns, resourceRegistry), &v1alpha1.ResourceRegistry{}) - + Invokes(testing.NewRootUpdateAction(resourceregistriesResource, resourceRegistry), &v1alpha1.ResourceRegistry{}) if obj == nil { return nil, err } @@ -90,8 +84,7 @@ func (c *FakeResourceRegistries) Update(ctx context.Context, resourceRegistry *v // Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). func (c *FakeResourceRegistries) UpdateStatus(ctx context.Context, resourceRegistry *v1alpha1.ResourceRegistry, opts v1.UpdateOptions) (*v1alpha1.ResourceRegistry, error) { obj, err := c.Fake. - Invokes(testing.NewUpdateSubresourceAction(resourceregistriesResource, "status", c.ns, resourceRegistry), &v1alpha1.ResourceRegistry{}) - + Invokes(testing.NewRootUpdateSubresourceAction(resourceregistriesResource, "status", resourceRegistry), &v1alpha1.ResourceRegistry{}) if obj == nil { return nil, err } @@ -101,14 +94,13 @@ func (c *FakeResourceRegistries) UpdateStatus(ctx context.Context, resourceRegis // Delete takes name of the resourceRegistry and deletes it. Returns an error if one occurs. func (c *FakeResourceRegistries) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { _, err := c.Fake. - Invokes(testing.NewDeleteActionWithOptions(resourceregistriesResource, c.ns, name, opts), &v1alpha1.ResourceRegistry{}) - + Invokes(testing.NewRootDeleteActionWithOptions(resourceregistriesResource, name, opts), &v1alpha1.ResourceRegistry{}) return err } // DeleteCollection deletes a collection of objects. func (c *FakeResourceRegistries) DeleteCollection(ctx context.Context, opts v1.DeleteOptions, listOpts v1.ListOptions) error { - action := testing.NewDeleteCollectionAction(resourceregistriesResource, c.ns, listOpts) + action := testing.NewRootDeleteCollectionAction(resourceregistriesResource, listOpts) _, err := c.Fake.Invokes(action, &v1alpha1.ResourceRegistryList{}) return err @@ -117,8 +109,7 @@ func (c *FakeResourceRegistries) DeleteCollection(ctx context.Context, opts v1.D // Patch applies the patch and returns the patched resourceRegistry. func (c *FakeResourceRegistries) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ResourceRegistry, err error) { obj, err := c.Fake. - Invokes(testing.NewPatchSubresourceAction(resourceregistriesResource, c.ns, name, pt, data, subresources...), &v1alpha1.ResourceRegistry{}) - + Invokes(testing.NewRootPatchSubresourceAction(resourceregistriesResource, name, pt, data, subresources...), &v1alpha1.ResourceRegistry{}) if obj == nil { return nil, err } diff --git a/pkg/generated/clientset/versioned/typed/search/v1alpha1/fake/fake_search_client.go b/pkg/generated/clientset/versioned/typed/search/v1alpha1/fake/fake_search_client.go index 35b28b78f..99ddebbc3 100644 --- a/pkg/generated/clientset/versioned/typed/search/v1alpha1/fake/fake_search_client.go +++ b/pkg/generated/clientset/versioned/typed/search/v1alpha1/fake/fake_search_client.go @@ -12,8 +12,8 @@ type FakeSearchV1alpha1 struct { *testing.Fake } -func (c *FakeSearchV1alpha1) ResourceRegistries(namespace string) v1alpha1.ResourceRegistryInterface { - return &FakeResourceRegistries{c, namespace} +func (c *FakeSearchV1alpha1) ResourceRegistries() v1alpha1.ResourceRegistryInterface { + return &FakeResourceRegistries{c} } // RESTClient returns a RESTClient that is used to communicate diff --git a/pkg/generated/clientset/versioned/typed/search/v1alpha1/resourceregistry.go b/pkg/generated/clientset/versioned/typed/search/v1alpha1/resourceregistry.go index e36eb238e..7a95c90bf 100644 --- a/pkg/generated/clientset/versioned/typed/search/v1alpha1/resourceregistry.go +++ b/pkg/generated/clientset/versioned/typed/search/v1alpha1/resourceregistry.go @@ -17,7 +17,7 @@ import ( // ResourceRegistriesGetter has a method to return a ResourceRegistryInterface. // A group's client should implement this interface. type ResourceRegistriesGetter interface { - ResourceRegistries(namespace string) ResourceRegistryInterface + ResourceRegistries() ResourceRegistryInterface } // ResourceRegistryInterface has methods to work with ResourceRegistry resources. @@ -37,14 +37,12 @@ type ResourceRegistryInterface interface { // resourceRegistries implements ResourceRegistryInterface type resourceRegistries struct { client rest.Interface - ns string } // newResourceRegistries returns a ResourceRegistries -func newResourceRegistries(c *SearchV1alpha1Client, namespace string) *resourceRegistries { +func newResourceRegistries(c *SearchV1alpha1Client) *resourceRegistries { return &resourceRegistries{ client: c.RESTClient(), - ns: namespace, } } @@ -52,7 +50,6 @@ func newResourceRegistries(c *SearchV1alpha1Client, namespace string) *resourceR func (c *resourceRegistries) Get(ctx context.Context, name string, options v1.GetOptions) (result *v1alpha1.ResourceRegistry, err error) { result = &v1alpha1.ResourceRegistry{} err = c.client.Get(). - Namespace(c.ns). Resource("resourceregistries"). Name(name). VersionedParams(&options, scheme.ParameterCodec). @@ -69,7 +66,6 @@ func (c *resourceRegistries) List(ctx context.Context, opts v1.ListOptions) (res } result = &v1alpha1.ResourceRegistryList{} err = c.client.Get(). - Namespace(c.ns). Resource("resourceregistries"). VersionedParams(&opts, scheme.ParameterCodec). Timeout(timeout). @@ -86,7 +82,6 @@ func (c *resourceRegistries) Watch(ctx context.Context, opts v1.ListOptions) (wa } opts.Watch = true return c.client.Get(). - Namespace(c.ns). Resource("resourceregistries"). VersionedParams(&opts, scheme.ParameterCodec). Timeout(timeout). @@ -97,7 +92,6 @@ func (c *resourceRegistries) Watch(ctx context.Context, opts v1.ListOptions) (wa func (c *resourceRegistries) Create(ctx context.Context, resourceRegistry *v1alpha1.ResourceRegistry, opts v1.CreateOptions) (result *v1alpha1.ResourceRegistry, err error) { result = &v1alpha1.ResourceRegistry{} err = c.client.Post(). - Namespace(c.ns). Resource("resourceregistries"). VersionedParams(&opts, scheme.ParameterCodec). Body(resourceRegistry). @@ -110,7 +104,6 @@ func (c *resourceRegistries) Create(ctx context.Context, resourceRegistry *v1alp func (c *resourceRegistries) Update(ctx context.Context, resourceRegistry *v1alpha1.ResourceRegistry, opts v1.UpdateOptions) (result *v1alpha1.ResourceRegistry, err error) { result = &v1alpha1.ResourceRegistry{} err = c.client.Put(). - Namespace(c.ns). Resource("resourceregistries"). Name(resourceRegistry.Name). VersionedParams(&opts, scheme.ParameterCodec). @@ -125,7 +118,6 @@ func (c *resourceRegistries) Update(ctx context.Context, resourceRegistry *v1alp func (c *resourceRegistries) UpdateStatus(ctx context.Context, resourceRegistry *v1alpha1.ResourceRegistry, opts v1.UpdateOptions) (result *v1alpha1.ResourceRegistry, err error) { result = &v1alpha1.ResourceRegistry{} err = c.client.Put(). - Namespace(c.ns). Resource("resourceregistries"). Name(resourceRegistry.Name). SubResource("status"). @@ -139,7 +131,6 @@ func (c *resourceRegistries) UpdateStatus(ctx context.Context, resourceRegistry // Delete takes name of the resourceRegistry and deletes it. Returns an error if one occurs. func (c *resourceRegistries) Delete(ctx context.Context, name string, opts v1.DeleteOptions) error { return c.client.Delete(). - Namespace(c.ns). Resource("resourceregistries"). Name(name). Body(&opts). @@ -154,7 +145,6 @@ func (c *resourceRegistries) DeleteCollection(ctx context.Context, opts v1.Delet timeout = time.Duration(*listOpts.TimeoutSeconds) * time.Second } return c.client.Delete(). - Namespace(c.ns). Resource("resourceregistries"). VersionedParams(&listOpts, scheme.ParameterCodec). Timeout(timeout). @@ -167,7 +157,6 @@ func (c *resourceRegistries) DeleteCollection(ctx context.Context, opts v1.Delet func (c *resourceRegistries) Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts v1.PatchOptions, subresources ...string) (result *v1alpha1.ResourceRegistry, err error) { result = &v1alpha1.ResourceRegistry{} err = c.client.Patch(pt). - Namespace(c.ns). Resource("resourceregistries"). Name(name). SubResource(subresources...). diff --git a/pkg/generated/clientset/versioned/typed/search/v1alpha1/search_client.go b/pkg/generated/clientset/versioned/typed/search/v1alpha1/search_client.go index 629a7c1de..6fe00735e 100644 --- a/pkg/generated/clientset/versioned/typed/search/v1alpha1/search_client.go +++ b/pkg/generated/clientset/versioned/typed/search/v1alpha1/search_client.go @@ -20,8 +20,8 @@ type SearchV1alpha1Client struct { restClient rest.Interface } -func (c *SearchV1alpha1Client) ResourceRegistries(namespace string) ResourceRegistryInterface { - return newResourceRegistries(c, namespace) +func (c *SearchV1alpha1Client) ResourceRegistries() ResourceRegistryInterface { + return newResourceRegistries(c) } // NewForConfig creates a new SearchV1alpha1Client for the given config. diff --git a/pkg/generated/informers/externalversions/search/v1alpha1/interface.go b/pkg/generated/informers/externalversions/search/v1alpha1/interface.go index d12fce9e5..fef87d0d6 100644 --- a/pkg/generated/informers/externalversions/search/v1alpha1/interface.go +++ b/pkg/generated/informers/externalversions/search/v1alpha1/interface.go @@ -25,5 +25,5 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList // ResourceRegistries returns a ResourceRegistryInformer. func (v *version) ResourceRegistries() ResourceRegistryInformer { - return &resourceRegistryInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} + return &resourceRegistryInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} } diff --git a/pkg/generated/informers/externalversions/search/v1alpha1/resourceregistry.go b/pkg/generated/informers/externalversions/search/v1alpha1/resourceregistry.go index b9b28bb23..676748b19 100644 --- a/pkg/generated/informers/externalversions/search/v1alpha1/resourceregistry.go +++ b/pkg/generated/informers/externalversions/search/v1alpha1/resourceregistry.go @@ -26,33 +26,32 @@ type ResourceRegistryInformer interface { type resourceRegistryInformer struct { factory internalinterfaces.SharedInformerFactory tweakListOptions internalinterfaces.TweakListOptionsFunc - namespace string } // NewResourceRegistryInformer constructs a new informer for ResourceRegistry 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 NewResourceRegistryInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { - return NewFilteredResourceRegistryInformer(client, namespace, resyncPeriod, indexers, nil) +func NewResourceRegistryInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredResourceRegistryInformer(client, resyncPeriod, indexers, nil) } // NewFilteredResourceRegistryInformer constructs a new informer for ResourceRegistry 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 NewFilteredResourceRegistryInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { +func NewFilteredResourceRegistryInformer(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.SearchV1alpha1().ResourceRegistries(namespace).List(context.TODO(), options) + return client.SearchV1alpha1().ResourceRegistries().List(context.TODO(), options) }, WatchFunc: func(options v1.ListOptions) (watch.Interface, error) { if tweakListOptions != nil { tweakListOptions(&options) } - return client.SearchV1alpha1().ResourceRegistries(namespace).Watch(context.TODO(), options) + return client.SearchV1alpha1().ResourceRegistries().Watch(context.TODO(), options) }, }, &searchv1alpha1.ResourceRegistry{}, @@ -62,7 +61,7 @@ func NewFilteredResourceRegistryInformer(client versioned.Interface, namespace s } func (f *resourceRegistryInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { - return NewFilteredResourceRegistryInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) + return NewFilteredResourceRegistryInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) } func (f *resourceRegistryInformer) Informer() cache.SharedIndexInformer { diff --git a/pkg/generated/listers/search/v1alpha1/expansion_generated.go b/pkg/generated/listers/search/v1alpha1/expansion_generated.go index 6ef680d48..ab5388886 100644 --- a/pkg/generated/listers/search/v1alpha1/expansion_generated.go +++ b/pkg/generated/listers/search/v1alpha1/expansion_generated.go @@ -5,7 +5,3 @@ package v1alpha1 // ResourceRegistryListerExpansion allows custom methods to be added to // ResourceRegistryLister. type ResourceRegistryListerExpansion interface{} - -// ResourceRegistryNamespaceListerExpansion allows custom methods to be added to -// ResourceRegistryNamespaceLister. -type ResourceRegistryNamespaceListerExpansion interface{} diff --git a/pkg/generated/listers/search/v1alpha1/resourceregistry.go b/pkg/generated/listers/search/v1alpha1/resourceregistry.go index d94421bce..9be20abf9 100644 --- a/pkg/generated/listers/search/v1alpha1/resourceregistry.go +++ b/pkg/generated/listers/search/v1alpha1/resourceregistry.go @@ -15,8 +15,9 @@ type ResourceRegistryLister interface { // List lists all ResourceRegistries in the indexer. // Objects returned here must be treated as read-only. List(selector labels.Selector) (ret []*v1alpha1.ResourceRegistry, err error) - // ResourceRegistries returns an object that can list and get ResourceRegistries. - ResourceRegistries(namespace string) ResourceRegistryNamespaceLister + // Get retrieves the ResourceRegistry from the index for a given name. + // Objects returned here must be treated as read-only. + Get(name string) (*v1alpha1.ResourceRegistry, error) ResourceRegistryListerExpansion } @@ -38,41 +39,9 @@ func (s *resourceRegistryLister) List(selector labels.Selector) (ret []*v1alpha1 return ret, err } -// ResourceRegistries returns an object that can list and get ResourceRegistries. -func (s *resourceRegistryLister) ResourceRegistries(namespace string) ResourceRegistryNamespaceLister { - return resourceRegistryNamespaceLister{indexer: s.indexer, namespace: namespace} -} - -// ResourceRegistryNamespaceLister helps list and get ResourceRegistries. -// All objects returned here must be treated as read-only. -type ResourceRegistryNamespaceLister interface { - // List lists all ResourceRegistries in the indexer for a given namespace. - // Objects returned here must be treated as read-only. - List(selector labels.Selector) (ret []*v1alpha1.ResourceRegistry, err error) - // Get retrieves the ResourceRegistry from the indexer for a given namespace and name. - // Objects returned here must be treated as read-only. - Get(name string) (*v1alpha1.ResourceRegistry, error) - ResourceRegistryNamespaceListerExpansion -} - -// resourceRegistryNamespaceLister implements the ResourceRegistryNamespaceLister -// interface. -type resourceRegistryNamespaceLister struct { - indexer cache.Indexer - namespace string -} - -// List lists all ResourceRegistries in the indexer for a given namespace. -func (s resourceRegistryNamespaceLister) List(selector labels.Selector) (ret []*v1alpha1.ResourceRegistry, err error) { - err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { - ret = append(ret, m.(*v1alpha1.ResourceRegistry)) - }) - return ret, err -} - -// Get retrieves the ResourceRegistry from the indexer for a given namespace and name. -func (s resourceRegistryNamespaceLister) Get(name string) (*v1alpha1.ResourceRegistry, error) { - obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) +// Get retrieves the ResourceRegistry from the index for a given name. +func (s *resourceRegistryLister) Get(name string) (*v1alpha1.ResourceRegistry, error) { + obj, exists, err := s.indexer.GetByKey(name) if err != nil { return nil, err } diff --git a/pkg/generated/openapi/zz_generated.openapi.go b/pkg/generated/openapi/zz_generated.openapi.go index bad45b4dc..946cc1c8c 100644 --- a/pkg/generated/openapi/zz_generated.openapi.go +++ b/pkg/generated/openapi/zz_generated.openapi.go @@ -76,6 +76,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ResourceRegistrySpec": schema_pkg_apis_search_v1alpha1_ResourceRegistrySpec(ref), "github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ResourceRegistryStatus": schema_pkg_apis_search_v1alpha1_ResourceRegistryStatus(ref), "github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.ResourceSelector": schema_pkg_apis_search_v1alpha1_ResourceSelector(ref), + "github.com/karmada-io/karmada/pkg/apis/search/v1alpha1.Search": schema_pkg_apis_search_v1alpha1_Search(ref), "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1.AggregatedStatusItem": schema_pkg_apis_work_v1alpha1_AggregatedStatusItem(ref), "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1.ClusterResourceBinding": schema_pkg_apis_work_v1alpha1_ClusterResourceBinding(ref), "github.com/karmada-io/karmada/pkg/apis/work/v1alpha1.ClusterResourceBindingList": schema_pkg_apis_work_v1alpha1_ClusterResourceBindingList(ref), @@ -3280,6 +3281,33 @@ func schema_pkg_apis_search_v1alpha1_ResourceSelector(ref common.ReferenceCallba } } +func schema_pkg_apis_search_v1alpha1_Search(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Description: "Search define a flag for resource search that do not have actual resources.", + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "kind": { + SchemaProps: spec.SchemaProps{ + 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{"string"}, + Format: "", + }, + }, + "apiVersion": { + SchemaProps: spec.SchemaProps{ + 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{"string"}, + Format: "", + }, + }, + }, + }, + }, + } +} + func schema_pkg_apis_work_v1alpha1_AggregatedStatusItem(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ diff --git a/pkg/karmadactl/cmdinit/karmada/deploy.go b/pkg/karmadactl/cmdinit/karmada/deploy.go index 4b2f9469a..813b06bc8 100644 --- a/pkg/karmadactl/cmdinit/karmada/deploy.go +++ b/pkg/karmadactl/cmdinit/karmada/deploy.go @@ -172,7 +172,7 @@ func getName(str, start, end string) string { } func initAPIService(clientSet *kubernetes.Clientset, restConfig *rest.Config, systemNamespace string) error { - // https://github.com/karmada-io/karmada/blob/master/artifacts/deploy/apiservice.yaml + // https://github.com/karmada-io/karmada/blob/master/artifacts/deploy/karmada-aggregated-apiserver-apiservice.yaml aaService := &corev1.Service{ TypeMeta: metav1.TypeMeta{ APIVersion: "v1", diff --git a/pkg/registry/search/storage/resourceregistry.go b/pkg/registry/search/storage/resourceregistry.go new file mode 100644 index 000000000..4c66e2a83 --- /dev/null +++ b/pkg/registry/search/storage/resourceregistry.go @@ -0,0 +1,88 @@ +package storage + +import ( + "context" + + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/generic" + genericregistry "k8s.io/apiserver/pkg/registry/generic/registry" + "k8s.io/apiserver/pkg/registry/rest" + "sigs.k8s.io/structured-merge-diff/v4/fieldpath" + + searchapis "github.com/karmada-io/karmada/pkg/apis/search" + searchregistry "github.com/karmada-io/karmada/pkg/registry/search" +) + +// ResourceRegistryStorage includes storage for ResourceRegistry and for all the subresources. +type ResourceRegistryStorage struct { + ResourceRegistry *REST + Status *StatusREST +} + +// NewResourceRegistryStorage returns a ResourceRegistryStorage object that will work against resourceRegistries. +func NewResourceRegistryStorage(scheme *runtime.Scheme, optsGetter generic.RESTOptionsGetter) (*ResourceRegistryStorage, error) { + strategy := searchregistry.NewStrategy(scheme) + + store := &genericregistry.Store{ + NewFunc: func() runtime.Object { return &searchapis.ResourceRegistry{} }, + NewListFunc: func() runtime.Object { return &searchapis.ResourceRegistryList{} }, + PredicateFunc: searchregistry.MatchResourceRegistry, + DefaultQualifiedResource: searchapis.Resource("resourceRegistries"), + + CreateStrategy: strategy, + UpdateStrategy: strategy, + DeleteStrategy: strategy, + + // TODO: define table converter that exposes more than name/creation timestamp + TableConvertor: rest.NewDefaultTableConvertor(searchapis.Resource("resourceRegistries")), + } + + options := &generic.StoreOptions{RESTOptions: optsGetter, AttrFunc: searchregistry.GetAttrs} + if err := store.CompleteWithOptions(options); err != nil { + return nil, err + } + + statusStrategy := searchregistry.NewStatusStrategy(strategy) + statusStore := *store + statusStore.UpdateStrategy = statusStrategy + statusStore.ResetFieldsStrategy = statusStrategy + + resourceRegistryRest := &REST{store} + return &ResourceRegistryStorage{ + ResourceRegistry: resourceRegistryRest, + Status: &StatusREST{&statusStore}, + }, nil +} + +// REST implements a RESTStorage for ResourceRegistry. +type REST struct { + *genericregistry.Store +} + +// StatusREST implements the REST endpoint for changing the status of a ResourceRegistry. +type StatusREST struct { + store *genericregistry.Store +} + +// New returns empty ResourceRegistry. +func (r *StatusREST) New() runtime.Object { + return &searchapis.ResourceRegistry{} +} + +// Get retrieves the object from the storage. It is required to support Patch. +func (r *StatusREST) Get(ctx context.Context, name string, options *metav1.GetOptions) (runtime.Object, error) { + return r.store.Get(ctx, name, options) +} + +// Update alters the status subset of an object. +func (r *StatusREST) Update(ctx context.Context, name string, objInfo rest.UpdatedObjectInfo, createValidation rest.ValidateObjectFunc, updateValidation rest.ValidateObjectUpdateFunc, forceAllowCreate bool, options *metav1.UpdateOptions) (runtime.Object, bool, error) { + // We are explicitly setting forceAllowCreate to false in the call to the underlying storage because + // subresources should never allow create on update. + return r.store.Update(ctx, name, objInfo, createValidation, updateValidation, false, options) +} + +// GetResetFields implements rest.ResetFieldsStrategy +func (r *StatusREST) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + return r.store.GetResetFields() +} diff --git a/pkg/registry/search/storage/search.go b/pkg/registry/search/storage/search.go new file mode 100644 index 000000000..26b26a699 --- /dev/null +++ b/pkg/registry/search/storage/search.go @@ -0,0 +1,61 @@ +package storage + +import ( + "context" + "net/http" + + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apiserver/pkg/registry/rest" + "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" + + searchapis "github.com/karmada-io/karmada/pkg/apis/search" +) + +// SearchREST implements a RESTStorage for search resource. +type SearchREST struct { + kubeClient kubernetes.Interface + + // add needed parameters here +} + +var _ rest.Scoper = &SearchREST{} +var _ rest.Storage = &SearchREST{} +var _ rest.Connecter = &SearchREST{} + +// NewSearchREST returns a RESTStorage object that will work against search. +func NewSearchREST(client kubernetes.Interface) *SearchREST { + return &SearchREST{ + kubeClient: client, + } +} + +// New return empty Search object. +func (r *SearchREST) New() runtime.Object { + return &searchapis.Search{} +} + +// NamespaceScoped returns false because Search is not namespaced. +func (r *SearchREST) NamespaceScoped() bool { + return false +} + +// ConnectMethods returns the list of HTTP methods handled by Connect. +func (r *SearchREST) ConnectMethods() []string { + return []string{"GET"} +} + +// NewConnectOptions returns an empty options object that will be used to pass options to the Connect method. +func (r *SearchREST) NewConnectOptions() (runtime.Object, bool, string) { + return nil, true, "" +} + +// Connect returns a handler for the ES search. +func (r *SearchREST) Connect(ctx context.Context, id string, _ runtime.Object, responder rest.Responder) (http.Handler, error) { + klog.Infof("Prepare for construct handler to connect ES.") + + return http.HandlerFunc(func(rw http.ResponseWriter, req *http.Request) { + + // Construct a handler and send the request to the ES. + }), nil +} diff --git a/pkg/registry/search/strategy.go b/pkg/registry/search/strategy.go new file mode 100644 index 000000000..e98ee8c36 --- /dev/null +++ b/pkg/registry/search/strategy.go @@ -0,0 +1,142 @@ +package search + +import ( + "context" + "fmt" + + "k8s.io/apimachinery/pkg/fields" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/util/validation/field" + "k8s.io/apiserver/pkg/registry/generic" + "k8s.io/apiserver/pkg/storage" + "k8s.io/apiserver/pkg/storage/names" + "sigs.k8s.io/structured-merge-diff/v4/fieldpath" + + searchapis "github.com/karmada-io/karmada/pkg/apis/search" +) + +// NewStrategy creates and returns a ResourceRegistry Strategy instance. +func NewStrategy(typer runtime.ObjectTyper) Strategy { + return Strategy{typer, names.SimpleNameGenerator} +} + +// GetAttrs returns labels.Set, fields.Set, and error in case the given runtime.Object is not a ResourceRegistry. +func GetAttrs(obj runtime.Object) (labels.Set, fields.Set, error) { + resourceRegistry, ok := obj.(*searchapis.ResourceRegistry) + if !ok { + return nil, nil, fmt.Errorf("given object is not a ResourceRegistry") + } + return resourceRegistry.ObjectMeta.Labels, SelectableFields(resourceRegistry), nil +} + +// MatchResourceRegistry is the filter used by the generic etcd backend to watch events +// from etcd to clients of the apiserver only interested in specific labels/fields. +func MatchResourceRegistry(label labels.Selector, field fields.Selector) storage.SelectionPredicate { + return storage.SelectionPredicate{ + Label: label, + Field: field, + GetAttrs: GetAttrs, + } +} + +// SelectableFields returns a field set that represents the object. +func SelectableFields(obj *searchapis.ResourceRegistry) fields.Set { + return generic.ObjectMetaFieldsSet(&obj.ObjectMeta, false) +} + +// Strategy implements behavior for ResourceRegistry. +type Strategy struct { + runtime.ObjectTyper + names.NameGenerator +} + +// NamespaceScoped returns if the object must be in a namespace. +func (Strategy) NamespaceScoped() bool { + return false +} + +// GetResetFields returns the set of fields that get reset by the strategy +// and should not be modified by the user. +func (Strategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + return map[fieldpath.APIVersion]*fieldpath.Set{ + "search.karmada.io/v1alpha1": fieldpath.NewSet( + fieldpath.MakePathOrDie("status"), + ), + } +} + +// PrepareForCreate is invoked on create before validation to normalize the object. +func (Strategy) PrepareForCreate(ctx context.Context, obj runtime.Object) { +} + +// PrepareForUpdate is invoked on update before validation to normalize the object. +func (Strategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { +} + +// Validate returns an ErrorList with validation errors or nil. +func (Strategy) Validate(ctx context.Context, obj runtime.Object) field.ErrorList { + // TODO: add validation for ResourceRegistry + return field.ErrorList{} +} + +// WarningsOnCreate returns warnings for the creation of the given object. +func (Strategy) WarningsOnCreate(ctx context.Context, obj runtime.Object) []string { return nil } + +// AllowCreateOnUpdate returns true if the object can be created by a PUT. +func (Strategy) AllowCreateOnUpdate() bool { + return false +} + +// AllowUnconditionalUpdate returns true if the object can be updated +// unconditionally (irrespective of the latest resource version), when +// there is no resource version specified in the object. +func (Strategy) AllowUnconditionalUpdate() bool { + return true +} + +// Canonicalize allows an object to be mutated into a canonical form. +func (Strategy) Canonicalize(obj runtime.Object) { +} + +// ValidateUpdate is invoked after default fields in the object have been +// filled in before the object is persisted. +func (Strategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { + // TODO: add validation for ResourceRegistry + return field.ErrorList{} +} + +// WarningsOnUpdate returns warnings for the given update. +func (Strategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { + return nil +} + +// StatusStrategy implements behavior for ResourceRegistryStatus. +type StatusStrategy struct { + Strategy +} + +// NewStatusStrategy creates and returns a StatusStrategy instance. +func NewStatusStrategy(strategy Strategy) StatusStrategy { + return StatusStrategy{strategy} +} + +// GetResetFields returns the set of fields that get reset by the strategy +// and should not be modified by the user. +func (StatusStrategy) GetResetFields() map[fieldpath.APIVersion]*fieldpath.Set { + return map[fieldpath.APIVersion]*fieldpath.Set{} +} + +// PrepareForUpdate clears fields that are not allowed to be set by end users on update of status +func (StatusStrategy) PrepareForUpdate(ctx context.Context, obj, old runtime.Object) { +} + +// ValidateUpdate is the default update validation for an end user updating status +func (StatusStrategy) ValidateUpdate(ctx context.Context, obj, old runtime.Object) field.ErrorList { + return field.ErrorList{} +} + +// WarningsOnUpdate returns warnings for the given update. +func (StatusStrategy) WarningsOnUpdate(ctx context.Context, obj, old runtime.Object) []string { + return nil +} diff --git a/pkg/search/apiserver.go b/pkg/search/apiserver.go new file mode 100644 index 000000000..7cf09c668 --- /dev/null +++ b/pkg/search/apiserver.go @@ -0,0 +1,118 @@ +package search + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" + "k8s.io/apimachinery/pkg/runtime/serializer" + "k8s.io/apimachinery/pkg/version" + "k8s.io/apiserver/pkg/registry/rest" + genericapiserver "k8s.io/apiserver/pkg/server" + "k8s.io/client-go/kubernetes" + "k8s.io/klog/v2" + + searchapis "github.com/karmada-io/karmada/pkg/apis/search" + searchinstall "github.com/karmada-io/karmada/pkg/apis/search/install" + searchstorage "github.com/karmada-io/karmada/pkg/registry/search/storage" +) + +var ( + // Scheme defines methods for serializing and deserializing API objects. + Scheme = runtime.NewScheme() + // Codecs provides methods for retrieving codecs and serializers for specific + // versions and content types. + Codecs = serializer.NewCodecFactory(Scheme) + // ParameterCodec handles versioning of objects that are converted to query parameters. + ParameterCodec = runtime.NewParameterCodec(Scheme) +) + +func init() { + searchinstall.Install(Scheme) + + // we need to add the options to empty v1 + // TODO fix the server code to avoid this + metav1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + + // TODO: keep the generic API server from wanting this + unversioned := schema.GroupVersion{Group: "", Version: "v1"} + Scheme.AddUnversionedTypes(unversioned, + &metav1.Status{}, + &metav1.APIVersions{}, + &metav1.APIGroupList{}, + &metav1.APIGroup{}, + &metav1.APIResourceList{}, + ) +} + +// ExtraConfig holds custom apiserver config +type ExtraConfig struct { + // Add custom config if necessary. +} + +// Config defines the config for the APIServer. +type Config struct { + GenericConfig *genericapiserver.RecommendedConfig + ExtraConfig ExtraConfig +} + +// APIServer contains state for karmada-search. +type APIServer struct { + GenericAPIServer *genericapiserver.GenericAPIServer +} + +type completedConfig struct { + GenericConfig genericapiserver.CompletedConfig + ExtraConfig *ExtraConfig +} + +// CompletedConfig embeds a private pointer that cannot be instantiated outside this package. +type CompletedConfig struct { + *completedConfig +} + +// Complete fills in any fields not set that are required to have valid data. It's mutating the receiver. +func (cfg *Config) Complete() CompletedConfig { + c := completedConfig{ + cfg.GenericConfig.Complete(), + &cfg.ExtraConfig, + } + + c.GenericConfig.Version = &version.Info{ + Major: "1", + Minor: "0", + } + + return CompletedConfig{&c} +} + +func (c completedConfig) New(kubeClient kubernetes.Interface) (*APIServer, error) { + genericServer, err := c.GenericConfig.New("karmada-search", genericapiserver.NewEmptyDelegate()) + if err != nil { + return nil, err + } + + server := &APIServer{ + GenericAPIServer: genericServer, + } + + apiGroupInfo := genericapiserver.NewDefaultAPIGroupInfo(searchapis.GroupName, Scheme, ParameterCodec, Codecs) + + resourceRegistryStorage, err := searchstorage.NewResourceRegistryStorage(Scheme, c.GenericConfig.RESTOptionsGetter) + if err != nil { + klog.Errorf("unable to create REST storage for a resource due to %v, will die", err) + return nil, err + } + searchREST := searchstorage.NewSearchREST(kubeClient) + + v1alpha1search := map[string]rest.Storage{} + v1alpha1search["resourceRegistry"] = resourceRegistryStorage.ResourceRegistry + v1alpha1search["resourceRegistry/status"] = resourceRegistryStorage.Status + v1alpha1search["search"] = searchREST + apiGroupInfo.VersionedResourcesStorageMap["v1alpha1"] = v1alpha1search + + if err = server.GenericAPIServer.InstallAPIGroup(&apiGroupInfo); err != nil { + return nil, err + } + + return server, nil +}