From 160601e7845fb5d949fa85c412f1e2f1ce3eeafe Mon Sep 17 00:00:00 2001 From: Joe Julian Date: Fri, 28 Aug 2020 16:10:38 -0700 Subject: [PATCH] add more verbose deprecation info Signed-off-by: Joe Julian --- pkg/lint/rules/deprecations.go | 202 +++++++++++++++++++++++++++------ 1 file changed, 165 insertions(+), 37 deletions(-) diff --git a/pkg/lint/rules/deprecations.go b/pkg/lint/rules/deprecations.go index 88921408d..acd6ad017 100644 --- a/pkg/lint/rules/deprecations.go +++ b/pkg/lint/rules/deprecations.go @@ -18,50 +18,176 @@ package rules // import "helm.sh/helm/v3/pkg/lint/rules" import "fmt" -// deprecatedAPIs lists APIs that are deprecated (left) with suggested alternatives (right). -// -// An empty rvalue indicates that the API is completely deprecated. -var deprecatedAPIs = map[string]string{ - "extensions/v1beta1 Deployment": "apps/v1 Deployment", - "extensions/v1beta1 DaemonSet": "apps/v1 DaemonSet", - "extensions/v1beta1 ReplicaSet": "apps/v1 ReplicaSet", - "extensions/v1beta1 PodSecurityPolicy": "policy/v1beta1 PodSecurityPolicy", - "extensions/v1beta1 NetworkPolicy": "networking.k8s.io/v1beta1 NetworkPolicy", - "extensions/v1beta1 Ingress": "networking.k8s.io/v1beta1 Ingress", - "apps/v1beta1 Deployment": "apps/v1 Deployment", - "apps/v1beta1 StatefulSet": "apps/v1 StatefulSet", - "apps/v1beta1 ReplicaSet": "apps/v1 ReplicaSet", - "apps/v1beta2 Deployment": "apps/v1 Deployment", - "apps/v1beta2 StatefulSet": "apps/v1 StatefulSet", - "apps/v1beta2 DaemonSet": "apps/v1 DaemonSet", - "apps/v1beta2 ReplicaSet": "apps/v1 ReplicaSet", - "apiextensions.k8s.io/v1beta1 CustomResourceDefinition": "apiextensions.k8s.io/v1 CustomResourceDefinition", - "rbac.authorization.k8s.io/v1alpha1 ClusterRole": "rbac.authorization.k8s.io/v1 ClusterRole", - "rbac.authorization.k8s.io/v1alpha1 ClusterRoleList": "rbac.authorization.k8s.io/v1 ClusterRoleList", - "rbac.authorization.k8s.io/v1alpha1 ClusterRoleBinding": "rbac.authorization.k8s.io/v1 ClusterRoleBinding", - "rbac.authorization.k8s.io/v1alpha1 ClusterRoleBindingList": "rbac.authorization.k8s.io/v1 ClusterRoleBindingList", - "rbac.authorization.k8s.io/v1alpha1 Role": "rbac.authorization.k8s.io/v1 Role", - "rbac.authorization.k8s.io/v1alpha1 RoleList": "rbac.authorization.k8s.io/v1 RoleList", - "rbac.authorization.k8s.io/v1alpha1 RoleBinding": "rbac.authorization.k8s.io/v1 RoleBinding", - "rbac.authorization.k8s.io/v1alpha1 RoleBindingList": "rbac.authorization.k8s.io/v1 RoleBindingList", - "rbac.authorization.k8s.io/v1beta1 ClusterRole": "rbac.authorization.k8s.io/v1 ClusterRole", - "rbac.authorization.k8s.io/v1beta1 ClusterRoleList": "rbac.authorization.k8s.io/v1 ClusterRoleList", - "rbac.authorization.k8s.io/v1beta1 ClusterRoleBinding": "rbac.authorization.k8s.io/v1 ClusterRoleBinding", - "rbac.authorization.k8s.io/v1beta1 ClusterRoleBindingList": "rbac.authorization.k8s.io/v1 ClusterRoleBindingList", - "rbac.authorization.k8s.io/v1beta1 Role": "rbac.authorization.k8s.io/v1 Role", - "rbac.authorization.k8s.io/v1beta1 RoleList": "rbac.authorization.k8s.io/v1 RoleList", - "rbac.authorization.k8s.io/v1beta1 RoleBinding": "rbac.authorization.k8s.io/v1 RoleBinding", - "rbac.authorization.k8s.io/v1beta1 RoleBindingList": "rbac.authorization.k8s.io/v1 RoleBindingList", +type deprecatedAPI struct { + NewAPI string + DeprecatedIn string + RemovedIn string +} + +// deprecatedAPIs lists APIs that are deprecated (key) with suggested alternatives (value). +var deprecatedAPIs = map[string]deprecatedAPI{ + "extensions/v1beta1 Deployment": { + NewAPI: "apps/v1 Deployment", + DeprecatedIn: "v1.9", + RemovedIn: "v1.16", + }, + "apps/v1beta1 Deployment": { + NewAPI: "apps/v1 Deployment", + DeprecatedIn: "v1.9", + RemovedIn: "v1.16", + }, + "apps/v1beta2 Deployment": { + NewAPI: "apps/v1 Deployment", + DeprecatedIn: "v1.9", + RemovedIn: "v1.16", + }, + "apps/v1beta1 StatefulSet": { + NewAPI: "apps/v1 StatefulSet", + DeprecatedIn: "v1.9", + RemovedIn: "v1.16", + }, + "apps/v1beta2 StatefulSet": { + NewAPI: "apps/v1 StatefulSet", + DeprecatedIn: "v1.9", + RemovedIn: "v1.16", + }, + "extensions/v1beta1 DaemonSet": { + NewAPI: "apps/v1 DaemonSet", + DeprecatedIn: "v1.9", + RemovedIn: "v1.16", + }, + "apps/v1beta2 DaemonSet": { + NewAPI: "apps/v1 DaemonSet", + DeprecatedIn: "v1.9", + RemovedIn: "v1.16", + }, + "extensions/v1beta1 ReplicaSet": { + NewAPI: "apps/v1 ReplicaSet", + DeprecatedIn: "v1.9", + RemovedIn: "v1.16", + }, + "apps/v1beta1 ReplicaSet": { + NewAPI: "apps/v1 ReplicaSet", + DeprecatedIn: "v1.9", + RemovedIn: "v1.16", + }, + "apps/v1beta2 ReplicaSet": { + NewAPI: "apps/v1 ReplicaSet", + DeprecatedIn: "v1.9", + RemovedIn: "v1.16", + }, + "extensions/v1beta1 NetworkPolicy": { + NewAPI: "networking.k8s.io/v1 NetworkPolicy", + DeprecatedIn: "v1.8", + RemovedIn: "v1.16", + }, + "extensions/v1beta1 PodSecurityPolicy": { + NewAPI: "policy/v1beta1 PodSecurityPolicy", + DeprecatedIn: "v1.10", + RemovedIn: "v1.16", + }, + "apiextensions.k8s.io/v1beta1 CustomResourceDefinition": { + NewAPI: "apiextensions.k8s.io/v1 CustomResourceDefinition", + DeprecatedIn: "v1.16", + RemovedIn: "v1.19", + }, + "extensions/v1beta1 Ingress": { + NewAPI: "networking.k8s.io/v1beta1 Ingress", + DeprecatedIn: "v1.14", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1alpha1 ClusterRole": { + NewAPI: "rbac.authorization.k8s.io/v1 ClusterRole", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1alpha1 ClusterRoleList": { + NewAPI: "rbac.authorization.k8s.io/v1 ClusterRoleList", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1alpha1 ClusterRoleBinding": { + NewAPI: "rbac.authorization.k8s.io/v1 ClusterRoleBinding", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1alpha1 ClusterRoleBindingList": { + NewAPI: "rbac.authorization.k8s.io/v1 ClusterRoleBindingList", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1alpha1 Role": { + NewAPI: "rbac.authorization.k8s.io/v1 Role", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1alpha1 RoleList": { + NewAPI: "rbac.authorization.k8s.io/v1 RoleList", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1alpha1 RoleBinding": { + NewAPI: "rbac.authorization.k8s.io/v1 RoleBinding", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1alpha1 RoleBindingList": { + NewAPI: "rbac.authorization.k8s.io/v1 RoleBindingList", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1beta ClusterRole": { + NewAPI: "rbac.authorization.k8s.io/v1 ClusterRole", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1beta1 ClusterRoleList": { + NewAPI: "rbac.authorization.k8s.io/v1 ClusterRoleList", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1beta1 ClusterRoleBinding": { + NewAPI: "rbac.authorization.k8s.io/v1 ClusterRoleBinding", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1beta1 ClusterRoleBindingList": { + NewAPI: "rbac.authorization.k8s.io/v1 ClusterRoleBindingList", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1beta1 Role": { + NewAPI: "rbac.authorization.k8s.io/v1 Role", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1beta1 RoleList": { + NewAPI: "rbac.authorization.k8s.io/v1 RoleList", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1beta1 RoleBinding": { + NewAPI: "rbac.authorization.k8s.io/v1 RoleBinding", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, + "rbac.authorization.k8s.io/v1beta1 RoleBindingList": { + NewAPI: "rbac.authorization.k8s.io/v1 RoleBindingList", + DeprecatedIn: "v1.17", + RemovedIn: "v1.22", + }, } // deprecatedAPIError indicates than an API is deprecated in Kubernetes type deprecatedAPIError struct { Deprecated string Alternative string + In string + Removed string } func (e deprecatedAPIError) Error() string { - msg := fmt.Sprintf("the kind %q is deprecated", e.Deprecated) + msg := fmt.Sprintf("the kind %q is deprecated as of %q and removed in %q", e.Deprecated, e.In, e.Removed) if e.Alternative != "" { msg += fmt.Sprintf(" in favor of %q", e.Alternative) } @@ -70,10 +196,12 @@ func (e deprecatedAPIError) Error() string { func validateNoDeprecations(resource *K8sYamlStruct) error { gvk := fmt.Sprintf("%s %s", resource.APIVersion, resource.Kind) - if alt, ok := deprecatedAPIs[gvk]; ok { + if dep, ok := deprecatedAPIs[gvk]; ok { return deprecatedAPIError{ Deprecated: gvk, - Alternative: alt, + Alternative: dep.NewAPI, + In: dep.DeprecatedIn, + Removed: dep.RemovedIn, } } return nil