Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package pluto for openSUSE:Factory checked in at 2023-02-23 16:28:51 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/pluto (Old) and /work/SRC/openSUSE:Factory/.pluto.new.1706 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "pluto" Thu Feb 23 16:28:51 2023 rev:26 rq:1067396 version:5.15.1 Changes: -------- --- /work/SRC/openSUSE:Factory/pluto/pluto.changes 2023-02-21 15:36:57.980605714 +0100 +++ /work/SRC/openSUSE:Factory/.pluto.new.1706/pluto.changes 2023-02-23 16:53:04.341019635 +0100 @@ -1,0 +2,18 @@ +Thu Feb 23 10:39:17 UTC 2023 - ka...@b1-systems.de + +- Update to version 5.15.1: + * add: set replacement-available-in to existing version. (#457) + +------------------------------------------------------------------- +Thu Feb 23 10:37:21 UTC 2023 - ka...@b1-systems.de + +- Update to version 5.15.0: + * Add a `detect-all-in-cluster` command to run both `detect-helm` and `detect-api-resources` (#455) + +------------------------------------------------------------------- +Wed Feb 22 17:26:16 UTC 2023 - ka...@b1-systems.de + +- Update to version 5.14.0: + * add replacement-available-in (#452) + +------------------------------------------------------------------- Old: ---- pluto-5.13.4.tar.gz New: ---- pluto-5.15.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ pluto.spec ++++++ --- /var/tmp/diff_new_pack.ofmFj9/_old 2023-02-23 16:53:04.893022836 +0100 +++ /var/tmp/diff_new_pack.ofmFj9/_new 2023-02-23 16:53:04.913022952 +0100 @@ -19,7 +19,7 @@ %define __arch_install_post export NO_BRP_STRIP_DEBUG=true Name: pluto -Version: 5.13.4 +Version: 5.15.1 Release: 0 Summary: A cli tool to help discover deprecated apiVersions in Kubernetes License: Apache-2.0 ++++++ _service ++++++ --- /var/tmp/diff_new_pack.ofmFj9/_old 2023-02-23 16:53:04.957023207 +0100 +++ /var/tmp/diff_new_pack.ofmFj9/_new 2023-02-23 16:53:04.965023253 +0100 @@ -3,7 +3,7 @@ <param name="url">https://github.com/FairwindsOps/pluto</param> <param name="scm">git</param> <param name="exclude">.git</param> - <param name="revision">v5.13.4</param> + <param name="revision">v5.15.1</param> <param name="versionformat">@PARENT_TAG@</param> <param name="changesgenerate">enable</param> <param name="versionrewrite-pattern">v(.*)</param> @@ -16,7 +16,7 @@ <param name="compression">gz</param> </service> <service name="go_modules" mode="disabled"> - <param name="archive">pluto-5.13.4.tar.gz</param> + <param name="archive">pluto-5.15.1.tar.gz</param> </service> </services> ++++++ _servicedata ++++++ --- /var/tmp/diff_new_pack.ofmFj9/_old 2023-02-23 16:53:04.985023370 +0100 +++ /var/tmp/diff_new_pack.ofmFj9/_new 2023-02-23 16:53:04.993023416 +0100 @@ -1,6 +1,6 @@ <servicedata> <service name="tar_scm"> <param name="url">https://github.com/FairwindsOps/pluto</param> - <param name="changesrevision">87f16b12344ffa38690a3c252fa3d1a23664c10b</param></service></servicedata> + <param name="changesrevision">cf69d915f3bcb2c54c55b2b7a5c0a6bbce7f78c8</param></service></servicedata> (No newline at EOF) ++++++ pluto-5.13.4.tar.gz -> pluto-5.15.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluto-5.13.4/cmd/root.go new/pluto-5.15.1/cmd/root.go --- old/pluto-5.13.4/cmd/root.go 2023-02-20 18:46:37.000000000 +0100 +++ new/pluto-5.15.1/cmd/root.go 2023-02-22 22:11:39.000000000 +0100 @@ -48,23 +48,24 @@ ) var ( - version string - versionCommit string - versionFileData []byte - additionalVersionsFile string - directory string - outputFormat string - ignoreDeprecations bool - ignoreRemovals bool - namespace string - apiInstance *api.Instance - targetVersions map[string]string - customColumns []string - componentsFromUser []string - onlyShowRemoved bool - kubeContext string - noHeaders bool - exitCode int + version string + versionCommit string + versionFileData []byte + additionalVersionsFile string + directory string + outputFormat string + ignoreDeprecations bool + ignoreRemovals bool + ignoreUnavailableReplacements bool + namespace string + apiInstance *api.Instance + targetVersions map[string]string + customColumns []string + componentsFromUser []string + onlyShowRemoved bool + kubeContext string + noHeaders bool + exitCode int ) const ( @@ -84,6 +85,7 @@ func init() { rootCmd.PersistentFlags().BoolVar(&ignoreDeprecations, "ignore-deprecations", false, "Ignore the default behavior to exit 2 if deprecated apiVersions are found.") rootCmd.PersistentFlags().BoolVar(&ignoreRemovals, "ignore-removals", false, "Ignore the default behavior to exit 3 if removed apiVersions are found.") + rootCmd.PersistentFlags().BoolVar(&ignoreUnavailableReplacements, "ignore-unavailable-replacements", false, "Ignore the default behavior to exit 4 if deprecated but unavailable apiVersions are found.") rootCmd.PersistentFlags().BoolVarP(&onlyShowRemoved, "only-show-removed", "r", false, "Only display the apiVersions that have been removed in the target version.") rootCmd.PersistentFlags().BoolVarP(&noHeaders, "no-headers", "H", false, "When using the default or custom-column output format, don't print headers (default print headers).") rootCmd.PersistentFlags().StringVarP(&additionalVersionsFile, "additional-versions", "f", "", "Additional deprecated versions file to add to the list. Cannot contain any existing versions") @@ -103,6 +105,10 @@ detectApiResourceCmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", "", "Only detect resources in a specific namespace.") detectApiResourceCmd.PersistentFlags().StringVar(&kubeContext, "kube-context", "", "The kube context to use. If blank, defaults to current context.") + rootCmd.AddCommand(detectAllInClusterCmd) + detectAllInClusterCmd.PersistentFlags().StringVarP(&namespace, "namespace", "n", "", "Only detect resources in a specific namespace.") + detectAllInClusterCmd.PersistentFlags().StringVar(&kubeContext, "kube-context", "", "The kube context to use. If blank, defaults to current context.") + rootCmd.AddCommand(listVersionsCmd) rootCmd.AddCommand(detectCmd) @@ -268,15 +274,16 @@ // this apiInstance will be used by all detection methods apiInstance = &api.Instance{ - TargetVersions: targetVersions, - OutputFormat: outputFormat, - CustomColumns: customColumns, - IgnoreDeprecations: ignoreDeprecations, - IgnoreRemovals: ignoreRemovals, - OnlyShowRemoved: onlyShowRemoved, - NoHeaders: noHeaders, - DeprecatedVersions: deprecatedVersionList, - Components: componentList, + TargetVersions: targetVersions, + OutputFormat: outputFormat, + CustomColumns: customColumns, + IgnoreDeprecations: ignoreDeprecations, + IgnoreRemovals: ignoreRemovals, + IgnoreUnavailableReplacements: ignoreUnavailableReplacements, + OnlyShowRemoved: onlyShowRemoved, + NoHeaders: noHeaders, + DeprecatedVersions: deprecatedVersionList, + Components: componentList, } return nil @@ -309,24 +316,19 @@ Short: "detect-helm", Long: `Detect Kubernetes apiVersions in a helm release (in cluster)`, Run: func(cmd *cobra.Command, args []string) { - h, err := helm.NewHelm(namespace, kubeContext, apiInstance) + err := detectHelm() if err != nil { - fmt.Printf("error getting helm configuration: %s\n", err.Error()) - os.Exit(1) - } - err = h.FindVersions() - if err != nil { - fmt.Println("Error running helm-detect:", err) + fmt.Println(err) os.Exit(1) } err = apiInstance.DisplayOutput() if err != nil { - fmt.Println("Error Parsing Output:", err) + fmt.Printf("Error Parsing Output: %v\n", err) os.Exit(1) } - retCode := apiInstance.GetReturnCode() - klog.V(5).Infof("retCode: %d", retCode) - os.Exit(retCode) + exitCode := apiInstance.GetReturnCode() + klog.V(5).Infof("retCode: %d", exitCode) + os.Exit(exitCode) }, } @@ -335,23 +337,48 @@ Short: "detect-api-resources", Long: `Detect Kubernetes apiVersions from an active cluster (using last-applied-configuration annotation)`, Run: func(cmd *cobra.Command, args []string) { - disCl, err := discoveryapi.NewDiscoveryClient(namespace, kubeContext, apiInstance) + err := detectAPIResources() + if err != nil { + fmt.Println(err) + os.Exit(1) + } + err = apiInstance.DisplayOutput() + if err != nil { + fmt.Printf("Error Parsing Output: %v\n", err) + os.Exit(1) + } + exitCode := apiInstance.GetReturnCode() + klog.V(5).Infof("retCode: %d", exitCode) + os.Exit(exitCode) + }, +} + +var detectAllInClusterCmd = &cobra.Command{ + Use: "detect-all-in-cluster", + Short: "run all in-cluster detections", + Long: `Detect Kubernetes apiVersions from an active cluster using all available methods (Helm releases, using the last-applied-configuration annotation)`, + Run: func(cmd *cobra.Command, args []string) { + err := detectHelm() if err != nil { - fmt.Println("Error creating Discovery REST Client: ", err) + fmt.Println(err) os.Exit(1) } - err = disCl.GetApiResources() + klog.V(5).Infof("after running detect-helm, exit-code is %d, and there are %d output items", apiInstance.GetReturnCode(), len(apiInstance.Outputs)) + err = detectAPIResources() if err != nil { - fmt.Println("Error getting API resources using discovery client:", err) + fmt.Println(err) os.Exit(1) } + klog.V(5).Infof("after running detect-api-resources, exit-code is %d, and there are %d output items", apiInstance.GetReturnCode(), len(apiInstance.Outputs)) + err = apiInstance.DisplayOutput() if err != nil { - fmt.Println("Error Parsing Output:", err) + fmt.Printf("Error Parsing Output: %v\n", err) os.Exit(1) } - exitCode = apiInstance.GetReturnCode() + exitCode := apiInstance.GetReturnCode() klog.V(5).Infof("retCode: %d", exitCode) + os.Exit(exitCode) }, } @@ -438,3 +465,27 @@ os.Exit(1) } } + +func detectHelm() error { + h, err := helm.NewHelm(namespace, kubeContext, apiInstance) + if err != nil { + return fmt.Errorf("error getting helm configuration: %v", err) + } + err = h.FindVersions() + if err != nil { + return fmt.Errorf("Error running helm-detect: %v", err) + } + return nil +} + +func detectAPIResources() error { + disCl, err := discoveryapi.NewDiscoveryClient(namespace, kubeContext, apiInstance) + if err != nil { + return fmt.Errorf("Error creating Discovery REST Client: %v", err) + } + err = disCl.GetApiResources() + if err != nil { + return fmt.Errorf("Error getting API resources using discovery client: %v", err) + } + return nil +} diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluto-5.13.4/docs/quickstart.md new/pluto-5.15.1/docs/quickstart.md --- old/pluto-5.13.4/docs/quickstart.md 2023-02-20 18:46:37.000000000 +0100 +++ new/pluto-5.15.1/docs/quickstart.md 2023-02-22 22:11:39.000000000 +0100 @@ -61,3 +61,15 @@ ``` This indicates that the PodSecurityPolicy was deployed with apps/v1beta1 which is deprecated in 1.21 + +### helm and API resources (in-cluster) + +``` +$ pluto detect-all-in-cluster -o wide 2>/dev/null +NAME NAMESPACE KIND VERSION REPLACEMENT DEPRECATED DEPRECATED IN REMOVED REMOVED IN +testing/viahelm viahelm Ingress networking.k8s.io/v1beta1 networking.k8s.io/v1 true v1.19.0 true v1.22.0 +webapp default Ingress networking.k8s.io/v1beta1 networking.k8s.io/v1 true v1.19.0 true v1.22.0 +eks.privileged <UNKNOWN> PodSecurityPolicy policy/v1beta1 true v1.21.0 false v1.25.0 +``` + +This combines all available in-cluster detections, showing results from Helm releases and API resources. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluto-5.13.4/e2e/tests/01_helm-detect-3.yaml new/pluto-5.15.1/e2e/tests/01_helm-detect-3.yaml --- old/pluto-5.13.4/e2e/tests/01_helm-detect-3.yaml 2023-02-20 18:46:37.000000000 +0100 +++ new/pluto-5.15.1/e2e/tests/01_helm-detect-3.yaml 2023-02-22 22:11:39.000000000 +0100 @@ -57,7 +57,7 @@ - script: pluto detect-helm -ojson --target-versions k8s=v1.16.0 assertions: - result.code ShouldEqual 3 - - result.systemout ShouldEqual {"items":[{"name":"test/test-helm3chart-v1beta1","namespace":"default","api":{"version":"extensions/v1beta1","kind":"Deployment","deprecated-in":"v1.9.0","removed-in":"v1.16.0","replacement-api":"apps/v1","component":"k8s"},"deprecated":true,"removed":true},{"name":"test/test-helm3chart-v1beta1","namespace":"demo2","api":{"version":"extensions/v1beta1","kind":"Deployment","deprecated-in":"v1.9.0","removed-in":"v1.16.0","replacement-api":"apps/v1","component":"k8s"},"deprecated":true,"removed":true}],"target-versions":{"cert-manager":"v1.5.3","istio":"v1.11.0","k8s":"v1.16.0"}} + - result.systemout ShouldEqual {"items":[{"name":"test/test-helm3chart-v1beta1","namespace":"default","api":{"version":"extensions/v1beta1","kind":"Deployment","deprecated-in":"v1.9.0","removed-in":"v1.16.0","replacement-api":"apps/v1","replacement-available-in":"v1.9.0","component":"k8s"},"deprecated":true,"removed":true,"replacementAvailable":true},{"name":"test/test-helm3chart-v1beta1","namespace":"demo2","api":{"version":"extensions/v1beta1","kind":"Deployment","deprecated-in":"v1.9.0","removed-in":"v1.16.0","replacement-api":"apps/v1","replacement-available-in":"v1.9.0","component":"k8s"},"deprecated":true,"removed":true,"replacementAvailable":true}],"target-versions":{"cert-manager":"v1.5.3","istio":"v1.11.0","k8s":"v1.16.0"}} - name: helm detect --kube-context=doesnotexist steps: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluto-5.13.4/pkg/api/columns.go new/pluto-5.15.1/pkg/api/columns.go --- old/pluto-5.13.4/pkg/api/columns.go 2023-02-20 18:46:37.000000000 +0100 +++ new/pluto-5.15.1/pkg/api/columns.go 2023-02-22 22:11:39.000000000 +0100 @@ -24,7 +24,7 @@ type columnList map[int]column -//PossibleColumnNames is the list of implmented columns +// PossibleColumnNames is the list of implmented columns var PossibleColumnNames = []string{ "NAME", "FILEPATH", @@ -37,6 +37,8 @@ "REMOVED", "REMOVED IN", "COMPONENT", + "REPL AVAIL", + "REPL AVAIL IN", } var possibleColumns = []column{ @@ -129,6 +131,22 @@ func (c component) header() string { return "COMPONENT" } func (c component) value(output *Output) string { return output.APIVersion.Component } +// replacementAvailable is the output for the boolean ReplacementAvailable +type replacementAvailable struct{} + +func (ra replacementAvailable) header() string { return "REPL AVAIL" } +func (ra replacementAvailable) value(output *Output) string { + return fmt.Sprintf("%t", output.ReplacementAvailable) +} + +// replacementAvailableIn is the string value of when an output was ReplacementAvailableIn +type replacementAvailableIn struct{} + +func (rai replacementAvailableIn) header() string { return "REPL AVAIL IN" } +func (rai replacementAvailableIn) value(output *Output) string { + return output.APIVersion.ReplacementAvailableIn +} + // normalColumns returns the list of columns for -onormal func (instance *Instance) normalColumns() columnList { columnList := columnList{ @@ -138,6 +156,7 @@ 3: new(replacement), 4: new(removed), 5: new(deprecated), + 6: new(replacementAvailable), } return columnList } @@ -145,15 +164,17 @@ // wideColumns returns the list of columns for -owide func (instance *Instance) wideColumns() columnList { columnList := columnList{ - 0: new(name), - 1: new(namespace), - 2: new(kind), - 3: new(version), - 4: new(replacement), - 5: new(deprecated), - 6: new(deprecatedIn), - 7: new(removed), - 8: new(removedIn), + 0: new(name), + 1: new(namespace), + 2: new(kind), + 3: new(version), + 4: new(replacement), + 5: new(deprecated), + 6: new(deprecatedIn), + 7: new(removed), + 8: new(removedIn), + 9: new(replacementAvailable), + 10: new(replacementAvailableIn), } return columnList } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluto-5.13.4/pkg/api/output.go new/pluto-5.15.1/pkg/api/output.go --- old/pluto-5.13.4/pkg/api/output.go 2023-02-20 18:46:37.000000000 +0100 +++ new/pluto-5.15.1/pkg/api/output.go 2023-02-22 22:11:39.000000000 +0100 @@ -45,22 +45,25 @@ Deprecated bool `json:"deprecated" yaml:"deprecated"` // Removed is a boolean indicating whether or not the version has been removed Removed bool `json:"removed" yaml:"removed"` + // ReplacementAvailable is a boolean indicating whether or not the replacement is available + ReplacementAvailable bool `json:"replacementAvailable" yaml:"replacementAvailable"` // CustomColumns is a list of column headers to be displayed with -ocustom or -omarkdown CustomColumns []string `json:"-" yaml:"-"` } // Instance is an instance of the API. This holds configuration for a "run" of Pluto type Instance struct { - Outputs []*Output `json:"items,omitempty" yaml:"items,omitempty"` - IgnoreDeprecations bool `json:"-" yaml:"-"` - IgnoreRemovals bool `json:"-" yaml:"-"` - OnlyShowRemoved bool `json:"-" yaml:"-"` - NoHeaders bool `json:"-" yaml:"-"` - OutputFormat string `json:"-" yaml:"-"` - TargetVersions map[string]string `json:"target-versions,omitempty" yaml:"target-versions,omitempty"` - DeprecatedVersions []Version `json:"-" yaml:"-"` - CustomColumns []string `json:"-" yaml:"-"` - Components []string `json:"-" yaml:"-"` + Outputs []*Output `json:"items,omitempty" yaml:"items,omitempty"` + IgnoreDeprecations bool `json:"-" yaml:"-"` + IgnoreRemovals bool `json:"-" yaml:"-"` + IgnoreUnavailableReplacements bool `json:"-" yaml:"-"` + OnlyShowRemoved bool `json:"-" yaml:"-"` + NoHeaders bool `json:"-" yaml:"-"` + OutputFormat string `json:"-" yaml:"-"` + TargetVersions map[string]string `json:"target-versions,omitempty" yaml:"target-versions,omitempty"` + DeprecatedVersions []Version `json:"-" yaml:"-"` + CustomColumns []string `json:"-" yaml:"-"` + Components []string `json:"-" yaml:"-"` } // DisplayOutput prints the output based on desired variables @@ -155,6 +158,7 @@ for _, output := range instance.Outputs { output.Deprecated = output.APIVersion.isDeprecatedIn(instance.TargetVersions) output.Removed = output.APIVersion.isRemovedIn(instance.TargetVersions) + output.ReplacementAvailable = output.APIVersion.isReplacementAvailableIn(instance.TargetVersions) switch instance.OnlyShowRemoved { case false: if output.Deprecated || output.Removed { @@ -298,23 +302,34 @@ // takes a boolean to ignore any errors. // exit 2 - version deprecated // exit 3 - version removed +// exit 4 - replacement is unavailable in target version func (instance *Instance) GetReturnCode() int { returnCode := 0 var deprecations int var removals int + var unavailableReplacements int for _, output := range instance.Outputs { if output.APIVersion.isRemovedIn(instance.TargetVersions) { removals = removals + 1 } if output.APIVersion.isDeprecatedIn(instance.TargetVersions) { - deprecations = deprecations + 1 + if output.APIVersion.isReplacementAvailableIn(instance.TargetVersions) || !instance.IgnoreUnavailableReplacements { + deprecations = deprecations + 1 + } + } + if !output.APIVersion.isReplacementAvailableIn(instance.TargetVersions) { + unavailableReplacements = unavailableReplacements + 1 } } + if deprecations > 0 && !instance.IgnoreDeprecations { returnCode = 2 } if removals > 0 && !instance.IgnoreRemovals { returnCode = 3 } + if unavailableReplacements > 0 && !instance.IgnoreUnavailableReplacements { + returnCode = 4 + } return returnCode } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluto-5.13.4/pkg/api/output_test.go new/pluto-5.15.1/pkg/api/output_test.go --- old/pluto-5.13.4/pkg/api/output_test.go 2023-02-20 18:46:37.000000000 +0100 +++ new/pluto-5.15.1/pkg/api/output_test.go 2023-02-22 22:11:39.000000000 +0100 @@ -39,35 +39,38 @@ Namespace: "pluto-namespace", FilePath: "path-to-file", APIVersion: &Version{ - Name: "extensions/v1beta1", - Kind: "Deployment", - DeprecatedIn: "v1.9.0", - RemovedIn: "v1.16.0", - ReplacementAPI: "apps/v1", - Component: "foo", + Name: "extensions/v1beta1", + Kind: "Deployment", + DeprecatedIn: "v1.9.0", + RemovedIn: "v1.16.0", + ReplacementAPI: "apps/v1", + ReplacementAvailableIn: "v1.10.0", + Component: "foo", }, } var testOutput2 = &Output{ Name: "some name two", APIVersion: &Version{ - Name: "extensions/v1beta1", - Kind: "Deployment", - DeprecatedIn: "v1.9.0", - RemovedIn: "v1.16.0", - ReplacementAPI: "apps/v1", - Component: "foo", + Name: "extensions/v1beta1", + Kind: "Deployment", + DeprecatedIn: "v1.9.0", + RemovedIn: "v1.16.0", + ReplacementAPI: "apps/v1", + ReplacementAvailableIn: "v1.10.0", + Component: "foo", }, } var testOutputNoOutput = &Output{ Name: "not a deprecated object", APIVersion: &Version{ - Name: "apps/v1", - Kind: "Deployment", - DeprecatedIn: "", - RemovedIn: "", - ReplacementAPI: "", - Component: "foo", + Name: "apps/v1", + Kind: "Deployment", + DeprecatedIn: "", + RemovedIn: "", + ReplacementAPI: "", + ReplacementAvailableIn: "", + Component: "foo", }, } @@ -103,10 +106,10 @@ _ = instance.DisplayOutput() // Output: - // NAME-------------------- KIND-------- VERSION------------- REPLACEMENT-- REMOVED-- DEPRECATED-- - // some name one----------- Deployment-- extensions/v1beta1-- apps/v1------ true----- true-------- - // some name two----------- Deployment-- extensions/v1beta1-- apps/v1------ true----- true-------- - // deprecated not removed-- Deployment-- apps/v1------------- none--------- false---- true-------- + // NAME-------------------- KIND-------- VERSION------------- REPLACEMENT-- REMOVED-- DEPRECATED-- REPL AVAIL-- + // some name one----------- Deployment-- extensions/v1beta1-- apps/v1------ true----- true-------- true-------- + // some name two----------- Deployment-- extensions/v1beta1-- apps/v1------ true----- true-------- true-------- + // deprecated not removed-- Deployment-- apps/v1------------- none--------- false---- true-------- true-------- } func ExampleInstance_DisplayOutput_onlyShowRemoved() { @@ -126,9 +129,9 @@ _ = instance.DisplayOutput() // Output: - // NAME----------- KIND-------- VERSION------------- REPLACEMENT-- REMOVED-- DEPRECATED-- - // some name one-- Deployment-- extensions/v1beta1-- apps/v1------ true----- true-------- - // some name two-- Deployment-- extensions/v1beta1-- apps/v1------ true----- true-------- + // NAME----------- KIND-------- VERSION------------- REPLACEMENT-- REMOVED-- DEPRECATED-- REPL AVAIL-- + // some name one-- Deployment-- extensions/v1beta1-- apps/v1------ true----- true-------- true-------- + // some name two-- Deployment-- extensions/v1beta1-- apps/v1------ true----- true-------- true-------- } func ExampleInstance_DisplayOutput_wide() { @@ -146,9 +149,9 @@ _ = instance.DisplayOutput() // Output: - // NAME----------- NAMESPACE-------- KIND-------- VERSION------------- REPLACEMENT-- DEPRECATED-- DEPRECATED IN-- REMOVED-- REMOVED IN-- - // some name one-- pluto-namespace-- Deployment-- extensions/v1beta1-- apps/v1------ true-------- v1.9.0--------- true----- v1.16.0----- - // some name two-- <UNKNOWN>-------- Deployment-- extensions/v1beta1-- apps/v1------ true-------- v1.9.0--------- true----- v1.16.0----- + // NAME----------- NAMESPACE-------- KIND-------- VERSION------------- REPLACEMENT-- DEPRECATED-- DEPRECATED IN-- REMOVED-- REMOVED IN-- REPL AVAIL-- REPL AVAIL IN-- + // some name one-- pluto-namespace-- Deployment-- extensions/v1beta1-- apps/v1------ true-------- v1.9.0--------- true----- v1.16.0----- true-------- v1.10.0-------- + // some name two-- <UNKNOWN>-------- Deployment-- extensions/v1beta1-- apps/v1------ true-------- v1.9.0--------- true----- v1.16.0----- true-------- v1.10.0-------- } func ExampleInstance_DisplayOutput_custom() { @@ -187,10 +190,10 @@ _ = instance.DisplayOutput() // Output: - // | NAME | NAMESPACE | KIND | VERSION | REPLACEMENT | DEPRECATED | DEPRECATED IN | REMOVED | REMOVED IN | - // |---------------|-----------------|------------|--------------------|-------------|------------|---------------|---------|------------| - // | some name one | pluto-namespace | Deployment | extensions/v1beta1 | apps/v1 | true | v1.9.0 | true | v1.16.0 | - // | some name two | <UNKNOWN> | Deployment | extensions/v1beta1 | apps/v1 | true | v1.9.0 | true | v1.16.0 | + // | NAME | NAMESPACE | KIND | VERSION | REPLACEMENT | DEPRECATED | DEPRECATED IN | REMOVED | REMOVED IN | REPL AVAIL | REPL AVAIL IN | + // |---------------|-----------------|------------|--------------------|-------------|------------|---------------|---------|------------|------------|---------------| + // | some name one | pluto-namespace | Deployment | extensions/v1beta1 | apps/v1 | true | v1.9.0 | true | v1.16.0 | true | v1.10.0 | + // | some name two | <UNKNOWN> | Deployment | extensions/v1beta1 | apps/v1 | true | v1.9.0 | true | v1.16.0 | true | v1.10.0 | } func ExampleInstance_DisplayOutput_markdown_customcolumns() { @@ -230,7 +233,7 @@ _ = instance.DisplayOutput() // Output: - // {"items":[{"name":"some name one","filePath":"path-to-file","namespace":"pluto-namespace","api":{"version":"extensions/v1beta1","kind":"Deployment","deprecated-in":"v1.9.0","removed-in":"v1.16.0","replacement-api":"apps/v1","component":"foo"},"deprecated":true,"removed":true},{"name":"some name two","api":{"version":"extensions/v1beta1","kind":"Deployment","deprecated-in":"v1.9.0","removed-in":"v1.16.0","replacement-api":"apps/v1","component":"foo"},"deprecated":true,"removed":true}],"target-versions":{"foo":"v1.16.0"}} + // {"items":[{"name":"some name one","filePath":"path-to-file","namespace":"pluto-namespace","api":{"version":"extensions/v1beta1","kind":"Deployment","deprecated-in":"v1.9.0","removed-in":"v1.16.0","replacement-api":"apps/v1","replacement-available-in":"v1.10.0","component":"foo"},"deprecated":true,"removed":true,"replacementAvailable":true},{"name":"some name two","api":{"version":"extensions/v1beta1","kind":"Deployment","deprecated-in":"v1.9.0","removed-in":"v1.16.0","replacement-api":"apps/v1","replacement-available-in":"v1.10.0","component":"foo"},"deprecated":true,"removed":true,"replacementAvailable":true}],"target-versions":{"foo":"v1.16.0"}} } func ExampleInstance_DisplayOutput_yaml() { @@ -258,9 +261,11 @@ // deprecated-in: v1.9.0 // removed-in: v1.16.0 // replacement-api: apps/v1 + // replacement-available-in: v1.10.0 // component: foo // deprecated: true // removed: true + // replacementAvailable: true // - name: some name two // api: // version: extensions/v1beta1 @@ -268,9 +273,11 @@ // deprecated-in: v1.9.0 // removed-in: v1.16.0 // replacement-api: apps/v1 + // replacement-available-in: v1.10.0 // component: foo // deprecated: true // removed: true + // replacementAvailable: true // target-versions: // foo: v1.16.0 } @@ -290,9 +297,9 @@ _ = instance.DisplayOutput() // Output: - // NAME,NAMESPACE,KIND,VERSION,REPLACEMENT,DEPRECATED,DEPRECATED IN,REMOVED,REMOVED IN - // some name one,pluto-namespace,Deployment,extensions/v1beta1,apps/v1,true,v1.9.0,true,v1.16.0 - // some name two,<UNKNOWN>,Deployment,extensions/v1beta1,apps/v1,true,v1.9.0,true,v1.16.0 + // NAME,NAMESPACE,KIND,VERSION,REPLACEMENT,DEPRECATED,DEPRECATED IN,REMOVED,REMOVED IN,REPL AVAIL,REPL AVAIL IN + // some name one,pluto-namespace,Deployment,extensions/v1beta1,apps/v1,true,v1.9.0,true,v1.16.0,true,v1.10.0 + // some name two,<UNKNOWN>,Deployment,extensions/v1beta1,apps/v1,true,v1.9.0,true,v1.16.0,true,v1.10.0 } func ExampleInstance_DisplayOutput_csv_customcolumns() { @@ -332,8 +339,8 @@ _ = instance.DisplayOutput() // Output: - // some name one,pluto-namespace,Deployment,extensions/v1beta1,apps/v1,true,v1.9.0,true,v1.16.0 - // some name two,<UNKNOWN>,Deployment,extensions/v1beta1,apps/v1,true,v1.9.0,true,v1.16.0 + // some name one,pluto-namespace,Deployment,extensions/v1beta1,apps/v1,true,v1.9.0,true,v1.16.0,true,v1.10.0 + // some name two,<UNKNOWN>,Deployment,extensions/v1beta1,apps/v1,true,v1.9.0,true,v1.16.0,true,v1.10.0 } func ExampleInstance_DisplayOutput_noOutput() { @@ -368,9 +375,10 @@ func TestGetReturnCode(t *testing.T) { type args struct { - outputs []*Output - ignoreDeprecations bool - ignoreRemovals bool + outputs []*Output + ignoreDeprecations bool + ignoreRemovals bool + ignoreReplacementUnavailable bool } tests := []struct { name string @@ -380,13 +388,15 @@ { name: "empty return zero", args: args{ - outputs: []*Output{}, - ignoreDeprecations: false, + outputs: []*Output{}, + ignoreDeprecations: false, + ignoreRemovals: false, + ignoreReplacementUnavailable: false, }, want: 0, }, { - name: "version is deprecated return one", + name: "version is deprecated return two", args: args{ outputs: []*Output{ { @@ -397,8 +407,9 @@ }, }, }, - ignoreDeprecations: false, - ignoreRemovals: false, + ignoreDeprecations: false, + ignoreRemovals: false, + ignoreReplacementUnavailable: false, }, want: 2, }, @@ -414,8 +425,9 @@ }, }, }, - ignoreDeprecations: true, - ignoreRemovals: false, + ignoreDeprecations: true, + ignoreRemovals: false, + ignoreReplacementUnavailable: false, }, want: 0, }, @@ -431,10 +443,67 @@ }, }, }, + ignoreDeprecations: false, + ignoreRemovals: false, + ignoreReplacementUnavailable: false, + }, + want: 3, + }, + { + name: "version is removed and replacement is unavailable", + args: args{ + outputs: []*Output{ + { + APIVersion: &Version{ + DeprecatedIn: "v1.16.0", + RemovedIn: "v1.16.0", + ReplacementAvailableIn: "v1.17.0", + Component: "foo", + }, + }, + }, + ignoreDeprecations: false, + ignoreRemovals: false, + ignoreReplacementUnavailable: true, + }, + want: 3, + }, + { + name: "version is deprecated and replacement is unavailable", + args: args{ + outputs: []*Output{ + { + APIVersion: &Version{ + DeprecatedIn: "v1.16.0", + RemovedIn: "v1.20.0", + ReplacementAvailableIn: "v1.17.0", + Component: "foo", + }, + }, + }, ignoreDeprecations: false, ignoreRemovals: false, }, - want: 3, + want: 4, + }, + { + name: "version is deprecated and replacement is unavailable but ignored", + args: args{ + outputs: []*Output{ + { + APIVersion: &Version{ + DeprecatedIn: "v1.16.0", + RemovedIn: "v1.20.0", + ReplacementAvailableIn: "v1.17.0", + Component: "foo", + }, + }, + }, + ignoreDeprecations: false, + ignoreRemovals: false, + ignoreReplacementUnavailable: true, + }, + want: 0, }, } for _, tt := range tests { @@ -443,9 +512,10 @@ TargetVersions: map[string]string{ "foo": "v1.16.0", }, - IgnoreDeprecations: tt.args.ignoreDeprecations, - IgnoreRemovals: tt.args.ignoreRemovals, - Outputs: tt.args.outputs, + IgnoreDeprecations: tt.args.ignoreDeprecations, + IgnoreRemovals: tt.args.ignoreRemovals, + IgnoreUnavailableReplacements: tt.args.ignoreReplacementUnavailable, + Outputs: tt.args.outputs, } got := instance.GetReturnCode() assert.Equal(t, tt.want, got) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluto-5.13.4/pkg/api/versions.go new/pluto-5.15.1/pkg/api/versions.go --- old/pluto-5.13.4/pkg/api/versions.go 2023-02-20 18:46:37.000000000 +0100 +++ new/pluto-5.15.1/pkg/api/versions.go 2023-02-22 22:11:39.000000000 +0100 @@ -70,6 +70,8 @@ RemovedIn string `json:"removed-in" yaml:"removed-in"` // ReplacementAPI is the apiVersion that replaces the deprecated one ReplacementAPI string `json:"replacement-api" yaml:"replacement-api"` + // ReplacementAvailableIn is the version in which the replacement api is available + ReplacementAvailableIn string `json:"replacement-available-in" yaml:"replacement-available-in"` // Component is the component associated with this version Component string `json:"component" yaml:"component"` } @@ -240,6 +242,30 @@ return comparison >= 0 } +// isReplacementAvailableIn returns true if the replacement api is available in the applicable targetVersion +// Will return false if the targetVersion passed is not a valid semver string +func (v *Version) isReplacementAvailableIn(targetVersions map[string]string) bool { + for component, targetVersion := range targetVersions { + if !semver.IsValid(targetVersion) { + klog.V(3).Infof("targetVersion %s for %s is not valid semVer", targetVersion, component) + return false + } + } + + if v.ReplacementAvailableIn == "" { + return true + } + + targetVersion, ok := targetVersions[v.Component] + if !ok { + klog.V(3).Infof("targetVersion missing for component %s", v.Component) + return false + } + + comparison := semver.Compare(targetVersion, v.ReplacementAvailableIn) + return comparison >= 0 +} + // PrintVersionList prints out the list of versions // in a specific format func (instance *Instance) PrintVersionList(outputFormat string) error { @@ -282,7 +308,7 @@ w.Init(os.Stdout, 0, 15, 2, padChar, 0) if !instance.NoHeaders { - fmt.Fprintln(w, "KIND\t NAME\t DEPRECATED IN\t REMOVED IN\t REPLACEMENT\t COMPONENT\t") + fmt.Fprintln(w, "KIND\t NAME\t DEPRECATED IN\t REMOVED IN\t REPLACEMENT\t REPL AVAIL IN\t COMPONENT\t") } for _, version := range instance.DeprecatedVersions { @@ -300,7 +326,12 @@ replacementAPI = "n/a" } - _, _ = fmt.Fprintf(w, "%s\t %s\t %s\t %s\t %s\t %s\t\n", version.Kind, version.Name, deprecatedIn, removedIn, replacementAPI, version.Component) + replacementAvailableIn := version.ReplacementAvailableIn + if replacementAvailableIn == "" { + replacementAvailableIn = "n/a" + } + + _, _ = fmt.Fprintf(w, "%s\t %s\t %s\t %s\t %s\t %s\t %s\t\n", version.Kind, version.Name, deprecatedIn, removedIn, replacementAPI, replacementAvailableIn, version.Component) } err := w.Flush() if err != nil { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluto-5.13.4/pkg/api/versions_test.go new/pluto-5.15.1/pkg/api/versions_test.go --- old/pluto-5.13.4/pkg/api/versions_test.go 2023-02-20 18:46:37.000000000 +0100 +++ new/pluto-5.15.1/pkg/api/versions_test.go 2023-02-22 22:11:39.000000000 +0100 @@ -55,6 +55,7 @@ deprecated-in: v1.9.0 removed-in: v1.16.0 replacement-api: apps/v1 + replacement-available-in: v1.10.0 component: k8s target-versions: k8s: v1.16.0 @@ -62,12 +63,13 @@ cert-manager: v0.15.1` var testVersionDeployment = Version{ - Name: "extensions/v1beta1", - Kind: "Deployment", - DeprecatedIn: "v1.9.0", - RemovedIn: "v1.16.0", - ReplacementAPI: "apps/v1", - Component: "k8s", + Name: "extensions/v1beta1", + Kind: "Deployment", + DeprecatedIn: "v1.9.0", + RemovedIn: "v1.16.0", + ReplacementAPI: "apps/v1", + ReplacementAvailableIn: "v1.10.0", + Component: "k8s", } func Test_jsonToStub(t *testing.T) { @@ -425,34 +427,91 @@ } } +func TestVersion_isReplacementAvailableIn(t *testing.T) { + tests := []struct { + name string + targetVersions map[string]string + component string + want bool + replacementAvailableIn string + }{ + { + name: "not available yet 1.15.0", + targetVersions: map[string]string{"foo": "v1.15.0"}, + component: "foo", + replacementAvailableIn: "v1.16.0", + want: false, + }, + { + name: "equal values", + targetVersions: map[string]string{"foo": "v1.16.0"}, + component: "foo", + replacementAvailableIn: "v1.16.0", + want: true, + }, + { + name: "greater than", + targetVersions: map[string]string{"foo": "v1.17.0"}, + component: "foo", + replacementAvailableIn: "v1.16.0", + want: true, + }, + { + name: "bad semVer", + targetVersions: map[string]string{"foo": "foo"}, + replacementAvailableIn: "v1.16.0", + want: false, + }, + { + name: "blank replacementAvailableIn - is available", + targetVersions: map[string]string{"foo": "v1.16.0"}, + component: "foo", + replacementAvailableIn: "", + want: true, + }, + { + name: "targetVersions not included for component", + targetVersions: map[string]string{"one": "v1.16.0"}, + component: "two", + replacementAvailableIn: "v1.16.0", + want: false, + }, + } + for _, tt := range tests { + removedVersion := &Version{ReplacementAvailableIn: tt.replacementAvailableIn, Component: tt.component} + got := removedVersion.isReplacementAvailableIn(tt.targetVersions) + assert.Equal(t, tt.want, got, "test failed: "+tt.name) + } +} + func ExampleInstance_printVersionsTabular() { instance := Instance{ DeprecatedVersions: []Version{ testVersionDeployment, - {Kind: "testkind", Name: "testname", DeprecatedIn: "", RemovedIn: "", Component: "custom"}, + {Kind: "testkind", Name: "testname", DeprecatedIn: "", RemovedIn: "", ReplacementAvailableIn: "", Component: "custom"}, }, } _ = instance.printVersionsTabular() // Output: - // KIND-------- NAME---------------- DEPRECATED IN-- REMOVED IN-- REPLACEMENT-- COMPONENT-- - // Deployment-- extensions/v1beta1-- v1.9.0--------- v1.16.0----- apps/v1------ k8s-------- - // testkind---- testname------------ n/a------------ n/a--------- n/a---------- custom----- + // KIND-------- NAME---------------- DEPRECATED IN-- REMOVED IN-- REPLACEMENT-- REPL AVAIL IN-- COMPONENT-- + // Deployment-- extensions/v1beta1-- v1.9.0--------- v1.16.0----- apps/v1------ v1.10.0-------- k8s-------- + // testkind---- testname------------ n/a------------ n/a--------- n/a---------- n/a------------ custom----- } func ExampleInstance_printVersionsTabular_noHeaders() { instance := Instance{ DeprecatedVersions: []Version{ testVersionDeployment, - {Kind: "testkind", Name: "testname", DeprecatedIn: "", RemovedIn: "", Component: "custom"}, + {Kind: "testkind", Name: "testname", DeprecatedIn: "", RemovedIn: "", ReplacementAvailableIn: "", Component: "custom"}, }, NoHeaders: true, } _ = instance.printVersionsTabular() // Output: - // Deployment-- extensions/v1beta1-- v1.9.0-- v1.16.0-- apps/v1-- k8s----- - // testkind---- testname------------ n/a----- n/a------ n/a------ custom-- + // Deployment-- extensions/v1beta1-- v1.9.0-- v1.16.0-- apps/v1-- v1.10.0-- k8s----- + // testkind---- testname------------ n/a----- n/a------ n/a------ n/a------ custom-- } func ExampleInstance_PrintVersionList_json() { @@ -462,7 +521,7 @@ _ = instance.PrintVersionList("json") // Output: - // {"deprecated-versions":[{"version":"extensions/v1beta1","kind":"Deployment","deprecated-in":"v1.9.0","removed-in":"v1.16.0","replacement-api":"apps/v1","component":"k8s"}]} + // {"deprecated-versions":[{"version":"extensions/v1beta1","kind":"Deployment","deprecated-in":"v1.9.0","removed-in":"v1.16.0","replacement-api":"apps/v1","replacement-available-in":"v1.10.0","component":"k8s"}]} } func ExampleInstance_PrintVersionList_yaml() { @@ -478,6 +537,7 @@ // deprecated-in: v1.9.0 // removed-in: v1.16.0 // replacement-api: apps/v1 + // replacement-available-in: v1.10.0 // component: k8s } @@ -488,8 +548,8 @@ _ = instance.PrintVersionList("normal") // Output: - // KIND-------- NAME---------------- DEPRECATED IN-- REMOVED IN-- REPLACEMENT-- COMPONENT-- - // Deployment-- extensions/v1beta1-- v1.9.0--------- v1.16.0----- apps/v1------ k8s-------- + // KIND-------- NAME---------------- DEPRECATED IN-- REMOVED IN-- REPLACEMENT-- REPL AVAIL IN-- COMPONENT-- + // Deployment-- extensions/v1beta1-- v1.9.0--------- v1.16.0----- apps/v1------ v1.10.0-------- k8s-------- } func ExampleInstance_PrintVersionList_wide() { @@ -499,8 +559,8 @@ _ = instance.PrintVersionList("wide") // Output: - // KIND-------- NAME---------------- DEPRECATED IN-- REMOVED IN-- REPLACEMENT-- COMPONENT-- - // Deployment-- extensions/v1beta1-- v1.9.0--------- v1.16.0----- apps/v1------ k8s-------- + // KIND-------- NAME---------------- DEPRECATED IN-- REMOVED IN-- REPLACEMENT-- REPL AVAIL IN-- COMPONENT-- + // Deployment-- extensions/v1beta1-- v1.9.0--------- v1.16.0----- apps/v1------ v1.10.0-------- k8s-------- } func ExampleInstance_PrintVersionList_badformat() { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/pluto-5.13.4/versions.yaml new/pluto-5.15.1/versions.yaml --- old/pluto-5.13.4/versions.yaml 2023-02-20 18:46:37.000000000 +0100 +++ new/pluto-5.15.1/versions.yaml 2023-02-22 22:11:39.000000000 +0100 @@ -4,72 +4,84 @@ deprecated-in: v1.9.0 removed-in: v1.16.0 replacement-api: apps/v1 + replacement-available-in: v1.9.0 component: k8s - version: apps/v1beta2 kind: Deployment deprecated-in: v1.9.0 removed-in: v1.16.0 replacement-api: apps/v1 + replacement-available-in: v1.9.0 component: k8s - version: apps/v1beta1 kind: Deployment deprecated-in: v1.9.0 removed-in: v1.16.0 replacement-api: apps/v1 + replacement-available-in: v1.9.0 component: k8s - version: apps/v1beta1 kind: StatefulSet deprecated-in: v1.9.0 removed-in: v1.16.0 replacement-api: apps/v1 + replacement-available-in: v1.9.0 component: k8s - version: apps/v1beta2 kind: StatefulSet deprecated-in: v1.9.0 removed-in: v1.16.0 replacement-api: apps/v1 + replacement-available-in: v1.9.0 component: k8s - version: extensions/v1beta1 kind: NetworkPolicy deprecated-in: v1.9.0 removed-in: v1.16.0 replacement-api: networking.k8s.io/v1 + replacement-available-in: v1.8.0 component: k8s - version: extensions/v1beta1 kind: Ingress deprecated-in: v1.14.0 removed-in: v1.22.0 replacement-api: networking.k8s.io/v1 + replacement-available-in: v1.19.0 component: k8s - version: networking.k8s.io/v1beta1 kind: Ingress deprecated-in: v1.19.0 removed-in: v1.22.0 replacement-api: networking.k8s.io/v1 + replacement-available-in: v1.19.0 component: k8s - version: networking.k8s.io/v1beta1 kind: IngressClass deprecated-in: v1.19.0 removed-in: v1.22.0 replacement-api: networking.k8s.io/v1 + replacement-available-in: v1.19.0 component: k8s - version: apps/v1beta2 kind: DaemonSet deprecated-in: v1.9.0 removed-in: v1.16.0 replacement-api: apps/v1 + replacement-available-in: v1.9.0 component: k8s - version: extensions/v1beta1 kind: DaemonSet deprecated-in: v1.9.0 removed-in: v1.16.0 replacement-api: apps/v1 + replacement-available-in: v1.9.0 component: k8s - version: extensions/v1beta1 kind: PodSecurityPolicy deprecated-in: v1.10.0 removed-in: v1.16.0 replacement-api: policy/v1beta1 + replacement-available-in: v1.10.0 component: k8s - version: policy/v1beta1 kind: PodSecurityPolicy @@ -82,24 +94,28 @@ deprecated-in: "" removed-in: v1.16.0 replacement-api: apps/v1 + replacement-available-in: v1.9.0 component: k8s - version: apps/v1beta1 kind: ReplicaSet deprecated-in: "" removed-in: v1.16.0 replacement-api: apps/v1 + replacement-available-in: v1.9.0 component: k8s - version: apps/v1beta2 kind: ReplicaSet deprecated-in: "" removed-in: v1.16.0 replacement-api: apps/v1 + replacement-available-in: v1.9.0 component: k8s - version: scheduling.k8s.io/v1beta1 kind: PriorityClass deprecated-in: v1.14.0 removed-in: v1.22.0 replacement-api: scheduling.k8s.io/v1 + replacement-available-in: v1.14.0 component: k8s - version: scheduling.k8s.io/v1alpha1 kind: PriorityClass @@ -112,30 +128,35 @@ deprecated-in: v1.16.0 removed-in: v1.22.0 replacement-api: apiextensions.k8s.io/v1 + replacement-available-in: v1.16.0 component: k8s - version: admissionregistration.k8s.io/v1beta1 kind: MutatingWebhookConfiguration deprecated-in: v1.16.0 removed-in: v1.22.0 replacement-api: admissionregistration.k8s.io/v1 + replacement-available-in: v1.16.0 component: k8s - version: admissionregistration.k8s.io/v1beta1 kind: ValidatingWebhookConfiguration deprecated-in: v1.16.0 removed-in: v1.22.0 replacement-api: admissionregistration.k8s.io/v1 + replacement-available-in: v1.16.0 component: k8s - version: rbac.authorization.k8s.io/v1alpha1 kind: ClusterRoleBinding deprecated-in: v1.17.0 removed-in: v1.22.0 replacement-api: rbac.authorization.k8s.io/v1 + replacement-available-in: v1.8.0 component: k8s - version: rbac.authorization.k8s.io/v1alpha1 kind: ClusterRole deprecated-in: v1.17.0 removed-in: v1.22.0 replacement-api: rbac.authorization.k8s.io/v1 + replacement-available-in: v1.8.0 component: k8s - version: rbac.authorization.k8s.io/v1alpha1 kind: ClusterRoleBindingList @@ -154,12 +175,14 @@ deprecated-in: v1.17.0 removed-in: v1.22.0 replacement-api: rbac.authorization.k8s.io/v1 + replacement-available-in: v1.8.0 component: k8s - version: rbac.authorization.k8s.io/v1alpha1 kind: RoleBinding deprecated-in: v1.17.0 removed-in: v1.22.0 replacement-api: rbac.authorization.k8s.io/v1 + replacement-available-in: v1.8.0 component: k8s - version: rbac.authorization.k8s.io/v1alpha1 kind: RoleList @@ -221,11 +244,19 @@ removed-in: v1.22.0 replacement-api: rbac.authorization.k8s.io/v1 component: k8s + - version: node.k8s.io/v1beta1 + kind: RuntimeClass + deprecated-in: v1.22.0 + removed-in: v1.25.0 + replacement-api: node.k8s.io/v1 + replacement-available-in: v1.20.0 + component: k8s - version: policy/v1beta1 kind: PodDisruptionBudget deprecated-in: v1.21.0 removed-in: v1.25.0 replacement-api: policy/v1 + replacement-available-in: v1.21.0 component: k8s - version: policy/v1beta1 kind: PodDisruptionBudgetList @@ -238,6 +269,7 @@ deprecated-in: v1.22.0 removed-in: v1.25.0 replacement-api: autoscaling/v2 + replacement-available-in: v1.23.0 component: k8s - version: autoscaling/v2beta1 kind: HorizontalPodAutoscalerList @@ -260,6 +292,7 @@ - version: batch/v1beta1 kind: CronJob replacement-api: batch/v1 + replacement-available-in: v1.21.0 deprecated-in: v1.21.0 removed-in: v1.25.0 component: k8s @@ -274,40 +307,47 @@ deprecated-in: v1.17.0 removed-in: v1.22.0 replacement-api: storage.k8s.io/v1 + replacement-available-in: v1.17.0 component: k8s - version: storage.k8s.io/v1beta1 kind: CSIDriver deprecated-in: v1.19.0 removed-in: v1.22.0 replacement-api: storage.k8s.io/v1 + replacement-available-in: v1.19.0 component: k8s - version: storage.k8s.io/v1beta1 kind: CSIStorageCapacity deprecated-in: v1.24.0 removed-in: v1.27.0 replacement-api: storage.k8s.io/v1 + replacement-available-in: v1.24.0 component: k8s - version: storage.k8s.io/v1beta1 kind: StorageClass deprecated-in: v1.6.0 removed-in: v1.22.0 replacement-api: storage.k8s.io/v1 + replacement-available-in: v1.6.0 component: k8s - version: storage.k8s.io/v1beta1 kind: VolumeAttachment deprecated-in: v1.13.0 removed-in: v1.22.0 replacement-api: storage.k8s.io/v1 + replacement-available-in: v1.13.0 component: k8s - version: apiregistration.k8s.io/v1beta1 kind: APIService removed-in: v1.22.0 deprecated-in: v1.10.0 replacement-api: apiregistration.k8s.io/v1 + replacement-available-in: v1.10.0 component: k8s - version: authentication.k8s.io/v1beta1 kind: TokenReview replacement-api: authentication.k8s.io/v1 + replacement-available-in: v1.6.0 deprecated-in: v1.6.0 removed-in: v1.22.0 component: k8s @@ -316,22 +356,26 @@ deprecated-in: v1.19.0 removed-in: v1.22.0 replacement-api: certificates.k8s.io/v1 + replacement-available-in: v1.19.0 component: k8s - version: coordination.k8s.io/v1beta1 kind: Lease replacement-api: coordination.k8s.io/v1 + replacement-available-in: v1.14.0 deprecated-in: v1.14.0 removed-in: v1.22.0 component: k8s - version: events.k8s.io/v1beta1 kind: Event replacement-api: events.k8s.io/v1 + replacement-available-in: v1.19.0 deprecated-in: v1.19.0 removed-in: v1.25.0 component: k8s - version: discovery.k8s.io/v1beta1 kind: EndpointSlice replacement-api: discovery.k8s.io/v1 + replacement-available-in: v1.21.0 deprecated-in: v1.21.0 removed-in: v1.25.0 component: k8s ++++++ vendor.tar.gz ++++++ /work/SRC/openSUSE:Factory/pluto/vendor.tar.gz /work/SRC/openSUSE:Factory/.pluto.new.1706/vendor.tar.gz differ: char 5, line 1