diff --git a/cmd/kyma/alpha/create/module/module.go b/cmd/kyma/alpha/create/module/module.go index a66327f79..b05e9fad1 100644 --- a/cmd/kyma/alpha/create/module/module.go +++ b/cmd/kyma/alpha/create/module/module.go @@ -8,6 +8,9 @@ import ( "path/filepath" "strings" + "github.com/kyma-project/cli/internal/cli" + "github.com/kyma-project/cli/internal/nice" + "github.com/kyma-project/cli/pkg/module" "github.com/mandelsoft/vfs/pkg/memoryfs" "github.com/mandelsoft/vfs/pkg/osfs" "github.com/mandelsoft/vfs/pkg/vfs" @@ -16,10 +19,8 @@ import ( "github.com/spf13/cobra" "go.uber.org/zap" "golang.org/x/exp/maps" - - "github.com/kyma-project/cli/internal/cli" - "github.com/kyma-project/cli/internal/nice" - "github.com/kyma-project/cli/pkg/module" + "gopkg.in/yaml.v3" + "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions" ) type command struct { @@ -205,6 +206,11 @@ func configureLegacyFlags(cmd *cobra.Command, o *Options) *cobra.Command { return cmd } +type validator interface { + GetCrd() []byte + Run(ctx context.Context, log *zap.SugaredLogger) error +} + func (cmd *command) Run(ctx context.Context) error { osFS := osfs.New() @@ -249,7 +255,8 @@ func (cmd *command) Run(ctx context.Context) error { } cmd.CurrentStep.Successf("Module built") - if err := cmd.validateDefaultCR(ctx, modDef, l); err != nil { + var crValidator validator + if crValidator, err = cmd.validateDefaultCR(ctx, modDef, l); err != nil { return err } @@ -350,6 +357,12 @@ func (cmd *command) Run(ctx context.Context) error { labels["operator.kyma-project.io/internal"] = "true" } } + isClusterScoped := isCrdClusterScoped(crValidator.GetCrd()) + if isClusterScoped { + annotations["operator.kyma-project.io/is-cluster-scoped"] = "true" + } else { + annotations["operator.kyma-project.io/is-cluster-scoped"] = "false" + } var channel = cmd.opts.Channel if modCnf != nil { @@ -374,15 +387,10 @@ func (cmd *command) Run(ctx context.Context) error { return nil } -func (cmd *command) validateDefaultCR(ctx context.Context, modDef *module.Definition, l *zap.SugaredLogger) error { +func (cmd *command) validateDefaultCR(ctx context.Context, modDef *module.Definition, l *zap.SugaredLogger) (validator, error) { cmd.NewStep("Validating Default CR") - type validator interface { - Run(ctx context.Context, log *zap.SugaredLogger) error - } - var crValidator validator - if cmd.opts.WithModuleConfigFile() { crValidator = module.NewSingleManifestFileCRValidator(modDef.DefaultCR, modDef.SingleManifestPath) } else { @@ -392,12 +400,12 @@ func (cmd *command) validateDefaultCR(ctx context.Context, modDef *module.Defini if err := crValidator.Run(ctx, l); err != nil { if errors.Is(err, module.ErrEmptyCR) { cmd.CurrentStep.Successf("Default CR validation skipped - no default CR") - return nil + return crValidator, nil } - return err + return crValidator, err } cmd.CurrentStep.Successf("Default CR validation succeeded") - return nil + return crValidator, nil } func (cmd *command) getRemote(nameMapping module.NameMapping) (*module.Remote, error) { @@ -515,3 +523,16 @@ func resolveFilePath(given, absolutePrefix string) (string, error) { return res, nil } + +func isCrdClusterScoped(crdBytes []byte) bool { + if crdBytes == nil { + return false + } + + crd := &apiextensions.CustomResourceDefinition{} + if err := yaml.Unmarshal(crdBytes, crd); err != nil { + return false + } + + return crd.Spec.Scope == apiextensions.ClusterScoped +} diff --git a/cmd/kyma/alpha/create/module/module_test.go b/cmd/kyma/alpha/create/module/module_test.go new file mode 100644 index 000000000..b62fa5142 --- /dev/null +++ b/cmd/kyma/alpha/create/module/module_test.go @@ -0,0 +1,45 @@ +package module + +import ( + _ "embed" + "testing" +) + +//go:embed testdata/clusterScopedCRD.yaml +var clusterScopedCrd []byte + +//go:embed testdata/namespacedScopedCRD.yaml +var namespacedScopedCrd []byte + +func Test_isCrdClusterScoped(t *testing.T) { + type args struct { + crdBytes []byte + } + tests := []struct { + name string + args args + want bool + }{ + { + name: "Cluster scoped module", + args: args{ + crdBytes: clusterScopedCrd, + }, + want: true, + }, + { + name: "Namespaced scoped module", + args: args{ + crdBytes: namespacedScopedCrd, + }, + want: false, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if got := isCrdClusterScoped(tt.args.crdBytes); got != tt.want { + t.Errorf("isCrdClusterScoped() = %v, want %v", got, tt.want) + } + }) + } +} diff --git a/cmd/kyma/alpha/create/module/testdata/clusterScopedCRD.yaml b/cmd/kyma/alpha/create/module/testdata/clusterScopedCRD.yaml new file mode 100644 index 000000000..69241aa6b --- /dev/null +++ b/cmd/kyma/alpha/create/module/testdata/clusterScopedCRD.yaml @@ -0,0 +1,351 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.11.3 + creationTimestamp: null + name: logpipelines.telemetry.kyma-project.io +spec: + group: telemetry.kyma-project.io + names: + kind: LogPipeline + listKind: LogPipelineList + plural: logpipelines + singular: logpipeline + scope: Cluster + versions: + - additionalPrinterColumns: + - jsonPath: .status.conditions[-1].type + name: Status + type: string + - jsonPath: .status.unsupportedMode + name: Unsupported-Mode + type: boolean + - jsonPath: .metadata.creationTimestamp + name: Age + type: date + name: v1alpha1 + schema: + openAPIV3Schema: + description: LogPipeline is the Schema for the logpipelines API + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + description: Defines the desired state of LogPipeline + properties: + files: + items: + description: Provides file content to be consumed by a LogPipeline + configuration + properties: + content: + type: string + name: + type: string + type: object + type: array + filters: + items: + description: Describes a filtering option on the logs of the pipeline. + properties: + custom: + description: 'Custom filter definition in the Fluent Bit syntax. + Note: If you use a `custom` filter, you put the LogPipeline + in unsupported mode.' + type: string + type: object + type: array + input: + description: Defines where to collect logs, including selector mechanisms. + properties: + application: + description: Configures in more detail from which containers application + logs are enabled as input. + properties: + containers: + description: Describes whether application logs from specific + containers are selected. The options are mutually exclusive. + properties: + exclude: + description: Specifies to exclude only the container logs + with the specified container names. + items: + type: string + type: array + include: + description: Specifies to include only the container logs + with the specified container names. + items: + type: string + type: array + type: object + dropLabels: + description: Defines whether to drop all Kubernetes labels. + The default is `false`. + type: boolean + keepAnnotations: + description: Defines whether to keep all Kubernetes annotations. + The default is `false`. + type: boolean + namespaces: + description: Describes whether application logs from specific + Namespaces are selected. The options are mutually exclusive. + System Namespaces are excluded by default from the collection. + properties: + exclude: + description: Exclude the container logs of the specified + Namespace names. + items: + type: string + type: array + include: + description: Include only the container logs of the specified + Namespace names. + items: + type: string + type: array + system: + description: Set to `true` if collecting from all Namespaces + must also include the system Namespaces like kube-system, + istio-system, and kyma-system. + type: boolean + type: object + type: object + type: object + output: + description: '[Fluent Bit output](https://docs.fluentbit.io/manual/pipeline/outputs) + where you want to push the logs. Only one output can be specified.' + properties: + custom: + description: 'Defines a custom output in the Fluent Bit syntax. + Note: If you use a `custom` output, you put the LogPipeline + in unsupported mode.' + type: string + grafana-loki: + description: Configures an output to the Kyma-internal Loki instance. + [Fluent Bit grafana-loki output](https://grafana.com/docs/loki/v2.2.x/clients/fluentbit/). + **Note:** This output is considered legacy and is only provided + for backward compatibility with the [deprecated](https://kyma-project.io/blog/2022/11/2/loki-deprecation/) + in-cluster Loki instance. It might not be compatible with the + latest Loki versions. For integration with a custom Loki installation + use the `custom` output with the name `loki` instead, see also + [Installing a custom Loki stack in Kyma](https://github.com/kyma-project/examples/tree/main/loki). + properties: + labels: + additionalProperties: + type: string + description: Labels to set for each log record. + type: object + removeKeys: + description: Attributes to be removed from a log record. + items: + type: string + type: array + url: + description: Grafana Loki URL. + properties: + value: + description: Value that can contain references to Secret + values. + type: string + valueFrom: + properties: + secretKeyRef: + description: Refers to a key in a Secret. You must + provide `name` and `namespace` of the Secret, as + well as the name of the `key`. + properties: + key: + type: string + name: + type: string + namespace: + type: string + type: object + type: object + type: object + type: object + http: + description: Configures an HTTP-based output compatible with the + Fluent Bit HTTP output plugin. + properties: + compress: + description: Defines the compression algorithm to use. + type: string + dedot: + description: Enables de-dotting of Kubernetes labels and annotations + for compatibility with ElasticSearch based backends. Dots + (.) will be replaced by underscores (_). Default is `false`. + type: boolean + format: + description: Data format to be used in the HTTP request body. + Default is `json`. + type: string + host: + description: Defines the host of the HTTP receiver. + properties: + value: + description: Value that can contain references to Secret + values. + type: string + valueFrom: + properties: + secretKeyRef: + description: Refers to a key in a Secret. You must + provide `name` and `namespace` of the Secret, as + well as the name of the `key`. + properties: + key: + type: string + name: + type: string + namespace: + type: string + type: object + type: object + type: object + password: + description: Defines the basic auth password. + properties: + value: + description: Value that can contain references to Secret + values. + type: string + valueFrom: + properties: + secretKeyRef: + description: Refers to a key in a Secret. You must + provide `name` and `namespace` of the Secret, as + well as the name of the `key`. + properties: + key: + type: string + name: + type: string + namespace: + type: string + type: object + type: object + type: object + port: + description: Defines the port of the HTTP receiver. Default + is 443. + type: string + tls: + description: Configures TLS for the HTTP target server. + properties: + disabled: + description: Indicates if TLS is disabled or enabled. + Default is `false`. + type: boolean + skipCertificateValidation: + description: If `true`, the validation of certificates + is skipped. Default is `false`. + type: boolean + type: object + uri: + description: Defines the URI of the HTTP receiver. Default + is "/". + type: string + user: + description: Defines the basic auth user. + properties: + value: + description: Value that can contain references to Secret + values. + type: string + valueFrom: + properties: + secretKeyRef: + description: Refers to a key in a Secret. You must + provide `name` and `namespace` of the Secret, as + well as the name of the `key`. + properties: + key: + type: string + name: + type: string + namespace: + type: string + type: object + type: object + type: object + type: object + type: object + variables: + description: A list of mappings from Kubernetes Secret keys to environment + variables. Mapped keys are mounted as environment variables, so + that they are available as [Variables](https://docs.fluentbit.io/manual/administration/configuring-fluent-bit/classic-mode/variables) + in the sections. + items: + description: References a Kubernetes secret that should be provided + as environment variable to Fluent Bit + properties: + name: + description: Name of the variable to map. + type: string + valueFrom: + properties: + secretKeyRef: + description: Refers to a key in a Secret. You must provide + `name` and `namespace` of the Secret, as well as the name + of the `key`. + properties: + key: + type: string + name: + type: string + namespace: + type: string + type: object + type: object + type: object + type: array + type: object + status: + description: Shows the observed state of the LogPipeline + properties: + conditions: + description: An array of conditions describing the status of the pipeline. + items: + description: LogPipelineCondition contains details for the current + condition of this LogPipeline + properties: + lastTransitionTime: + description: An array of conditions describing the status of + the pipeline. + format: date-time + type: string + reason: + description: An array of conditions describing the status of + the pipeline. + type: string + type: + description: 'The possible transition types are:
- `Running`: + The instance is ready and usable.
- `Pending`: The pipeline + is being activated.' + type: string + type: object + type: array + unsupportedMode: + description: Is active when the LogPipeline uses a `custom` output + or filter; see [unsupported mode](https://kyma-project.io/docs/kyma/latest/01-overview/telemetry/telemetry-02-logs/#unsupported-mode). + type: boolean + type: object + type: object + served: true + storage: true + subresources: + status: {} \ No newline at end of file diff --git a/cmd/kyma/alpha/create/module/testdata/namespacedScopedCRD.yaml b/cmd/kyma/alpha/create/module/testdata/namespacedScopedCRD.yaml new file mode 100644 index 000000000..9165437e7 --- /dev/null +++ b/cmd/kyma/alpha/create/module/testdata/namespacedScopedCRD.yaml @@ -0,0 +1,137 @@ +--- +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + annotations: + controller-gen.kubebuilder.io/version: v0.9.2 + creationTimestamp: null + name: samples.operator.kyma-project.io +spec: + group: operator.kyma-project.io + names: + kind: Sample + listKind: SampleList + plural: samples + singular: sample + scope: Namespaced + versions: + - additionalPrinterColumns: + - jsonPath: .status.state + name: State + type: string + name: v1alpha1 + schema: + openAPIV3Schema: + description: Sample is the Schema for the samples API. + properties: + apiVersion: + description: 'APIVersion defines the versioned schema of this representation + of an object. Servers should convert recognized schemas to the latest + internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' + type: string + kind: + description: 'Kind is a string value representing the REST resource this + object represents. Servers may infer this from the endpoint the client + submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' + type: string + metadata: + type: object + spec: + properties: + resourceFilePath: + description: ResourceFilePath indicates the local dir path containing + a .yaml or .yml, with all required resources to be processed + type: string + type: object + status: + properties: + conditions: + description: Conditions contain a set of conditionals to determine + the State of Status. If all Conditions are met, State is expected + to be in StateReady. + items: + description: "Condition contains details for one aspect of the current + state of this API Resource. --- This struct is intended for direct + use as an array at the field path .status.conditions. For example, + \n type FooStatus struct{ // Represents the observations of a + foo's current state. // Known .status.conditions.type are: \"Available\", + \"Progressing\", and \"Degraded\" // +patchMergeKey=type // +patchStrategy=merge + // +listType=map // +listMapKey=type Conditions []metav1.Condition + `json:\"conditions,omitempty\" patchStrategy:\"merge\" patchMergeKey:\"type\" + protobuf:\"bytes,1,rep,name=conditions\"` \n // other fields }" + properties: + lastTransitionTime: + description: lastTransitionTime is the last time the condition + transitioned from one status to another. This should be when + the underlying condition changed. If that is not known, then + using the time when the API field changed is acceptable. + format: date-time + type: string + message: + description: message is a human readable message indicating + details about the transition. This may be an empty string. + maxLength: 32768 + type: string + observedGeneration: + description: observedGeneration represents the .metadata.generation + that the condition was set based upon. For instance, if .metadata.generation + is currently 12, but the .status.conditions[x].observedGeneration + is 9, the condition is out of date with respect to the current + state of the instance. + format: int64 + minimum: 0 + type: integer + reason: + description: reason contains a programmatic identifier indicating + the reason for the condition's last transition. Producers + of specific condition types may define expected values and + meanings for this field, and whether the values are considered + a guaranteed API. The value should be a CamelCase string. + This field may not be empty. + maxLength: 1024 + minLength: 1 + pattern: ^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$ + type: string + status: + description: status of the condition, one of True, False, Unknown. + enum: + - "True" + - "False" + - Unknown + type: string + type: + description: type of condition in CamelCase or in foo.example.com/CamelCase. + --- Many .condition.type values are consistent across resources + like Available, but because arbitrary conditions can be useful + (see .node.status.conditions), the ability to deconflict is + important. The regex it matches is (dns1123SubdomainFmt/)?(qualifiedNameFmt) + maxLength: 316 + pattern: ^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$ + type: string + required: + - lastTransitionTime + - message + - reason + - status + - type + type: object + type: array + state: + description: State signifies current state of Module CR. Value can + be one of ("Ready", "Processing", "Error", "Deleting"). + enum: + - Processing + - Deleting + - Ready + - Error + - Warning + - "" + type: string + required: + - state + type: object + type: object + served: true + storage: true + subresources: + status: {} \ No newline at end of file diff --git a/go.mod b/go.mod index 71625b10c..f6047765e 100644 --- a/go.mod +++ b/go.mod @@ -26,11 +26,11 @@ require ( github.com/go-logr/logr v1.2.4 github.com/go-logr/zapr v1.2.3 github.com/imdario/mergo v0.3.15 - github.com/kyma-incubator/reconciler v0.0.0-20230720145416-32bfb53785f1 + github.com/kyma-incubator/reconciler v0.0.0-20230811075910-e99144248b04 github.com/kyma-project/hydroform/function v0.0.0-20230628151226-25b31247e585 github.com/kyma-project/hydroform/provision v0.0.0-20230418133637-1ea26b368bb6 github.com/kyma-project/lifecycle-manager v0.0.0-20230626125722-e28fc6438d83 - github.com/mandelsoft/vfs v0.0.0-20220805210647-bf14a11bfe31 + github.com/mandelsoft/vfs v0.0.0-20230714093241-d557f163aecd github.com/open-component-model/ocm v0.3.0-rc.1 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0-rc2 @@ -254,14 +254,14 @@ require ( go.starlark.net v0.0.0-20230128213706-3f75dec8e403 // indirect go.uber.org/atomic v1.10.0 // indirect go.uber.org/multierr v1.9.0 // indirect - golang.org/x/crypto v0.9.0 // indirect + golang.org/x/crypto v0.10.0 // indirect golang.org/x/mod v0.9.0 // indirect - golang.org/x/net v0.10.0 // indirect + golang.org/x/net v0.11.0 // indirect golang.org/x/oauth2 v0.4.0 // indirect golang.org/x/sync v0.1.0 // indirect - golang.org/x/sys v0.8.0 // indirect - golang.org/x/term v0.8.0 // indirect - golang.org/x/text v0.9.0 // indirect + golang.org/x/sys v0.9.0 // indirect + golang.org/x/term v0.9.0 // indirect + golang.org/x/text v0.10.0 // indirect golang.org/x/time v0.3.0 // indirect golang.org/x/tools v0.7.0 // indirect gomodules.xyz/jsonpatch/v2 v2.2.0 // indirect diff --git a/go.sum b/go.sum index 1ed3588d9..a0d92524d 100644 --- a/go.sum +++ b/go.sum @@ -1173,8 +1173,8 @@ github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/ktrysmt/go-bitbucket v0.6.4/go.mod h1:9u0v3hsd2rqCHRIpbir1oP7F58uo5dq19sBYvuMoyQ4= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= -github.com/kyma-incubator/reconciler v0.0.0-20230720145416-32bfb53785f1 h1:GtieKj9fCIlvVnfjcCvQ7R6aOAuFSfHnZFkoVLssQCI= -github.com/kyma-incubator/reconciler v0.0.0-20230720145416-32bfb53785f1/go.mod h1:hJnoGbxdqK4urAPkU8J1OxFXVqPc9pA7MlIL321xK3E= +github.com/kyma-incubator/reconciler v0.0.0-20230811075910-e99144248b04 h1:JRKd3v6qI/PD62x9X229IyT3clra/cr1BIRvE1TQ110= +github.com/kyma-incubator/reconciler v0.0.0-20230811075910-e99144248b04/go.mod h1:hJnoGbxdqK4urAPkU8J1OxFXVqPc9pA7MlIL321xK3E= github.com/kyma-project/hydroform/function v0.0.0-20230628151226-25b31247e585 h1:+fs52VM2jVQuVHWpcSVGfD9RXyao3izEm5Z+HYlJ5lk= github.com/kyma-project/hydroform/function v0.0.0-20230628151226-25b31247e585/go.mod h1:aNqrx5xoV2sOw5FZFShUzFLpc5VJku9YhokKC3PyQro= github.com/kyma-project/hydroform/provision v0.0.0-20230418133637-1ea26b368bb6 h1:k8TsRKhbYr+uQ1Glpbwii9kBqMPSFEZdMSov9KJjgiA= @@ -1231,8 +1231,8 @@ github.com/mandelsoft/logging v0.0.0-20221114215048-ab754b164dd6/go.mod h1:vxGpz github.com/mandelsoft/spiff v1.7.0-beta-3 h1:AvZldpnctpyfQqtAA5uxokD5rlCK52mGAXxg7tnW5Ag= github.com/mandelsoft/spiff v1.7.0-beta-3/go.mod h1:3Kg6qrggWO4oc1k++acd6xhcWisJ2YkzxpVZpuYONGg= github.com/mandelsoft/vfs v0.0.0-20201002080026-d03d33d5889a/go.mod h1:74aV7kulg9C434HiI3zNALN79QHc9IZMN+SI4UdLn14= -github.com/mandelsoft/vfs v0.0.0-20220805210647-bf14a11bfe31 h1:5gmUtnP0NYOODvS/gTeQOJKSu4W8bOUImDiKdAb/j1A= -github.com/mandelsoft/vfs v0.0.0-20220805210647-bf14a11bfe31/go.mod h1:74aV7kulg9C434HiI3zNALN79QHc9IZMN+SI4UdLn14= +github.com/mandelsoft/vfs v0.0.0-20230714093241-d557f163aecd h1:bp5Qgw/7gqjGU9jNLCMSCDEGw3r1uIxMju6V+F18GbY= +github.com/mandelsoft/vfs v0.0.0-20230714093241-d557f163aecd/go.mod h1:k83vb5I4cqRGJh3TUUVbf2oTF8FrYhvixQ+FwIAgP1Y= github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/markbates/errx v1.1.0 h1:QDFeR+UP95dO12JgW+tgi2UVfo0V8YBHiUIOaeBPiEI= github.com/markbates/errx v1.1.0/go.mod h1:PLa46Oex9KNbVDZhKel8v1OT7hD5JZ2eI7AHhA0wswc= @@ -1886,8 +1886,8 @@ golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU= -golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g= -golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0= +golang.org/x/crypto v0.10.0 h1:LKqV2xt9+kDzSTfOhx4FrkEBcMrAgHSYgzywV9zcGmM= +golang.org/x/crypto v0.10.0/go.mod h1:o4eNf7Ede1fv+hwOwZsTHl9EsPFO6q6ZvYR8vYfY45I= golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= @@ -2024,8 +2024,8 @@ golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.11.0 h1:Gi2tvZIJyBtO9SDr1q9h5hEQCp/4L2RQ+ar0qjx2oNU= +golang.org/x/net v0.11.0/go.mod h1:2L/ixqYpgIVXmeoSA/4Lu7BzTG4KIyPIryS4IsOd1oQ= golang.org/x/oauth2 v0.0.0-20180227000427-d7d64896b5ff/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -2198,8 +2198,8 @@ golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.9.0 h1:KS/R3tvhPqvJvwcKfnBHJwwthS11LRhmM5D59eEXa0s= +golang.org/x/sys v0.9.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -2210,8 +2210,8 @@ golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc= golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U= -golang.org/x/term v0.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols= -golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= +golang.org/x/term v0.9.0 h1:GRRCnKYhdQrD8kfRAdQ6Zcw1P0OcELxGLKJvtjVMZ28= +golang.org/x/term v0.9.0/go.mod h1:M6DEAAIenWoTxdKrOltXcmDY3rSplQUkrvaDU5FcQyo= golang.org/x/text v0.0.0-20160726164857-2910a502d2bf/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -2226,8 +2226,8 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= -golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE= -golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= +golang.org/x/text v0.10.0 h1:UpjohKhiEgNc0CSauXmwYftY1+LlaC75SJwh0SgCX58= +golang.org/x/text v0.10.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/pkg/module/kubebuilder/project.go b/pkg/module/kubebuilder/project.go index 11bf057da..835c0a6c3 100644 --- a/pkg/module/kubebuilder/project.go +++ b/pkg/module/kubebuilder/project.go @@ -18,7 +18,6 @@ const ( V4alpha = "go.kubebuilder.io/v4-alpha" projectFile = "PROJECT" - configFile = "config.yaml" defaultKustomization = "config/default" samplesPath = "config/samples/" OutputPath = "manifests" @@ -88,18 +87,6 @@ func (p *Project) Build(name string) (string, error) { return renderedManifestPath, nil } -func (p *Project) Config() (string, error) { - configPath := filepath.Join(p.path, configFile) - info, err := os.Stat(configPath) - if err != nil { - return "", err - } - if info.IsDir() { - return "", fmt.Errorf("expected file but found directory at %q", configPath) - } - return configPath, nil -} - // DefaultCR checks the samples of the project to obtain the default CR for the operator and returns its contents. // Should there be several sample files, the user will be asked to specify which one to use. func (p *Project) DefaultCR(s step.Step) ([]byte, error) { diff --git a/pkg/module/resources.go b/pkg/module/resources.go index 60e2420e5..407e71dcb 100644 --- a/pkg/module/resources.go +++ b/pkg/module/resources.go @@ -234,17 +234,6 @@ func inspectProject(def *Definition, p *kubebuilder.Project, layers []Layer, s s return err } - // config.yaml -> layer 2 - if configPath, err := p.Config(); err == nil { - def.Layers = append(def.Layers, Layer{ - name: configLayerName, - resourceType: typeYaml, - path: configPath, - }) - } else if !errors.Is(err, os.ErrNotExist) { - return fmt.Errorf("error while determining config layer: %w", err) - } - // Add default CR if generating template var cr []byte if def.RegistryURL != "" { diff --git a/pkg/module/validation.go b/pkg/module/validation.go index 91dab4396..c13cc9b13 100644 --- a/pkg/module/validation.go +++ b/pkg/module/validation.go @@ -10,10 +10,9 @@ import ( "strings" "time" - "github.com/kyma-project/cli/pkg/module/kubebuilder" - setup "github.com/kyma-project/cli/internal/cli/setup/envtest" "github.com/kyma-project/cli/internal/kube" + "github.com/kyma-project/cli/pkg/module/kubebuilder" "go.uber.org/zap" "gopkg.in/yaml.v3" amv "k8s.io/apimachinery/pkg/util/validation" @@ -24,6 +23,7 @@ var ErrEmptyCR = errors.New("provided CR is empty") type DefaultCRValidator struct { crdSearchDir string crData []byte + crd []byte } func NewDefaultCRValidator(cr []byte, modulePath string) *DefaultCRValidator { @@ -51,13 +51,14 @@ func (v *DefaultCRValidator) Run(ctx context.Context, log *zap.SugaredLogger) er } // find the file containing the CRD for given group and kind - crdFound, crdFilePath, err := findCRDFileFor(group, kind, v.crdSearchDir) + crd, crdFilePath, err := findCRDFileFor(group, kind, v.crdSearchDir) if err != nil { return fmt.Errorf("error finding CRD file in the %q directory: %w", v.crdSearchDir, err) } - if !crdFound { + if crd == nil { return fmt.Errorf("can't find the CRD for (group: %q, kind %q)", group, kind) } + v.crd = crd return runTestEnv(ctx, log, crdFilePath, crMap) } @@ -200,42 +201,43 @@ func renderYamlFromMap(modelMap map[string]interface{}) ([]byte, error) { } // findCRDFileFor returns path to the file with a CRD definition for the given group and kind, if exists. -// It looks in the dirPath directory and all of its subdirectories, recursively. The first parameter is true if the file is found, it's false otherwise. -func findCRDFileFor(group, kind, dirPath string) (bool, string, error) { +// It looks in the dirPath directory and all of its subdirectories, recursively. +func findCRDFileFor(group, kind, dirPath string) ([]byte, string, error) { //list all files in the dirPath and all it's subdirectories, recursively files, err := listFiles(dirPath) if err != nil { - return false, "", fmt.Errorf("error listing files in %q directory: %w", dirPath, err) + return nil, "", fmt.Errorf("error listing files in %q directory: %w", dirPath, err) } var found string + var crd []byte for _, f := range files { - ok, err := isCRDFileFor(group, kind, f) + crd, err = getCRDFileFor(group, kind, f) if err != nil { //Error is expected. Either the file is not YAML, or it's not a CRD, or it's a CRD but not the one we're looking for. continue } - if ok { + if crd != nil { found = f break } } if found != "" { - return true, found, nil + return crd, found, nil } - return false, "", nil + return nil, "", nil } -// isCRDFileFor checks if the given file is a CRD for given group and kind. -func isCRDFileFor(group, kind, filePath string) (bool, error) { +// getCRDFileFor returns the crd if the given file is a CRD for given group and kind. +func getCRDFileFor(group, kind, filePath string) ([]byte, error) { res, err := getCRDFromFile(group, kind, filePath) if err != nil { - return false, err + return nil, err } - return res != nil, nil + return res, nil } // getCRDFromFile tries to find a CRD for given group and kind in the given multi-document YAML file. Returns a generic map representation of the CRD @@ -354,6 +356,7 @@ func ValidateName(name string) error { type SingleManifestFileCRValidator struct { manifestPath string crData []byte + crd []byte } func NewSingleManifestFileCRValidator(cr []byte, manifestPath string) *SingleManifestFileCRValidator { @@ -387,6 +390,7 @@ func (v *SingleManifestFileCRValidator) Run(ctx context.Context, log *zap.Sugare if crdBytes == nil { return fmt.Errorf("can't find the CRD for (group: %q, kind %q)", group, kind) } + v.crd = crdBytes // store extracted CRD in a temp file tempDir, err := os.MkdirTemp("", "temporary-crd") @@ -408,3 +412,11 @@ func (v *SingleManifestFileCRValidator) Run(ctx context.Context, log *zap.Sugare // run testEnv using the temporary file with extracted CRD return runTestEnv(ctx, log, tempCRDFile, crMap) } + +func (v *SingleManifestFileCRValidator) GetCrd() []byte { + return v.crd +} + +func (v *DefaultCRValidator) GetCrd() []byte { + return v.crd +}