github.com/sealerio/sealer@v0.11.1-0.20240507115618-f4f89c5853ae/pkg/imageengine/buildah/inspect.go (about) 1 // Copyright © 2022 Alibaba Group Holding Ltd. 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 buildah 16 17 import ( 18 "fmt" 19 "sort" 20 "strings" 21 22 "github.com/containers/buildah" 23 ociv1 "github.com/opencontainers/image-spec/specs-go/v1" 24 "github.com/pkg/errors" 25 "k8s.io/apimachinery/pkg/util/json" 26 27 "github.com/sealerio/sealer/build/kubefile/command" 28 imagev1 "github.com/sealerio/sealer/pkg/define/image/v1" 29 "github.com/sealerio/sealer/pkg/define/options" 30 ) 31 32 func (engine *Engine) Inspect(opts *options.InspectOptions) (*imagev1.ImageSpec, error) { 33 if len(opts.ImageNameOrID) == 0 { 34 return nil, errors.Errorf("image name or image id must be specified") 35 } 36 37 var ( 38 builder *buildah.Builder 39 err error 40 ) 41 42 ctx := getContext() 43 store := engine.ImageStore() 44 newSystemCxt := engine.SystemContext() 45 name := opts.ImageNameOrID 46 47 builder, err = openImage(ctx, newSystemCxt, store, name) 48 if err != nil { 49 return nil, err 50 } 51 52 builderInfo := buildah.GetBuildInfo(builder) 53 var manifest = ociv1.Manifest{} 54 if err := json.Unmarshal([]byte(builderInfo.Manifest), &manifest); err != nil { 55 return nil, errors.Wrapf(err, "failed to get manifest") 56 } 57 58 if len(manifest.Annotations) != 0 { 59 delete(manifest.Annotations, imagev1.SealerImageExtension) 60 delete(manifest.Annotations, imagev1.SealerImageContainerImageList) 61 } 62 63 imageExtension, err := getImageExtensionFromAnnotations(builderInfo.ImageAnnotations) 64 if err != nil { 65 return nil, errors.Wrapf(err, "failed to get %s in image %s", imagev1.SealerImageExtension, opts.ImageNameOrID) 66 } 67 68 imageExtension.Labels = handleImageLabelOutput(builderInfo.OCIv1.Config.Labels) 69 70 // NOTE: avoid duplicate content output 71 builderInfo.OCIv1.Config.Labels = nil 72 73 containerImageList, err := getContainerImagesFromAnnotations(builderInfo.ImageAnnotations) 74 if err != nil { 75 return nil, errors.Wrapf(err, "failed to get %s in image %s", imagev1.SealerImageContainerImageList, opts.ImageNameOrID) 76 } 77 78 result := &imagev1.ImageSpec{ 79 ID: builderInfo.FromImageID, 80 Name: builderInfo.FromImage, 81 Digest: builderInfo.FromImageDigest, 82 ManifestV1: manifest, 83 OCIv1: builderInfo.OCIv1, 84 ImageExtension: imageExtension, 85 ContainerImageList: containerImageList, 86 } 87 88 return result, nil 89 } 90 91 func getImageExtensionFromAnnotations(annotations map[string]string) (imagev1.ImageExtension, error) { 92 extension := imagev1.ImageExtension{} 93 extensionStr := annotations[imagev1.SealerImageExtension] 94 if len(extensionStr) == 0 { 95 return extension, fmt.Errorf("%s does not exist", imagev1.SealerImageExtension) 96 } 97 98 if err := json.Unmarshal([]byte(extensionStr), &extension); err != nil { 99 return extension, errors.Wrapf(err, "failed to unmarshal %v", imagev1.SealerImageExtension) 100 } 101 return extension, nil 102 } 103 104 func getContainerImagesFromAnnotations(annotations map[string]string) ([]*imagev1.ContainerImage, error) { 105 var containerImageList []*imagev1.ContainerImage 106 annotationStr := annotations[imagev1.SealerImageContainerImageList] 107 if len(annotationStr) == 0 { 108 return nil, nil 109 } 110 111 if err := json.Unmarshal([]byte(annotationStr), &containerImageList); err != nil { 112 return nil, errors.Wrapf(err, "failed to unmarshal %v", imagev1.SealerImageContainerImageList) 113 } 114 return containerImageList, nil 115 } 116 117 func handleImageLabelOutput(labels map[string]string) map[string]string { 118 if len(labels) == 0 { 119 return labels 120 } 121 122 var result = make(map[string]string) 123 var supportedCNI []string 124 var supportedCSI []string 125 for k, v := range labels { 126 if strings.HasPrefix(k, command.LabelKubeCNIPrefix) { 127 supportedCNI = append(supportedCNI, strings.TrimPrefix(k, command.LabelKubeCNIPrefix)) 128 continue 129 } 130 if strings.HasPrefix(k, command.LabelKubeCSIPrefix) { 131 supportedCSI = append(supportedCSI, strings.TrimPrefix(k, command.LabelKubeCSIPrefix)) 132 continue 133 } 134 result[k] = v 135 } 136 137 if len(supportedCNI) != 0 { 138 sort.Strings(supportedCNI) 139 supportedCNIJSON, _ := json.Marshal(supportedCNI) 140 result[command.LabelSupportedKubeCNIAlpha] = string(supportedCNIJSON) 141 } 142 if len(supportedCSI) != 0 { 143 sort.Strings(supportedCSI) 144 supportedCSIJSON, _ := json.Marshal(supportedCSI) 145 result[command.LabelSupportedKubeCSIAlpha] = string(supportedCSIJSON) 146 } 147 148 return result 149 }