github.com/inspektor-gadget/inspektor-gadget@v0.28.1/pkg/oci/build_metadata.go (about) 1 // Copyright 2023-2024 The Inspektor Gadget 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 oci 16 17 import ( 18 "bytes" 19 "context" 20 "fmt" 21 "os" 22 23 "github.com/cilium/ebpf" 24 log "github.com/sirupsen/logrus" 25 "gopkg.in/yaml.v2" 26 27 "github.com/inspektor-gadget/inspektor-gadget/pkg/gadgets/run/types" 28 metadatav1 "github.com/inspektor-gadget/inspektor-gadget/pkg/metadata/v1" 29 ) 30 31 func loadSpec(progContent []byte) (*ebpf.CollectionSpec, error) { 32 progReader := bytes.NewReader(progContent) 33 spec, err := ebpf.LoadCollectionSpecFromReader(progReader) 34 if err != nil { 35 return nil, fmt.Errorf("loading spec: %w", err) 36 } 37 return spec, err 38 } 39 40 // getAnySpec returns the spec for any architecture found. It's used to generate the metadata so we 41 // don't care about the architecture this file was generated for. 42 func getAnySpec(opts *BuildGadgetImageOpts) (*ebpf.CollectionSpec, error) { 43 var progPath string 44 45 // TODO: we could perform a sanity check to be sure different architectures generate the 46 // same metadata, but that's too much for now. 47 // We're validating the metadata at runtime, so a possible error will be caught there. 48 for _, paths := range opts.ObjectPaths { 49 progPath = paths.EBPF 50 break 51 } 52 53 if progPath == "" { 54 return nil, fmt.Errorf("no eBPF object file found") 55 } 56 57 progContent, err := os.ReadFile(progPath) 58 if err != nil { 59 return nil, fmt.Errorf("reading eBPF object file: %w", err) 60 } 61 62 return loadSpec(progContent) 63 } 64 65 func validateMetadataFile(ctx context.Context, opts *BuildGadgetImageOpts) error { 66 metadataFile, err := os.Open(opts.MetadataPath) 67 if err != nil { 68 return fmt.Errorf("opening metadata file: %w", err) 69 } 70 defer metadataFile.Close() 71 72 metadata := &metadatav1.GadgetMetadata{} 73 if err := yaml.NewDecoder(metadataFile).Decode(metadata); err != nil { 74 return fmt.Errorf("decoding metadata file: %w", err) 75 } 76 77 spec, err := getAnySpec(opts) 78 if err != nil { 79 return fmt.Errorf("loading spec: %w", err) 80 } 81 82 return types.Validate(metadata, spec) 83 } 84 85 func createOrUpdateMetadataFile(ctx context.Context, opts *BuildGadgetImageOpts) error { 86 spec, err := getAnySpec(opts) 87 if err != nil { 88 return fmt.Errorf("loading spec: %w", err) 89 } 90 91 _, statErr := os.Stat(opts.MetadataPath) 92 update := statErr == nil 93 94 metadata := &metadatav1.GadgetMetadata{} 95 96 if update { 97 // load metadata file 98 metadataFile, err := os.Open(opts.MetadataPath) 99 if err != nil { 100 return fmt.Errorf("opening metadata file: %w", err) 101 } 102 defer metadataFile.Close() 103 104 if err := yaml.NewDecoder(metadataFile).Decode(metadata); err != nil { 105 return fmt.Errorf("decoding metadata file: %w", err) 106 } 107 108 log.Debugf("Metadata file found, updating it") 109 110 // TODO: this validation could be softer, just printing warnings 111 if err := types.Validate(metadata, spec); err != nil { 112 return fmt.Errorf("metadata file is wrong, fix it before continuing: %w", err) 113 } 114 } else { 115 log.Debug("Metadata file not found, generating it") 116 } 117 118 if err := types.Populate(metadata, spec); err != nil { 119 return fmt.Errorf("populating metadata: %w", err) 120 } 121 122 marshalled, err := yaml.Marshal(metadata) 123 if err != nil { 124 return err 125 } 126 127 if err := os.WriteFile(opts.MetadataPath, marshalled, 0o644); err != nil { 128 return fmt.Errorf("writing metadata file: %w", err) 129 } 130 131 // fix owner of created metadata file 132 if !update { 133 if err := fixOwner(opts.MetadataPath, opts.EBPFSourcePath); err != nil { 134 log.Warnf("Failed to fix metadata file owner: %v", err) 135 } 136 } 137 138 return nil 139 }