package kustomize import ( "fmt" "os" "path/filepath" "strings" "github.com/bazelbuild/bazel-gazelle/language" "github.com/bazelbuild/bazel-gazelle/resolve" "sigs.k8s.io/kustomize/api/filters/fsslice" "sigs.k8s.io/kustomize/api/types" "sigs.k8s.io/kustomize/kyaml/kio" "sigs.k8s.io/kustomize/kyaml/yaml" "edge-infra.dev/pkg/k8s/eyaml/fieldspecs" ) type filter struct { FsSlice types.FsSlice } var filteredImages = []string{} // GenerateBases generates (deprecated) base references to file srcs as well as // Kustomization dependencies func GenerateBases(args language.GenerateArgs, bases []string) ([]string, []resolve.ImportSpec, error) { var kustomizeImports []resolve.ImportSpec var srcs []string for _, b := range bases { absPath := filepath.Join(args.Dir, b) fi, err := os.Stat(absPath) if err != nil { fmt.Println(err) return nil, nil, err } if fi.IsDir() { kustomizeImports = append(kustomizeImports, toImportSpec(args.Rel, b)) } else { srcs = append(srcs, b) } } return srcs, kustomizeImports, nil } // GenerateComponents returns a list of resolve.ImportSpecs referring to any Component // dependencies func GenerateComponents(args language.GenerateArgs, components []string) []resolve.ImportSpec { var kustomizeImports []resolve.ImportSpec for _, d := range components { kustomizeImports = append(kustomizeImports, toImportSpec(args.Rel, d)) } return kustomizeImports } // GenerateConfigmapGenerators func GenerateConfigmapGenerators(args language.GenerateArgs, cmGens []types.ConfigMapArgs) []string { var srcs []string for _, cmga := range cmGens { // cmga.EnvSource is a single source if cmga.EnvSource != "" { if filepath.IsLocal(cmga.EnvSource) { srcs = append(srcs, cmga.EnvSource) } else { srcs = append(srcs, toRemoteSrc(args.Rel, cmga.EnvSource)) } continue } // cmga.EnvSources is a list of sources if len(cmga.EnvSources) > 0 { for _, f := range cmga.EnvSources { if filepath.IsLocal(f) { srcs = append(srcs, f) } else { srcs = append(srcs, toRemoteSrc(args.Rel, f)) } } } // cmga.FileSources is a list of file sources if len(cmga.FileSources) > 0 { for _, f := range cmga.FileSources { if filepath.IsLocal(f) { srcs = append(srcs, f) } else { srcs = append(srcs, toRemoteSrc(args.Rel, f)) } } } } return srcs } // GenerateConfigurations takes a Kustomization's configurations attributes and returns // a list of file srcs func GenerateConfigurations(args language.GenerateArgs, configurations []string) []string { var srcs []string for _, c := range configurations { if filepath.IsLocal(c) { srcs = append(srcs, c) continue } srcs = append(srcs, toRemoteSrc(args.Rel, c)) } return srcs } // GeneratePatches returns a list of file srcs for Patch items func GeneratePatches(args language.GenerateArgs, patches []types.Patch) []string { var srcs []string for _, p := range patches { if p.Path != "" { if filepath.IsLocal(p.Path) { srcs = append(srcs, p.Path) continue } srcs = append(srcs, toRemoteSrc(args.Rel, p.Path)) } } return srcs } // GeneratePatchesJSON6902 returns a list of file srcs for PatchesJSON6902 func GeneratePatchesJSON6902(args language.GenerateArgs, patchesJSON6902 []types.Patch) []string { var srcs []string for _, p := range patchesJSON6902 { if p.Path != "" { if filepath.IsLocal(p.Path) { srcs = append(srcs, p.Path) continue } srcs = append(srcs, toRemoteSrc(args.Rel, p.Path)) } } return srcs } // GeneratePatchesStrategicMerge returns a list of file srcs for PatchStrategicMerge items func GeneratePatchesStrategicMerge(args language.GenerateArgs, patchesStrategicMerge []types.Patch) ([]string, []resolve.ImportSpec, error) { var kustomizeImports []resolve.ImportSpec var srcs []string for _, psm := range patchesStrategicMerge { psmStr := psm.Patch absPath := filepath.Join(args.Dir, psmStr) fi, err := os.Stat(absPath) if err != nil { fmt.Println(err) return nil, nil, err } if fi.IsDir() { kustomizeImports = append(kustomizeImports, toImportSpec(args.Rel, psmStr)) } else { srcs = append(srcs, psmStr) } } return srcs, kustomizeImports, nil } // GenerateResources takes a Kustomization's resource attributes and returns a list of // file srcs and Kustomization dependencies as resolve.ImportSpecs func GenerateResources(args language.GenerateArgs, resources []string) ([]string, []string, []resolve.ImportSpec, error) { var kustomizeImports []resolve.ImportSpec var srcs []string // imgs := make(map[string]string) imgs := []string{} for _, r := range resources { rPath := filepath.Join(args.Dir, r) fi, err := os.Stat(rPath) if err != nil { fmt.Println(err) return nil, nil, nil, err } // Resources that are dirs must be Kustomizations if fi.IsDir() { kustomizeImports = append(kustomizeImports, toImportSpec(args.Rel, r)) continue } // If resource is a file reference, check if it can be directly referenced if filepath.IsLocal(r) { imgs, err = GenerateImages(rPath, imgs) if err != nil { fmt.Println(err) return nil, nil, nil, err } srcs = append(srcs, r) continue } // If it lives in another package, create a remote src reference srcs = append(srcs, toRemoteSrc(args.Rel, r)) } return srcs, imgs, kustomizeImports, nil } func GenerateImages(resource string, imgs []string) ([]string, error) { f, err := os.Open(resource) if err != nil { return nil, fmt.Errorf("failed to open file at %s: %w", resource, err) } rdr := kio.ByteReader{Reader: f} rns, err := rdr.Read() if err != nil { return nil, fmt.Errorf("failed to read with ByteReader: %w", err) } // Leverage a filter so that refs can be found with the same fieldspecs // used in rules_kustomize fltr := filter{ FsSlice: fieldspecs.Images, } _, err = kio.FilterAll(fltr).Filter(rns) if err != nil { return nil, fmt.Errorf("filter failed: %w", err) } for _, img := range filteredImages { // If the workloads or third_party repo is found, it points to an image reference // to be resolved by kustomizations if strings.HasPrefix(img, "us-east1-docker.pkg.dev/ret-edge-pltf-infra/workloads") || strings.HasPrefix(img, "us-east1-docker.pkg.dev/ret-edge-pltf-infra/thirdparty") || strings.HasPrefix(img, "us-east1-docker.pkg.dev/ret-edge-f8ngang2/f8n-sandbox") { imgs = append(imgs, img) } } // Reset slice for next generation filteredImages = []string{} return imgs, nil } // TODO(wc185097_ncrvoyix): refactor, can likely just use a fsslice.Filter func (f filter) Filter(node *yaml.RNode) (*yaml.RNode, error) { return node.Pipe(fsslice.Filter{ FsSlice: f.FsSlice, SetValue: f.getRef, }) } func (f filter) getRef(rn *yaml.RNode) error { // TODO(wc185097_ncrvoyix): is this check necessary? if err := yaml.ErrorIfInvalid(rn, yaml.ScalarNode); err != nil { return err } value := rn.YNode().Value filteredImages = append(filteredImages, value) return nil }