github.com/kata-containers/runtime@v0.0.0-20210505125100-04f29832a923/virtcontainers/pkg/compatoci/utils.go (about) 1 // Copyright (c) 2017 Intel Corporation 2 // 3 // SPDX-License-Identifier: Apache-2.0 4 // 5 6 package compatoci 7 8 import ( 9 "encoding/json" 10 "fmt" 11 "io/ioutil" 12 "path/filepath" 13 14 specs "github.com/opencontainers/runtime-spec/specs-go" 15 "github.com/sirupsen/logrus" 16 17 vcAnnotations "github.com/kata-containers/runtime/virtcontainers/pkg/annotations" 18 ) 19 20 var ociLog = logrus.WithFields(logrus.Fields{ 21 "source": "virtcontainers", 22 "subsystem": "compatoci", 23 }) 24 25 // compatOCIProcess is a structure inheriting from specs.Process defined 26 // in runtime-spec/specs-go package. The goal is to be compatible with 27 // both v1.0.0-rc4 and v1.0.0-rc5 since the latter introduced a change 28 // about the type of the Capabilities field. 29 // Refer to: https://github.com/opencontainers/runtime-spec/commit/37391fb 30 type compatOCIProcess struct { 31 specs.Process 32 Capabilities interface{} `json:"capabilities,omitempty" platform:"linux"` //nolint:govet 33 } 34 35 // compatOCISpec is a structure inheriting from specs.Spec defined 36 // in runtime-spec/specs-go package. It relies on the compatOCIProcess 37 // structure declared above, in order to be compatible with both 38 // v1.0.0-rc4 and v1.0.0-rc5. 39 // Refer to: https://github.com/opencontainers/runtime-spec/commit/37391fb 40 type compatOCISpec struct { 41 specs.Spec 42 Process *compatOCIProcess `json:"process,omitempty"` //nolint:govet 43 } 44 45 func containerCapabilities(s compatOCISpec) (specs.LinuxCapabilities, error) { 46 capabilities := s.Process.Capabilities 47 var c specs.LinuxCapabilities 48 49 // In spec v1.0.0-rc4, capabilities was a list of strings. This was changed 50 // to an object with v1.0.0-rc5. 51 // Check for the interface type to support both the versions. 52 switch caps := capabilities.(type) { 53 case map[string]interface{}: 54 for key, value := range caps { 55 switch val := value.(type) { 56 case []interface{}: 57 var list []string 58 59 for _, str := range val { 60 list = append(list, str.(string)) 61 } 62 63 switch key { 64 case "bounding": 65 c.Bounding = list 66 case "effective": 67 c.Effective = list 68 case "inheritable": 69 c.Inheritable = list 70 case "ambient": 71 c.Ambient = list 72 case "permitted": 73 c.Permitted = list 74 } 75 76 default: 77 return c, fmt.Errorf("Unexpected format for capabilities: %v", caps) 78 } 79 } 80 case []interface{}: 81 var list []string 82 for _, str := range caps { 83 list = append(list, str.(string)) 84 } 85 86 c = specs.LinuxCapabilities{ 87 Bounding: list, 88 Effective: list, 89 Inheritable: list, 90 Ambient: list, 91 Permitted: list, 92 } 93 case nil: 94 ociLog.Debug("Empty capabilities have been passed") 95 return c, nil 96 default: 97 return c, fmt.Errorf("Unexpected format for capabilities: %v", caps) 98 } 99 100 return c, nil 101 } 102 103 // SetLogger sets up a logger for this pkg 104 func SetLogger(logger *logrus.Entry) { 105 fields := ociLog.Data 106 107 ociLog = logger.WithFields(fields) 108 } 109 110 // ContainerCapabilities return a LinuxCapabilities for virtcontainer 111 func ContainerCapabilities(s compatOCISpec) (specs.LinuxCapabilities, error) { 112 if s.Process == nil { 113 return specs.LinuxCapabilities{}, fmt.Errorf("ContainerCapabilities, Process is nil") 114 } 115 return containerCapabilities(s) 116 } 117 118 // getConfigPath returns the full config path from the bundle 119 // path provided. 120 func getConfigPath(bundlePath string) string { 121 return filepath.Join(bundlePath, "config.json") 122 } 123 124 // ParseConfigJSON unmarshals the config.json file. 125 func ParseConfigJSON(bundlePath string) (specs.Spec, error) { 126 configPath := getConfigPath(bundlePath) 127 ociLog.Debugf("converting %s", configPath) 128 129 configByte, err := ioutil.ReadFile(configPath) 130 if err != nil { 131 return specs.Spec{}, err 132 } 133 134 var compSpec compatOCISpec 135 if err := json.Unmarshal(configByte, &compSpec); err != nil { 136 return specs.Spec{}, err 137 } 138 139 caps, err := ContainerCapabilities(compSpec) 140 if err != nil { 141 return specs.Spec{}, err 142 } 143 144 compSpec.Spec.Process = &compSpec.Process.Process 145 compSpec.Spec.Process.Capabilities = &caps 146 147 return compSpec.Spec, nil 148 } 149 150 func GetContainerSpec(annotations map[string]string) (specs.Spec, error) { 151 if bundlePath, ok := annotations[vcAnnotations.BundlePathKey]; ok { 152 return ParseConfigJSON(bundlePath) 153 } 154 155 ociLog.Errorf("Annotations[%s] not found, cannot find container spec", 156 vcAnnotations.BundlePathKey) 157 return specs.Spec{}, fmt.Errorf("Could not find container spec") 158 }