istio.io/istio@v0.0.0-20240520182934-d79c90f27776/operator/cmd/mesh/profile-diff.go (about) 1 // Copyright Istio Authors 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package mesh 16 17 import ( 18 "fmt" 19 "io" 20 "os" 21 22 "github.com/spf13/cobra" 23 24 "istio.io/istio/operator/pkg/manifest" 25 "istio.io/istio/operator/pkg/util" 26 "istio.io/istio/operator/pkg/util/clog" 27 ) 28 29 type profileDiffArgs struct { 30 // manifestsPath is a path to a charts and profiles directory in the local filesystem with a release tgz. 31 manifestsPath string 32 } 33 34 func addProfileDiffFlags(cmd *cobra.Command, args *profileDiffArgs) { 35 cmd.PersistentFlags().StringVarP(&args.manifestsPath, "charts", "", "", ChartsDeprecatedStr) 36 cmd.PersistentFlags().StringVarP(&args.manifestsPath, "manifests", "d", "", ManifestsFlagHelpStr) 37 } 38 39 func profileDiffCmd(pfArgs *profileDiffArgs) *cobra.Command { 40 return &cobra.Command{ 41 Use: "diff <profile|file1.yaml> <profile|file2.yaml>", 42 Short: "Diffs two Istio configuration profiles", 43 Long: "The diff subcommand displays the differences between two Istio configuration profiles.", 44 Example: ` # Profile diff by providing yaml files 45 istioctl profile diff manifests/profiles/default.yaml manifests/profiles/demo.yaml 46 47 # Profile diff by providing a profile name 48 istioctl profile diff default demo`, 49 Args: func(cmd *cobra.Command, args []string) error { 50 if len(args) != 2 { 51 return fmt.Errorf("diff requires two profiles") 52 } 53 return nil 54 }, 55 RunE: func(cmd *cobra.Command, args []string) error { 56 isdifferent, err := profileDiff(cmd, pfArgs, args) 57 if err != nil { 58 return err 59 } 60 if isdifferent { 61 os.Exit(1) 62 } 63 return nil 64 }, 65 } 66 } 67 68 // profileDiff compare two profile files. 69 func profileDiff(cmd *cobra.Command, pfArgs *profileDiffArgs, args []string) (bool, error) { 70 l := clog.NewConsoleLogger(cmd.OutOrStdout(), cmd.OutOrStderr(), nil) 71 setFlags := make([]string, 0) 72 if pfArgs.manifestsPath != "" { 73 setFlags = append(setFlags, fmt.Sprintf("installPackagePath=%s", pfArgs.manifestsPath)) 74 } 75 return profileDiffInternal(args[0], args[1], setFlags, cmd.OutOrStdout(), l) 76 } 77 78 func profileDiffInternal(profileA, profileB string, setFlags []string, writer io.Writer, l clog.Logger) (bool, error) { 79 a, _, err := manifest.GenIOPFromProfile(profileA, "", setFlags, true, true, nil, l) 80 if err != nil { 81 return false, fmt.Errorf("could not read %q: %v", profileA, err) 82 } 83 84 b, _, err := manifest.GenIOPFromProfile(profileB, "", setFlags, true, true, nil, l) 85 if err != nil { 86 return false, fmt.Errorf("could not read %q: %v", profileB, err) 87 } 88 89 diff := util.YAMLDiff(a, b) 90 if diff == "" { 91 fmt.Fprintln(writer, "Profiles are identical") 92 } else { 93 fmt.Fprintf(writer, "The difference between profiles:\n%s", diff) 94 return true, nil 95 } 96 97 return false, nil 98 }