github.com/aporeto-inc/trireme-lib@v10.358.0+incompatible/monitor/extractors/docker.go (about) 1 package extractors 2 3 import ( 4 "encoding/json" 5 "errors" 6 "fmt" 7 "os" 8 "os/exec" 9 "strconv" 10 "strings" 11 12 "github.com/docker/docker/api/types" 13 "go.aporeto.io/enforcerd/trireme-lib/common" 14 "go.aporeto.io/enforcerd/trireme-lib/monitor/constants" 15 "go.aporeto.io/enforcerd/trireme-lib/policy" 16 "go.aporeto.io/enforcerd/trireme-lib/utils/cgnetcls" 17 "go.aporeto.io/enforcerd/trireme-lib/utils/portspec" 18 ) 19 20 // A DockerMetadataExtractor is a function used to extract a *policy.PURuntime from a given 21 // docker ContainerJSON. 22 type DockerMetadataExtractor func(*types.ContainerJSON) (*policy.PURuntime, error) 23 24 // DefaultMetadataExtractor is the default metadata extractor for Docker 25 func DefaultMetadataExtractor(info *types.ContainerJSON) (*policy.PURuntime, error) { 26 27 // trigger new build 28 tags := policy.NewTagStore() 29 tags.AppendKeyValue("@app:image", info.Config.Image) 30 tags.AppendKeyValue("@app:extractor", "docker") 31 tags.AppendKeyValue("@app:docker:name", info.Name) 32 33 for k, v := range info.Config.Labels { 34 if len(strings.TrimSpace(k)) == 0 { 35 continue 36 } 37 value := v 38 if len(v) == 0 { 39 value = "<empty>" 40 } 41 if !strings.HasPrefix(k, constants.UserLabelPrefix) { 42 tags.AppendKeyValue(constants.UserLabelPrefix+k, value) 43 } else { 44 tags.AppendKeyValue(k, value) 45 } 46 } 47 48 ipa := policy.ExtendedMap{ 49 "bridge": info.NetworkSettings.IPAddress, 50 } 51 52 if info.HostConfig.NetworkMode == constants.DockerHostMode { 53 return policy.NewPURuntime(info.Name, info.State.Pid, "", tags, ipa, common.LinuxProcessPU, policy.None, hostModeOptions(info)), nil 54 } 55 56 return policy.NewPURuntime(info.Name, info.State.Pid, "", tags, ipa, common.ContainerPU, policy.None, nil), nil 57 } 58 59 // hostModeOptions creates the default options for a host-mode container. This is done 60 // based on the policy and the metadata extractor logic and can very by implementation 61 func hostModeOptions(dockerInfo *types.ContainerJSON) *policy.OptionsType { 62 63 options := policy.OptionsType{ 64 CgroupName: strconv.Itoa(dockerInfo.State.Pid), 65 CgroupMark: strconv.FormatUint(cgnetcls.MarkVal(), 10), 66 AutoPort: true, 67 } 68 69 for p := range dockerInfo.Config.ExposedPorts { 70 if p.Proto() == "tcp" { 71 s, err := portspec.NewPortSpecFromString(p.Port(), nil) 72 if err != nil { 73 continue 74 } 75 76 options.Services = append(options.Services, common.Service{ 77 Protocol: uint8(6), 78 Ports: s, 79 }) 80 } 81 } 82 83 return &options 84 } 85 86 // NewExternalExtractor returns a new bash metadata extractor for Docker that will call 87 // the executable given in parameter and will generate a Policy Runtime as standard output 88 // The format of Input/Output of the executable are in standard JSON. 89 func NewExternalExtractor(filePath string) (DockerMetadataExtractor, error) { 90 91 if filePath == "" { 92 return nil, errors.New("file argument is empty in bash extractor") 93 } 94 95 path, err := exec.LookPath(filePath) 96 if err != nil { 97 return nil, fmt.Errorf("exec file not found %s: %s", filePath, err) 98 } 99 100 if _, err := os.Stat(path); os.IsNotExist(err) { 101 return nil, fmt.Errorf("exec file not found %s: %s", filePath, err) 102 } 103 104 // Generate a new function 105 externalExtractor := func(dockerInfo *types.ContainerJSON) (*policy.PURuntime, error) { 106 107 dockerInfoJSON, err := json.Marshal(dockerInfo) 108 if err != nil { 109 return nil, fmt.Errorf("unable to marshal docker info: %s", err) 110 } 111 112 cmd := exec.Command(path, string(dockerInfoJSON)) 113 jsonResult, err := cmd.Output() 114 if err != nil { 115 return nil, fmt.Errorf("unable to run bash extractor: %s", err) 116 } 117 118 var m policy.PURuntime 119 err = json.Unmarshal(jsonResult, &m) 120 if err != nil { 121 return nil, fmt.Errorf("unable to unmarshal data from bash extractor: %s", err) 122 } 123 124 return &m, nil 125 } 126 127 return externalExtractor, nil 128 }