diff --git a/Makefile b/Makefile index 74e1325..c8cf8b6 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,11 @@ build: export CGO_ENABLED=0 && \ go build -o bin/${HELM_PLUGIN_NAME} -ldflags $(LDFLAGS) ./cmd/mapkubeapis +.PHONY: converter +converter: + export CGO_ENABLED=0 && \ + go build -o bin/converter ./cmd/converter + .PHONY: bootstrap bootstrap: export GO111MODULE=on && \ diff --git a/README.md b/README.md index 8ef1b8f..2501cb3 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ > Note: Charts need to be updated also to supported Kubernetes APIs to avoid failure during deployment in a Kubernetes version. This is a separate task to the plugin. +> Note: The mapfile format has changed from the previous release. The new format is more resilient to changes in spacing and ordering of the Helm release metadata. The new format is described in the [API Mapping](#api-mapping) section. A converter has been provided to convert the old format to the new format. The converter may be found in the `cmd/converter` directory, built via `make converter`, and ran via `./bin/converter`. + ## Prerequisite - Helm client with `mapkubeapis` plugin installed on the same system @@ -95,10 +97,14 @@ kind: ClusterRoleBinding The mapping information of deprecated or removed APIs to supported APIs is configured in the [Map.yaml](https://github.com/helm/helm-mapkubeapis/blob/master/config/Map.yaml) file. The file is a list of entries similar to the following: ```yaml - - deprecatedAPI: "apiVersion: extensions/v1beta1\nkind: Deployment" - newAPI: "apiVersion: apps/v1\nkind: Deployment" - deprecatedInVersion: "v1.9" - removedInVersion: "v1.16" +- deprecatedAPI: + apiVersion: extensions/v1beta1 + kind: Deployment +newAPI: + apiVersion: apps/v1 + kind: Deployment +deprecatedInVersion: "v1.9" +removedInVersion: "v1.16" ``` The plugin when performing update of a Helm release metadata first loads the map file from the `config` directory where the plugin is run from. If the map file is a different name or in a different location, you can use the `--mapfile` flag to specify the different mapping file. diff --git a/cmd/converter/main.go b/cmd/converter/main.go new file mode 100644 index 0000000..8a6a748 --- /dev/null +++ b/cmd/converter/main.go @@ -0,0 +1,81 @@ +package main + +import ( + "fmt" + "os" + "strings" + + "github.com/helm/helm-mapkubeapis/pkg/common" + "github.com/helm/helm-mapkubeapis/pkg/mapping" + "sigs.k8s.io/yaml" +) + +func readConfig(f string) ([]common.GenericYAML, error) { + b, err := os.ReadFile(f) + if err != nil { + return nil, err + } + return common.ParseYAML(string(b)) +} + +func exitOnError(err error) { + if err != nil { + _, _ = os.Stderr.WriteString(err.Error() + "\n") + os.Exit(1) + } +} + +func main() { + var config string + if len(os.Args) == 1 || strings.HasPrefix(os.Args[1], "-h") || strings.HasPrefix(os.Args[1], "--h") { + _, _ = os.Stdout.WriteString("Usage: " + os.Args[0] + " [file]\n") + os.Exit(0) + } + config = os.Args[1] + input, err := readConfig(config) + exitOnError(err) + var mappings []any + if v, ok := input[0]["mappings"].([]any); ok { + mappings = v + } + if len(mappings) == 0 { + exitOnError(fmt.Errorf("failed to read mappings")) + } + var output mapping.Metadata + var m common.GenericYAML + var s string + var ok bool + for _, val := range mappings { + var om mapping.Mapping + if m, ok = val.(common.GenericYAML); !ok { + continue // skip invalid mappings + } + if s, ok = m["deprecatedAPI"].(string); ok { + apiVersion, kind := parseAPIString(s) + if apiVersion == "" || kind == "" { + continue // skip invalid mappings + } + om.DeprecatedAPI.APIVersion = apiVersion + om.DeprecatedAPI.Kind = kind + } + if s, ok = m["newAPI"].(string); ok { + apiVersion, kind := parseAPIString(s) + if apiVersion == "" || kind == "" { + continue // skip invalid mappings + } + om.NewAPI.APIVersion = apiVersion + om.NewAPI.Kind = kind + } + if s, ok = m["deprecatedInVersion"].(string); ok { + om.DeprecatedInVersion = s + } + if s, ok = m["removedInVersion"].(string); ok { + om.RemovedInVersion = s + } + output.Mappings = append(output.Mappings, &om) + } + var b []byte + b, err = yaml.Marshal(output) + exitOnError(err) + _, _ = os.Stdout.Write(b) +} diff --git a/cmd/converter/parse.go b/cmd/converter/parse.go new file mode 100644 index 0000000..1556370 --- /dev/null +++ b/cmd/converter/parse.go @@ -0,0 +1,33 @@ +package main + +import "strings" + +const ( + apiVersionLabel = "apiVersion:" + kindLabel = "kind:" + apiVersionLabelSize = len(apiVersionLabel) + kindLabelSize = len(kindLabel) +) + +// parseAPIString parses the API string into version and kind components +func parseAPIString(apiString string) (version, kind string) { + idx := strings.Index(apiString, apiVersionLabel) + if idx != -1 { + temps := apiString[idx+apiVersionLabelSize:] + idx = strings.Index(temps, "\n") + if idx != -1 { + temps = temps[:idx] + version = strings.TrimSpace(temps) + } + } + idx = strings.Index(apiString, kindLabel) + if idx != -1 { + temps := apiString[idx+kindLabelSize:] + idx = strings.Index(temps, "\n") + if idx != -1 { + temps = temps[:idx] + kind = strings.TrimSpace(temps) + } + } + return version, kind +} diff --git a/config/Map.yaml b/config/Map.yaml index 7379440..adae2a4 100644 --- a/config/Map.yaml +++ b/config/Map.yaml @@ -1,235 +1,472 @@ mappings: - - deprecatedAPI: "apiVersion: extensions/v1beta1\nkind: Deployment\n" - newAPI: "apiVersion: apps/v1\nkind: Deployment\n" - deprecatedInVersion: "v1.9" - removedInVersion: "v1.16" - - deprecatedAPI: "apiVersion: apps/v1beta1\nkind: Deployment\n" - newAPI: "apiVersion: apps/v1\nkind: Deployment\n" - deprecatedInVersion: "v1.9" - removedInVersion: "v1.16" - - deprecatedAPI: "apiVersion: apps/v1beta2\nkind: Deployment\n" - newAPI: "apiVersion: apps/v1\nkind: Deployment\n" - deprecatedInVersion: "v1.9" - removedInVersion: "v1.16" - - deprecatedAPI: "apiVersion: apps/v1beta1\nkind: StatefulSet\n" - newAPI: "apiVersion: apps/v1\nkind: StatefulSet\n" - deprecatedInVersion: "v1.9" - removedInVersion: "v1.16" - - deprecatedAPI: "apiVersion: apps/v1beta2\nkind: StatefulSet\n" - newAPI: "apiVersion: apps/v1\nkind: StatefulSet\n" - deprecatedInVersion: "v1.9" - removedInVersion: "v1.16" - - deprecatedAPI: "apiVersion: extensions/v1beta1\nkind: DaemonSet\n" - newAPI: "apiVersion: apps/v1\nkind: DaemonSet\n" - deprecatedInVersion: "v1.9" - removedInVersion: "v1.16" - - deprecatedAPI: "apiVersion: apps/v1beta2\nkind: DaemonSet\n" - newAPI: "apiVersion: apps/v1\nkind: DaemonSet\n" - deprecatedInVersion: "v1.9" - removedInVersion: "v1.16" - - deprecatedAPI: "apiVersion: extensions/v1beta1\nkind: ReplicaSet\n" - newAPI: "apiVersion: apps/v1\nkind: ReplicaSet\n" - deprecatedInVersion: "v1.9" - removedInVersion: "v1.16" - - deprecatedAPI: "apiVersion: apps/v1beta1\nkind: ReplicaSet\n" - newAPI: "apiVersion: apps/v1\nkind: ReplicaSet\n" - deprecatedInVersion: "v1.9" - removedInVersion: "v1.16" - - deprecatedAPI: "apiVersion: apps/v1beta2\nkind: ReplicaSet\n" - newAPI: "apiVersion: apps/v1\nkind: ReplicaSet\n" - deprecatedInVersion: "v1.9" - removedInVersion: "v1.16" - - deprecatedAPI: "apiVersion: extensions/v1beta1\nkind: NetworkPolicy\n" - newAPI: "apiVersion: networking.k8s.io/v1\nkind: NetworkPolicy\n" - deprecatedInVersion: "v1.8" - removedInVersion: "v1.16" - - deprecatedAPI: "apiVersion: extensions/v1beta1\nkind: PodSecurityPolicy\n" - newAPI: "apiVersion: policy/v1beta1\nkind: PodSecurityPolicy\n" - deprecatedInVersion: "v1.10" - removedInVersion: "v1.16" - - deprecatedAPI: "apiVersion: admissionregistration.k8s.io/v1beta1\nkind: MutatingWebhookConfiguration\n" - newAPI: "apiVersion: admissionregistration.k8s.io/v1\nkind: MutatingWebhookConfiguration\n" - deprecatedInVersion: "v1.16" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: admissionregistration.k8s.io/v1beta1\nkind: ValidatingWebhookConfiguration\n" - newAPI: "apiVersion: admissionregistration.k8s.io/v1\nkind: ValidatingWebhookConfiguration\n" - deprecatedInVersion: "v1.16" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: apiextensions.k8s.io/v1beta1\nkind: CustomResourceDefinition\n" - newAPI: "apiVersion: apiextensions.k8s.io/v1\nkind: CustomResourceDefinition\n" - deprecatedInVersion: "v1.16" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: apiregistration.k8s.io/v1beta1\nkind: APIService\n" - newAPI: "apiVersion: apiregistration.k8s.io/v1\nkind: APIService\n" - deprecatedInVersion: "v1.19" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: apiregistration.k8s.io/v1beta1\nkind: APIServiceList\n" - newAPI: "apiVersion: apiregistration.k8s.io/v1\nkind: APIServiceList\n" - deprecatedInVersion: "v1.19" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: authentication.k8s.io/v1beta1\nkind: TokenReview\n" - newAPI: "apiVersion: authentication.k8s.io/v1\nkind: TokenReview\n" - deprecatedInVersion: "v1.16" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: authorization.k8s.io/v1beta1\nkind: LocalSubjectAccessReview\n" - newAPI: "apiVersion: authorization.k8s.io/v1\nkind: LocalSubjectAccessReview\n" - deprecatedInVersion: "v1.16" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: authorization.k8s.io/v1beta1\nkind: SelfSubjectAccessReview\n" - newAPI: "apiVersion: authorization.k8s.io/v1\nkind: SelfSubjectAccessReview\n" - deprecatedInVersion: "v1.16" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: authorization.k8s.io/v1beta1\nkind: SubjectAccessReview\n" - newAPI: "apiVersion: authorization.k8s.io/v1\nkind: SubjectAccessReview\n" - deprecatedInVersion: "v1.16" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: autoscaling/v2beta1\nkind: HorizontalPodAutoscaler\n" - newAPI: "apiVersion: autoscaling/v2\nkind: HorizontalPodAutoscaler\n" - deprecatedInVersion: "v1.23" - removedInVersion: "v1.25" - - deprecatedAPI: "apiVersion: autoscaling/v2beta2\nkind: HorizontalPodAutoscaler\n" - newAPI: "apiVersion: autoscaling/v2\nkind: HorizontalPodAutoscaler\n" - deprecatedInVersion: "v1.23" - removedInVersion: "v1.26" - - deprecatedAPI: "apiVersion: batch/v1beta1\nkind: CronJob\n" - newAPI: "apiVersion: batch/v1\nkind: CronJob\n" - deprecatedInVersion: "v1.21" - removedInVersion: "v1.25" - - deprecatedAPI: "apiVersion: certificates.k8s.io/v1beta1\nkind: CertificateSigningRequest\n" - newAPI: "apiVersion: certificates.k8s.io/v1\nkind: CertificateSigningRequest\n" - deprecatedInVersion: "v1.19" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: coordination.k8s.io/v1beta1\nkind: Lease\n" - newAPI: "apiVersion: coordination.k8s.io/v1\nkind: Lease\n" - deprecatedInVersion: "v1.14" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: extensions/v1beta1\nkind: Ingress\n" - newAPI: "apiVersion: networking.k8s.io/v1beta1\nkind: Ingress\n" - deprecatedInVersion: "v1.14" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: networking.k8s.io/v1beta1\nkind: Ingress\n" - newAPI: "apiVersion: networking.k8s.io/v1\nkind: Ingress\n" - deprecatedInVersion: "v1.19" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: networking.k8s.io/v1beta1\nkind: IngressClass\n" - newAPI: "apiVersion: networking.k8s.io/v1\nkind: IngressClass\n" - deprecatedInVersion: "v1.19" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: policy/v1beta1\nkind: PodDisruptionBudget\n" - newAPI: "apiVersion: policy/v1\nkind: PodDisruptionBudget\n" - deprecatedInVersion: "v1.21" - removedInVersion: "v1.25" - - deprecatedAPI: "apiVersion: policy/v1beta1\nkind: PodSecurityPolicy\n" - removedInVersion: "v1.25" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1alpha1\nkind: ClusterRole\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1alpha1\nkind: ClusterRoleList\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleList\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1alpha1\nkind: ClusterRoleBinding\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1alpha1\nkind: ClusterRoleBindingList\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBindingList\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1alpha1\nkind: Role\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: Role\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1alpha1\nkind: RoleList\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: RoleList\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1alpha1\nkind: RoleBinding\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1alpha1\nkind: RoleBindingList\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBindingList\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRole\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRole\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRoleList\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleList\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRoleBinding\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBinding\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1beta1\nkind: ClusterRoleBindingList\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: ClusterRoleBindingList\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1beta1\nkind: Role\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: Role\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1beta1\nkind: RoleList\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: RoleList\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1beta1\nkind: RoleBinding\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBinding\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: rbac.authorization.k8s.io/v1beta1\nkind: RoleBindingList\n" - newAPI: "apiVersion: rbac.authorization.k8s.io/v1\nkind: RoleBindingList\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: scheduling.k8s.io/v1beta1\nkind: PriorityClass\n" - newAPI: "apiVersion: scheduling.k8s.io/v1\nkind: PriorityClass\n" - deprecatedInVersion: "v1.14" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: storage.k8s.io/v1beta1\nkind: CSIDriver\n" - newAPI: "apiVersion: storage.k8s.io/v1\nkind: CSIDriver\n" - deprecatedInVersion: "v1.19" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: storage.k8s.io/v1beta1\nkind: CSINode\n" - newAPI: "apiVersion: storage.k8s.io/v1\nkind: CSINode\n" - deprecatedInVersion: "v1.17" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: storage.k8s.io/v1beta1\nkind: StorageClass\n" - newAPI: "apiVersion: storage.k8s.io/v1\nkind: StorageClass\n" - deprecatedInVersion: "v1.16" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: storage.k8s.io/v1beta1\nkind: VolumeAttachment\n" - newAPI: "apiVersion: storage.k8s.io/v1\nkind: VolumeAttachment\n" - deprecatedInVersion: "v1.13" - removedInVersion: "v1.22" - - deprecatedAPI: "apiVersion: storage.k8s.io/v1beta1\nkind: CSIStorageCapacity\n" - newAPI: "apiVersion: storage.k8s.io/v1\nkind: CSIStorageCapacity\n" - deprecatedInVersion: "v1.24" - removedInVersion: "v1.27" - - deprecatedAPI: "apiVersion: flowcontrol.apiserver.k8s.io/v1beta1\nkind: FlowSchema\n" - newAPI: "apiVersion: flowcontrol.apiserver.k8s.io/v1beta3\nkind: FlowSchema\n" - deprecatedInVersion: "v1.26" - removedInVersion: "v1.26" - - deprecatedAPI: "apiVersion: flowcontrol.apiserver.k8s.io/v1beta2\nkind: FlowSchema\n" - newAPI: "apiVersion: flowcontrol.apiserver.k8s.io/v1beta3\nkind: FlowSchema\n" - deprecatedInVersion: "v1.26" - removedInVersion: "v1.29" - - deprecatedAPI: "apiVersion: flowcontrol.apiserver.k8s.io/v1beta3\nkind: FlowSchema\n" - newAPI: "apiVersion: flowcontrol.apiserver.k8s.io/v1\nkind: FlowSchema\n" - deprecatedInVersion: "v1.29" - removedInVersion: "v1.32" - - deprecatedAPI: "apiVersion: flowcontrol.apiserver.k8s.io/v1beta1\nkind: PriorityLevelConfiguration\n" - newAPI: "apiVersion: flowcontrol.apiserver.k8s.io/v1beta3\nkind: PriorityLevelConfiguration\n" - deprecatedInVersion: "v1.26" - removedInVersion: "v1.26" - - deprecatedAPI: "apiVersion: flowcontrol.apiserver.k8s.io/v1beta2\nkind: PriorityLevelConfiguration\n" - newAPI: "apiVersion: flowcontrol.apiserver.k8s.io/v1beta3\nkind: PriorityLevelConfiguration\n" - deprecatedInVersion: "v1.26" - removedInVersion: "v1.29" - - deprecatedAPI: "apiVersion: flowcontrol.apiserver.k8s.io/v1beta3\nkind: PriorityLevelConfiguration\n" - newAPI: "apiVersion: flowcontrol.apiserver.k8s.io/v1\nkind: PriorityLevelConfiguration\n" - deprecatedInVersion: "v1.29" - removedInVersion: "v1.32" \ No newline at end of file +- deprecatedAPI: + apiVersion: extensions/v1beta1 + kind: Deployment + deprecatedInVersion: v1.9 + newAPI: + apiVersion: apps/v1 + kind: Deployment + removedInVersion: v1.16 +- deprecatedAPI: + apiVersion: apps/v1beta1 + kind: Deployment + deprecatedInVersion: v1.9 + newAPI: + apiVersion: apps/v1 + kind: Deployment + removedInVersion: v1.16 +- deprecatedAPI: + apiVersion: apps/v1beta2 + kind: Deployment + deprecatedInVersion: v1.9 + newAPI: + apiVersion: apps/v1 + kind: Deployment + removedInVersion: v1.16 +- deprecatedAPI: + apiVersion: apps/v1beta1 + kind: StatefulSet + deprecatedInVersion: v1.9 + newAPI: + apiVersion: apps/v1 + kind: StatefulSet + removedInVersion: v1.16 +- deprecatedAPI: + apiVersion: apps/v1beta2 + kind: StatefulSet + deprecatedInVersion: v1.9 + newAPI: + apiVersion: apps/v1 + kind: StatefulSet + removedInVersion: v1.16 +- deprecatedAPI: + apiVersion: extensions/v1beta1 + kind: DaemonSet + deprecatedInVersion: v1.9 + newAPI: + apiVersion: apps/v1 + kind: DaemonSet + removedInVersion: v1.16 +- deprecatedAPI: + apiVersion: apps/v1beta2 + kind: DaemonSet + deprecatedInVersion: v1.9 + newAPI: + apiVersion: apps/v1 + kind: DaemonSet + removedInVersion: v1.16 +- deprecatedAPI: + apiVersion: extensions/v1beta1 + kind: ReplicaSet + deprecatedInVersion: v1.9 + newAPI: + apiVersion: apps/v1 + kind: ReplicaSet + removedInVersion: v1.16 +- deprecatedAPI: + apiVersion: apps/v1beta1 + kind: ReplicaSet + deprecatedInVersion: v1.9 + newAPI: + apiVersion: apps/v1 + kind: ReplicaSet + removedInVersion: v1.16 +- deprecatedAPI: + apiVersion: apps/v1beta2 + kind: ReplicaSet + deprecatedInVersion: v1.9 + newAPI: + apiVersion: apps/v1 + kind: ReplicaSet + removedInVersion: v1.16 +- deprecatedAPI: + apiVersion: extensions/v1beta1 + kind: NetworkPolicy + deprecatedInVersion: v1.8 + newAPI: + apiVersion: networking.k8s.io/v1 + kind: NetworkPolicy + removedInVersion: v1.16 +- deprecatedAPI: + apiVersion: extensions/v1beta1 + kind: PodSecurityPolicy + deprecatedInVersion: v1.10 + newAPI: + apiVersion: policy/v1beta1 + kind: PodSecurityPolicy + removedInVersion: v1.16 +- deprecatedAPI: + apiVersion: admissionregistration.k8s.io/v1beta1 + kind: MutatingWebhookConfiguration + deprecatedInVersion: v1.16 + newAPI: + apiVersion: admissionregistration.k8s.io/v1 + kind: MutatingWebhookConfiguration + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: admissionregistration.k8s.io/v1beta1 + kind: ValidatingWebhookConfiguration + deprecatedInVersion: v1.16 + newAPI: + apiVersion: admissionregistration.k8s.io/v1 + kind: ValidatingWebhookConfiguration + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: apiextensions.k8s.io/v1beta1 + kind: CustomResourceDefinition + deprecatedInVersion: v1.16 + newAPI: + apiVersion: apiextensions.k8s.io/v1 + kind: CustomResourceDefinition + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: apiregistration.k8s.io/v1beta1 + kind: APIService + deprecatedInVersion: v1.19 + newAPI: + apiVersion: apiregistration.k8s.io/v1 + kind: APIService + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: apiregistration.k8s.io/v1beta1 + kind: APIServiceList + deprecatedInVersion: v1.19 + newAPI: + apiVersion: apiregistration.k8s.io/v1 + kind: APIServiceList + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: authentication.k8s.io/v1beta1 + kind: TokenReview + deprecatedInVersion: v1.16 + newAPI: + apiVersion: authentication.k8s.io/v1 + kind: TokenReview + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: authorization.k8s.io/v1beta1 + kind: LocalSubjectAccessReview + deprecatedInVersion: v1.16 + newAPI: + apiVersion: authorization.k8s.io/v1 + kind: LocalSubjectAccessReview + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: authorization.k8s.io/v1beta1 + kind: SelfSubjectAccessReview + deprecatedInVersion: v1.16 + newAPI: + apiVersion: authorization.k8s.io/v1 + kind: SelfSubjectAccessReview + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: authorization.k8s.io/v1beta1 + kind: SubjectAccessReview + deprecatedInVersion: v1.16 + newAPI: + apiVersion: authorization.k8s.io/v1 + kind: SubjectAccessReview + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: autoscaling/v2beta1 + kind: HorizontalPodAutoscaler + deprecatedInVersion: v1.23 + newAPI: + apiVersion: autoscaling/v2 + kind: HorizontalPodAutoscaler + removedInVersion: v1.25 +- deprecatedAPI: + apiVersion: autoscaling/v2beta2 + kind: HorizontalPodAutoscaler + deprecatedInVersion: v1.23 + newAPI: + apiVersion: autoscaling/v2 + kind: HorizontalPodAutoscaler + removedInVersion: v1.26 +- deprecatedAPI: + apiVersion: batch/v1beta1 + kind: CronJob + deprecatedInVersion: v1.21 + newAPI: + apiVersion: batch/v1 + kind: CronJob + removedInVersion: v1.25 +- deprecatedAPI: + apiVersion: certificates.k8s.io/v1beta1 + kind: CertificateSigningRequest + deprecatedInVersion: v1.19 + newAPI: + apiVersion: certificates.k8s.io/v1 + kind: CertificateSigningRequest + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: coordination.k8s.io/v1beta1 + kind: Lease + deprecatedInVersion: v1.14 + newAPI: + apiVersion: coordination.k8s.io/v1 + kind: Lease + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: extensions/v1beta1 + kind: Ingress + deprecatedInVersion: v1.14 + newAPI: + apiVersion: networking.k8s.io/v1beta1 + kind: Ingress + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: networking.k8s.io/v1beta1 + kind: Ingress + deprecatedInVersion: v1.19 + newAPI: + apiVersion: networking.k8s.io/v1 + kind: Ingress + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: networking.k8s.io/v1beta1 + kind: IngressClass + deprecatedInVersion: v1.19 + newAPI: + apiVersion: networking.k8s.io/v1 + kind: IngressClass + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: policy/v1beta1 + kind: PodDisruptionBudget + deprecatedInVersion: v1.21 + newAPI: + apiVersion: policy/v1 + kind: PodDisruptionBudget + removedInVersion: v1.25 +- deprecatedAPI: + apiVersion: policy/v1beta1 + kind: PodSecurityPolicy + newAPI: + apiVersion: "" + kind: "" + removedInVersion: v1.25 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1alpha1 + kind: ClusterRole + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1alpha1 + kind: ClusterRoleList + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleList + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1alpha1 + kind: ClusterRoleBinding + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1alpha1 + kind: ClusterRoleBindingList + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBindingList + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1alpha1 + kind: Role + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1alpha1 + kind: RoleList + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleList + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1alpha1 + kind: RoleBinding + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1alpha1 + kind: RoleBindingList + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBindingList + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1beta1 + kind: ClusterRole + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRole + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1beta1 + kind: ClusterRoleList + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleList + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1beta1 + kind: ClusterRoleBinding + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBinding + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1beta1 + kind: ClusterRoleBindingList + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: ClusterRoleBindingList + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1beta1 + kind: Role + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: Role + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1beta1 + kind: RoleList + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleList + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1beta1 + kind: RoleBinding + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBinding + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: rbac.authorization.k8s.io/v1beta1 + kind: RoleBindingList + deprecatedInVersion: v1.17 + newAPI: + apiVersion: rbac.authorization.k8s.io/v1 + kind: RoleBindingList + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: scheduling.k8s.io/v1beta1 + kind: PriorityClass + deprecatedInVersion: v1.14 + newAPI: + apiVersion: scheduling.k8s.io/v1 + kind: PriorityClass + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: storage.k8s.io/v1beta1 + kind: CSIDriver + deprecatedInVersion: v1.19 + newAPI: + apiVersion: storage.k8s.io/v1 + kind: CSIDriver + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: storage.k8s.io/v1beta1 + kind: CSINode + deprecatedInVersion: v1.17 + newAPI: + apiVersion: storage.k8s.io/v1 + kind: CSINode + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: storage.k8s.io/v1beta1 + kind: StorageClass + deprecatedInVersion: v1.16 + newAPI: + apiVersion: storage.k8s.io/v1 + kind: StorageClass + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: storage.k8s.io/v1beta1 + kind: VolumeAttachment + deprecatedInVersion: v1.13 + newAPI: + apiVersion: storage.k8s.io/v1 + kind: VolumeAttachment + removedInVersion: v1.22 +- deprecatedAPI: + apiVersion: storage.k8s.io/v1beta1 + kind: CSIStorageCapacity + deprecatedInVersion: v1.24 + newAPI: + apiVersion: storage.k8s.io/v1 + kind: CSIStorageCapacity + removedInVersion: v1.27 +- deprecatedAPI: + apiVersion: flowcontrol.apiserver.k8s.io/v1beta1 + kind: FlowSchema + deprecatedInVersion: v1.26 + newAPI: + apiVersion: flowcontrol.apiserver.k8s.io/v1beta3 + kind: FlowSchema + removedInVersion: v1.26 +- deprecatedAPI: + apiVersion: flowcontrol.apiserver.k8s.io/v1beta2 + kind: FlowSchema + deprecatedInVersion: v1.26 + newAPI: + apiVersion: flowcontrol.apiserver.k8s.io/v1beta3 + kind: FlowSchema + removedInVersion: v1.29 +- deprecatedAPI: + apiVersion: flowcontrol.apiserver.k8s.io/v1beta3 + kind: FlowSchema + deprecatedInVersion: v1.29 + newAPI: + apiVersion: flowcontrol.apiserver.k8s.io/v1 + kind: FlowSchema + removedInVersion: v1.32 +- deprecatedAPI: + apiVersion: flowcontrol.apiserver.k8s.io/v1beta1 + kind: PriorityLevelConfiguration + deprecatedInVersion: v1.26 + newAPI: + apiVersion: flowcontrol.apiserver.k8s.io/v1beta3 + kind: PriorityLevelConfiguration + removedInVersion: v1.26 +- deprecatedAPI: + apiVersion: flowcontrol.apiserver.k8s.io/v1beta2 + kind: PriorityLevelConfiguration + deprecatedInVersion: v1.26 + newAPI: + apiVersion: flowcontrol.apiserver.k8s.io/v1beta3 + kind: PriorityLevelConfiguration + removedInVersion: v1.29 +- deprecatedAPI: + apiVersion: flowcontrol.apiserver.k8s.io/v1beta3 + kind: PriorityLevelConfiguration + deprecatedInVersion: v1.29 + newAPI: + apiVersion: flowcontrol.apiserver.k8s.io/v1 + kind: PriorityLevelConfiguration + removedInVersion: v1.32 diff --git a/go.mod b/go.mod index f8f75f6..11822f2 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/pkg/errors v0.9.1 github.com/spf13/cobra v1.9.1 github.com/spf13/pflag v1.0.6 - golang.org/x/mod v0.24.0 + golang.org/x/mod v0.26.0 gopkg.in/yaml.v3 v3.0.1 helm.sh/helm/v3 v3.18.0 k8s.io/client-go v0.33.1 @@ -27,7 +27,7 @@ require ( github.com/asaskevich/govalidator v0.0.0-20230301143203-a9d515a09cc2 // indirect github.com/blang/semver/v4 v4.0.0 // indirect github.com/chai2010/gettext-go v1.0.2 // indirect - github.com/containerd/containerd v1.7.27 // indirect + github.com/containerd/containerd v1.7.29 // indirect github.com/containerd/errdefs v0.3.0 // indirect github.com/containerd/log v0.1.0 // indirect github.com/containerd/platforms v0.2.1 // indirect @@ -96,15 +96,15 @@ require ( github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/xlab/treeprint v1.2.0 // indirect go.uber.org/automaxprocs v1.6.0 // indirect - golang.org/x/crypto v0.37.0 // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/oauth2 v0.28.0 // indirect - golang.org/x/sync v0.14.0 // indirect - golang.org/x/sys v0.33.0 // indirect - golang.org/x/term v0.31.0 // indirect - golang.org/x/text v0.24.0 // indirect - golang.org/x/time v0.9.0 // indirect - golang.org/x/tools v0.31.0 // indirect + golang.org/x/crypto v0.40.0 // indirect + golang.org/x/net v0.42.0 // indirect + golang.org/x/oauth2 v0.30.0 // indirect + golang.org/x/sync v0.16.0 // indirect + golang.org/x/sys v0.34.0 // indirect + golang.org/x/term v0.33.0 // indirect + golang.org/x/text v0.27.0 // indirect + golang.org/x/time v0.12.0 // indirect + golang.org/x/tools v0.34.0 // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20241209162323-e6fa225c2576 // indirect google.golang.org/grpc v1.68.1 // indirect google.golang.org/protobuf v1.36.5 // indirect diff --git a/go.sum b/go.sum index f125b5a..57d7260 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,8 @@ github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UF github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chai2010/gettext-go v1.0.2 h1:1Lwwip6Q2QGsAdl/ZKPCwTe9fe0CjlUbqj5bFNSjIRk= github.com/chai2010/gettext-go v1.0.2/go.mod h1:y+wnP2cHYaVj19NZhYKAwEMH2CI1gNHeQQ+5AjwawxA= -github.com/containerd/containerd v1.7.27 h1:yFyEyojddO3MIGVER2xJLWoCIn+Up4GaHFquP7hsFII= -github.com/containerd/containerd v1.7.27/go.mod h1:xZmPnl75Vc+BLGt4MIfu6bp+fy03gdHAn9bz+FreFR0= +github.com/containerd/containerd v1.7.29 h1:90fWABQsaN9mJhGkoVnuzEY+o1XDPbg9BTC9QTAHnuE= +github.com/containerd/containerd v1.7.29/go.mod h1:azUkWcOvHrWvaiUjSQH0fjzuHIwSPg1WL5PshGP4Szs= github.com/containerd/errdefs v0.3.0 h1:FSZgGOeK4yuT/+DnF07/Olde/q4KBoMsaamhXxIMDp4= github.com/containerd/errdefs v0.3.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= @@ -345,25 +345,25 @@ go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE= -golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc= +golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM= +golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU= -golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww= +golang.org/x/mod v0.26.0 h1:EGMPT//Ezu+ylkCijjPc+f4Aih7sZvaAr+O3EHBxvZg= +golang.org/x/mod v0.26.0/go.mod h1:/j6NAhSk8iQ723BGAUyoAcn7SlD7s15Dp9Nd/SfeaFQ= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/oauth2 v0.28.0 h1:CrgCKl8PPAVtLnU3c+EDw6x11699EWlsDeWNWKdIOkc= -golang.org/x/oauth2 v0.28.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8= +golang.org/x/net v0.42.0 h1:jzkYrhi3YQWD6MLBJcsklgQsoAcw89EcZbJw8Z614hs= +golang.org/x/net v0.42.0/go.mod h1:FF1RA5d3u7nAYA4z2TkclSCKh68eSXtiFwcWQpPXdt8= +golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= +golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.14.0 h1:woo0S4Yywslg6hp4eUFjTVOyKt0RookbpAHG4c1HmhQ= -golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= +golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -373,22 +373,22 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.33.0 h1:q3i8TbbEz+JRD9ywIRlyRAQbM0qF7hu24q3teo2hbuw= -golang.org/x/sys v0.33.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= -golang.org/x/term v0.31.0 h1:erwDkOK1Msy6offm1mOgvspSkslFnIGsFnxOKoufg3o= -golang.org/x/term v0.31.0/go.mod h1:R4BeIy7D95HzImkxGkTW1UQTtP54tio2RyHz7PwK0aw= +golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA= +golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg= +golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= -golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= -golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.27.0 h1:4fGWRpyh641NLlecmyl4LOe6yDdfaYNrGb2zdfo4JV4= +golang.org/x/text v0.27.0/go.mod h1:1D28KMCvyooCX9hBiosv5Tz/+YLxj0j7XhWjpSUF7CU= +golang.org/x/time v0.12.0 h1:ScB/8o8olJvc+CQPWrK3fPZNfh7qgwCrY0zJmoEQLSE= +golang.org/x/time v0.12.0/go.mod h1:CDIdPxbZBQxdj6cxyCIdrNogrJKMJ7pr37NYpMcMDSg= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= -golang.org/x/tools v0.31.0 h1:0EedkvKDbh+qistFTd0Bcwe/YLh4vHwWEkiI0toFIBU= -golang.org/x/tools v0.31.0/go.mod h1:naFTU+Cev749tSJRXJlna0T3WxKvb1kWEx15xA4SdmQ= +golang.org/x/tools v0.34.0 h1:qIpSLOxeCYGg9TrcJokLBG4KFA6d795g0xkBkiESGlo= +golang.org/x/tools v0.34.0/go.mod h1:pAP9OwEaY1CAW3HOmg3hLZC5Z0CCmzjAF2UQMSqNARg= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/pkg/common/common.go b/pkg/common/common.go index cf0cc13..9571f21 100644 --- a/pkg/common/common.go +++ b/pkg/common/common.go @@ -17,16 +17,14 @@ limitations under the License. package common import ( - "log" - "strings" - + "fmt" + "github.com/helm/helm-mapkubeapis/pkg/mapping" "github.com/pkg/errors" "golang.org/x/mod/semver" - - "github.com/helm/helm-mapkubeapis/pkg/mapping" + "log" ) -// KubeConfig are the Kubernetes configurationĀ settings +// KubeConfig are the Kubernetes configuration settings type KubeConfig struct { Context string File string @@ -47,7 +45,7 @@ const UpgradeDescription = "Kubernetes deprecated API upgrade - DO NOT rollback // ReplaceManifestUnSupportedAPIs returns a release manifest with deprecated or removed // Kubernetes APIs updated to supported APIs func ReplaceManifestUnSupportedAPIs(origManifest, mapFile string, kubeConfig KubeConfig, additionalMappings ...*mapping.Mapping) (string, error) { - var modifiedManifest = origManifest + var modifiedManifest string var err error var mapMetadata *mapping.Metadata @@ -68,7 +66,7 @@ func ReplaceManifestUnSupportedAPIs(origManifest, mapFile string, kubeConfig Kub } // Check for deprecated or removed APIs and map accordingly to supported versions - modifiedManifest, err = ReplaceManifestData(mapMetadata, modifiedManifest, kubeVersionStr) + modifiedManifest, err = ReplaceManifestData(mapMetadata, origManifest, kubeVersionStr) if err != nil { return "", err } @@ -79,69 +77,59 @@ func ReplaceManifestUnSupportedAPIs(origManifest, mapFile string, kubeConfig Kub // ReplaceManifestData scans the release manifest string for deprecated APIs in a given Kubernetes version and replaces // their groups and versions if there is a successor, or fully removes the manifest for that specific resource if no // successors exist (such as the PodSecurityPolicy API). -func ReplaceManifestData(mapMetadata *mapping.Metadata, modifiedManifest string, kubeVersionStr string) (string, error) { - for _, mapping := range mapMetadata.Mappings { - deprecatedAPI := mapping.DeprecatedAPI - supportedAPI := mapping.NewAPI - var apiVersionStr string - if mapping.DeprecatedInVersion != "" { - apiVersionStr = mapping.DeprecatedInVersion - } else { - apiVersionStr = mapping.RemovedInVersion +func ReplaceManifestData(mapMetadata *mapping.Metadata, origManifest string, kubeVersionStr string) (string, error) { + yamlDocs, err := ParseYAML(origManifest) + if err != nil { + return "", err + } + for _, m := range mapMetadata.Mappings { + var apiVersionStr = m.RemovedInVersion + if m.DeprecatedInVersion != "" { + apiVersionStr = m.DeprecatedInVersion } if !semver.IsValid(apiVersionStr) { - return "", errors.Errorf("Failed to get the deprecated or removed Kubernetes version for API: %s", strings.ReplaceAll(deprecatedAPI, "\n", " ")) + return "", errors.Errorf("Failed to get the deprecated or removed Kubernetes version for apiVersion: %s kind: %s", + m.DeprecatedAPI.APIVersion, m.DeprecatedAPI.Kind) } - if count := strings.Count(modifiedManifest, deprecatedAPI); count > 0 { - if semver.Compare(apiVersionStr, kubeVersionStr) > 0 { - log.Printf("The following API:\n\"%s\" does not require mapping as the "+ - "API is not deprecated or removed in Kubernetes \"%s\"\n", deprecatedAPI, kubeVersionStr) - // skip to next mapping - continue + var count = 0 + docLoop: + for idx, doc := range yamlDocs { + version, _ := doc["apiVersion"].(string) + kind, _ := doc["kind"].(string) + if version == m.DeprecatedAPI.APIVersion && kind == m.DeprecatedAPI.Kind { + fmt.Printf("Found deprecated or removed Kubernetes version for API: %s %s\n", + m.DeprecatedAPI.APIVersion, m.DeprecatedAPI.Kind) + fmt.Println("original: ", doc) + if semver.Compare(apiVersionStr, kubeVersionStr) > 0 { + log.Printf("The following API:\n\"%s\" does not require mapping as the "+ + "API is not deprecated or removed in Kubernetes \"%s\"\n", m.DeprecatedAPI.APIVersion, kubeVersionStr) + // skip to next mapping + break docLoop + } + count++ + if m.NewAPI.APIVersion != "" { + doc["apiVersion"] = m.NewAPI.APIVersion + doc["kind"] = m.NewAPI.Kind + fmt.Println("modified: ", doc) + } else { + yamlDocs = append(yamlDocs[:idx], yamlDocs[idx+1:]...) + fmt.Println("deleted doc without replacement") + } } - if supportedAPI == "" { - log.Printf("Found %d instances of deprecated or removed Kubernetes API:\n\"%s\"\nNo supported API equivalent\n", count, deprecatedAPI) - modifiedManifest = removeDeprecatedAPIWithoutSuccessor(count, deprecatedAPI, modifiedManifest) + } + if count > 0 { + if m.NewAPI.APIVersion == "" { + log.Printf("Found %d instances of deprecated or removed Kubernetes API:\n\"%s\"\nNo supported API equivalent\n", + count, m.DeprecatedAPI.APIVersion) } else { - log.Printf("Found %d instances of deprecated or removed Kubernetes API:\n\"%s\"\nSupported API equivalent:\n\"%s\"\n", count, deprecatedAPI, supportedAPI) - modifiedManifest = strings.ReplaceAll(modifiedManifest, deprecatedAPI, supportedAPI) + log.Printf("Found %d instances of deprecated or removed Kubernetes API:\n\"%s\"\nSupported API equivalent:\n\"%s\"\n", + count, m.DeprecatedAPI.APIVersion, m.NewAPI.APIVersion) } } } - return modifiedManifest, nil -} - -// removeDeprecatedAPIWithoutSuccessor removes a deprecated API that has no successor specified in the mapping file. -func removeDeprecatedAPIWithoutSuccessor(count int, deprecatedAPI string, modifiedManifest string) string { - for repl := 0; repl < count; repl++ { - // find the position where the API header is - apiIndex := strings.Index(modifiedManifest, deprecatedAPI) - - // find the next separator index - separatorIndex := strings.Index(modifiedManifest[apiIndex:], "---\n") - - // find the previous separator index - previousSeparatorIndex := strings.LastIndex(modifiedManifest[:apiIndex], "---\n") - - /* - * if no previous separator index was found, it means the resource is at the beginning and not - * prefixed by --- - */ - if previousSeparatorIndex == -1 { - previousSeparatorIndex = 0 - } - - if separatorIndex == -1 { // this means we reached the end of input - modifiedManifest = modifiedManifest[:previousSeparatorIndex] - } else { - modifiedManifest = modifiedManifest[:previousSeparatorIndex] + modifiedManifest[separatorIndex+apiIndex:] - } - } - - modifiedManifest = strings.Trim(modifiedManifest, "\n") - return modifiedManifest + return EncodeYAML(yamlDocs) } func getKubernetesServerVersion(kubeConfig KubeConfig) (string, error) { diff --git a/pkg/common/common_test.go b/pkg/common/common_test.go index a5a7a9c..f5e2cf9 100644 --- a/pkg/common/common_test.go +++ b/pkg/common/common_test.go @@ -1,14 +1,10 @@ package common_test import ( - "bytes" - "github.com/helm/helm-mapkubeapis/pkg/common" - "github.com/helm/helm-mapkubeapis/pkg/mapping" - "github.com/pkg/errors" - "gopkg.in/yaml.v3" - "io" "testing" + "github.com/helm/helm-mapkubeapis/pkg/common" + "github.com/helm/helm-mapkubeapis/pkg/mapping" "github.com/onsi/ginkgo/v2" "github.com/onsi/gomega" ) @@ -21,43 +17,49 @@ func TestCommon(t *testing.T) { // CheckDecode verifies that the passed YAML is parsing correctly // It doesn't check semantic correctness func CheckDecode(manifest string) error { - decoder := yaml.NewDecoder(bytes.NewBufferString(manifest)) - - for { - var value interface{} - - err := decoder.Decode(&value) - if errors.Is(err, io.EOF) { - break - } - - if err != nil { - return err - } - } - - return nil + _, err := common.ParseYAML(manifest) + return err } var _ = ginkgo.Describe("replacing deprecated APIs", ginkgo.Ordered, func() { var mapFile *mapping.Metadata - var deprecatedPodDisruptionBudget string - var newPodDisruptionBudget string + var deprecatedPodDisruptionBudget mapping.APIVersionKind + var newPodDisruptionBudget mapping.APIVersionKind - var deprecatedDeployment string - var newDeployment string + var deprecatedDeployment mapping.APIVersionKind + var newDeployment mapping.APIVersionKind - var deprecatedPodSecurityPolicy string + var deprecatedPodSecurityPolicy mapping.APIVersionKind ginkgo.BeforeAll(func() { - deprecatedPodDisruptionBudget = "apiVersion: policy/v1beta1\nkind: PodDisruptionBudget\n" - newPodDisruptionBudget = "apiVersion: policy/v1\nkind: PodDisruptionBudget\n" + // "apiVersion: policy/v1beta1\nkind: PodDisruptionBudget\n" + deprecatedPodDisruptionBudget = mapping.APIVersionKind{ + APIVersion: "policy/v1beta1", + Kind: "PodDisruptionBudget", + } + // "apiVersion: policy/v1\nkind: PodDisruptionBudget\n" + newPodDisruptionBudget = mapping.APIVersionKind{ + APIVersion: "policy/v1", + Kind: "PodDisruptionBudget", + } - deprecatedDeployment = "apiVersion: apps/v1beta2\nkind: Deployment\n" - newDeployment = "apiVersion: apps/v1\nkind: Deployment\n" + // "apiVersion: apps/v1beta2\nkind: Deployment\n" + deprecatedDeployment = mapping.APIVersionKind{ + APIVersion: "apps/v1beta2", + Kind: "Deployment", + } + // "apiVersion: apps/v1\nkind: Deployment\n" + newDeployment = mapping.APIVersionKind{ + APIVersion: "apps/v1", + Kind: "Deployment", + } - deprecatedPodSecurityPolicy = "apiVersion: policy/v1beta1\nkind: PodSecurityPolicy\n" + // "apiVersion: policy/v1beta1\nkind: PodSecurityPolicy\n" + deprecatedPodSecurityPolicy = mapping.APIVersionKind{ + APIVersion: "policy/v1beta1", + Kind: "PodSecurityPolicy", + } mapFile = &mapping.Metadata{ Mappings: []*mapping.Mapping{ @@ -111,8 +113,9 @@ metadata: spec: template: containers: - - name: test-container - image: test-image` + - image: test-image + name: test-container +` expectedResultingDeploymentManifest = `--- apiVersion: apps/v1 @@ -123,22 +126,25 @@ metadata: spec: template: containers: - - name: test-container - image: test-image` + - image: test-image + name: test-container +` podDisruptionBudgetManifest = `--- apiVersion: policy/v1beta1 kind: PodDisruptionBudget metadata: name: pdb-test - namespace: test-ns` + namespace: test-ns +` expectedResultingPodDisruptionBudgetManifest = `--- apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: pdb-test - namespace: test-ns` + namespace: test-ns +` }) ginkgo.It("replaces deprecated resources with a new version in Kubernetes v1.25", func() { @@ -170,7 +176,8 @@ apiVersion: v1 kind: ServiceAccount metadata: name: test-sa - namespace: test-ns` + namespace: test-ns +` ginkgo.When("it is in the beginning of the manifest", func() { var podSecurityPolicyManifest = `--- @@ -189,13 +196,15 @@ apiVersion: v1 kind: ServiceAccount metadata: name: test-sa - namespace: test-ns` + namespace: test-ns +` ginkgo.It("removes the deprecated API manifest and leaves a valid YAML", func() { modifiedDeploymentManifest, err := common.ReplaceManifestData(mapFile, podSecurityPolicyManifest, kubeVersion125) gomega.Expect(err).ToNot(gomega.HaveOccurred()) - gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.APIVersion)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.Kind)) gomega.Expect(expectedResultManifest).To(gomega.Equal(expectedResultManifest)) err = CheckDecode(modifiedDeploymentManifest) @@ -220,13 +229,15 @@ metadata: apiVersion: policy/v1beta1 kind: PodSecurityPolicy metadata: - name: test-psp` + name: test-psp +` ginkgo.It("removes the deprecated API manifest and leaves a valid YAML", func() { modifiedDeploymentManifest, err := common.ReplaceManifestData(mapFile, podSecurityPolicyManifest, kubeVersion125) gomega.Expect(err).ToNot(gomega.HaveOccurred()) - gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.APIVersion)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.Kind)) gomega.Expect(modifiedDeploymentManifest).To(gomega.Equal(expectedResultManifest)) err = CheckDecode(modifiedDeploymentManifest) @@ -251,13 +262,15 @@ apiVersion: v1 kind: ServiceAccount metadata: name: test-sa - namespace: test-ns` + namespace: test-ns +` ginkgo.It("removes the deprecated API manifest and leaves a valid YAML", func() { modifiedDeploymentManifest, err := common.ReplaceManifestData(mapFile, podSecurityPolicyManifest, kubeVersion125) gomega.Expect(err).ToNot(gomega.HaveOccurred()) - gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.APIVersion)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.Kind)) gomega.Expect(modifiedDeploymentManifest).To(gomega.Equal(expectedResultManifest)) err = CheckDecode(modifiedDeploymentManifest) @@ -281,13 +294,15 @@ apiVersion: v1 kind: ServiceAccount metadata: name: test-sa - namespace: test-ns` + namespace: test-ns +` ginkgo.It("removes the deprecated API manifest and leaves a valid YAML", func() { modifiedDeploymentManifest, err := common.ReplaceManifestData(mapFile, podSecurityPolicyManifest, kubeVersion125) gomega.Expect(err).ToNot(gomega.HaveOccurred()) - gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.APIVersion)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.Kind)) gomega.Expect(modifiedDeploymentManifest).To(gomega.Equal(expectedResultManifest)) err = CheckDecode(modifiedDeploymentManifest) @@ -312,13 +327,15 @@ apiVersion: v1 kind: ServiceAccount metadata: name: test-sa - namespace: test-ns` + namespace: test-ns +` ginkgo.It("removes the deprecated API manifest and leaves a valid YAML", func() { modifiedDeploymentManifest, err := common.ReplaceManifestData(mapFile, podSecurityPolicyManifest, kubeVersion125) gomega.Expect(err).ToNot(gomega.HaveOccurred()) - gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.APIVersion)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.Kind)) gomega.Expect(modifiedDeploymentManifest).To(gomega.Equal(expectedResultManifest)) err = CheckDecode(modifiedDeploymentManifest) @@ -342,13 +359,15 @@ apiVersion: v1 kind: ServiceAccount metadata: name: test-sa - namespace: test-ns` + namespace: test-ns +` ginkgo.It("removes the deprecated API manifest and leaves a valid YAML", func() { modifiedDeploymentManifest, err := common.ReplaceManifestData(mapFile, podSecurityPolicyManifest, kubeVersion125) gomega.Expect(err).ToNot(gomega.HaveOccurred()) - gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.APIVersion)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.Kind)) gomega.Expect(modifiedDeploymentManifest).To(gomega.Equal(expectedResultManifest)) err = CheckDecode(modifiedDeploymentManifest) @@ -373,13 +392,15 @@ apiVersion: v1 kind: ServiceAccount metadata: name: test-sa - namespace: test-ns` + namespace: test-ns +` ginkgo.It("removes the deprecated API manifest and leaves a valid YAML", func() { modifiedDeploymentManifest, err := common.ReplaceManifestData(mapFile, podSecurityPolicyManifest, kubeVersion125) gomega.Expect(err).ToNot(gomega.HaveOccurred()) - gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.APIVersion)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.Kind)) gomega.Expect(modifiedDeploymentManifest).To(gomega.Equal(expectedResultManifest)) err = CheckDecode(modifiedDeploymentManifest) @@ -413,7 +434,8 @@ spec: modifiedDeploymentManifest, err := common.ReplaceManifestData(mapFile, podSecurityPolicyManifest, kubeVersion125) gomega.Expect(err).ToNot(gomega.HaveOccurred()) - gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.APIVersion)) + gomega.Expect(modifiedDeploymentManifest).ToNot(gomega.ContainSubstring(deprecatedPodSecurityPolicy.Kind)) gomega.Expect(modifiedDeploymentManifest).To(gomega.Equal(expectedResultManifest)) err = CheckDecode(modifiedDeploymentManifest) diff --git a/pkg/common/yaml.go b/pkg/common/yaml.go new file mode 100644 index 0000000..1b4e1a2 --- /dev/null +++ b/pkg/common/yaml.go @@ -0,0 +1,47 @@ +package common + +import ( + "io" + "strings" + + "github.com/pkg/errors" + "gopkg.in/yaml.v3" // for multi-doc support +) + +// GenericYAML represents generic YAML document +type GenericYAML map[string]any + +// ParseYAML parses a YAML string into a slice of GenericYAML documents +func ParseYAML(s string) ([]GenericYAML, error) { + decoder := yaml.NewDecoder(strings.NewReader(s)) + var docs []GenericYAML + for { + var y GenericYAML + err := decoder.Decode(&y) + if errors.Is(err, io.EOF) { + break + } + + if err != nil { + return nil, errors.Wrap(err, "Failed to decode YAML") + } + docs = append(docs, y) + } + return docs, nil +} + +// EncodeYAML encodes a slice of GenericYAML documents into a multi-doc YAML string +func EncodeYAML(docs []GenericYAML) (string, error) { + var sb strings.Builder + encoder := yaml.NewEncoder(&sb) + encoder.SetIndent(2) // match test cases + for _, doc := range docs { + if err := encoder.Encode(doc); err != nil { + return "", errors.Wrap(err, "Failed to encode document") + } + } + if err := encoder.Close(); err != nil { + return "", errors.Wrap(err, "Failed to close encoder") + } + return "---\n" + sb.String(), nil // always start with a document separator +} diff --git a/pkg/mapping/mapping.go b/pkg/mapping/mapping.go index 89a7f3a..3825d88 100644 --- a/pkg/mapping/mapping.go +++ b/pkg/mapping/mapping.go @@ -16,14 +16,21 @@ limitations under the License. package mapping +// APIVersionKind represents the common elements of a Kubernetes API resource. This is used +// for the Mapping.DeprecatedAPI and Mapping.NewAPI fields. +type APIVersionKind struct { + APIVersion string `json:"apiVersion"` + Kind string `json:"kind"` +} + // Mapping describes mappings which defines the Kubernetes // API deprecations and the new replacement API type Mapping struct { // From is the API looking to be mapped - DeprecatedAPI string `json:"deprecatedAPI"` + DeprecatedAPI APIVersionKind `json:"deprecatedAPI"` // To is the API to be mapped to - NewAPI string `json:"newAPI"` + NewAPI APIVersionKind `json:"newAPI"` // Kubernetes version API is deprecated in DeprecatedInVersion string `json:"deprecatedInVersion,omitempty"`