github.com/containers/podman/v2@v2.2.2-0.20210501105131-c1e07d070c4c/pkg/varlinkapi/util.go (about) 1 // +build varlink 2 3 package varlinkapi 4 5 import ( 6 "context" 7 "strconv" 8 "strings" 9 "time" 10 11 "github.com/containers/buildah" 12 "github.com/containers/podman/v2/libpod" 13 "github.com/containers/podman/v2/libpod/define" 14 "github.com/containers/podman/v2/pkg/channel" 15 iopodman "github.com/containers/podman/v2/pkg/varlink" 16 "github.com/containers/storage/pkg/archive" 17 ) 18 19 // getContext returns a non-nil, empty context 20 func getContext() context.Context { 21 return context.TODO() 22 } 23 24 func makeListContainer(containerID string, batchInfo BatchContainerStruct) iopodman.Container { 25 var ( 26 mounts []iopodman.ContainerMount 27 ports []iopodman.ContainerPortMappings 28 ) 29 ns := GetNamespaces(batchInfo.Pid) 30 31 for _, mount := range batchInfo.ConConfig.Spec.Mounts { 32 m := iopodman.ContainerMount{ 33 Destination: mount.Destination, 34 Type: mount.Type, 35 Source: mount.Source, 36 Options: mount.Options, 37 } 38 mounts = append(mounts, m) 39 } 40 41 for _, pm := range batchInfo.ConConfig.PortMappings { 42 p := iopodman.ContainerPortMappings{ 43 Host_port: strconv.Itoa(int(pm.HostPort)), 44 Host_ip: pm.HostIP, 45 Protocol: pm.Protocol, 46 Container_port: strconv.Itoa(int(pm.ContainerPort)), 47 } 48 ports = append(ports, p) 49 50 } 51 52 // If we find this needs to be done for other container endpoints, we should 53 // convert this to a separate function or a generic map from struct function. 54 namespace := iopodman.ContainerNameSpace{ 55 User: ns.User, 56 Uts: ns.UTS, 57 Pidns: ns.PIDNS, 58 Pid: ns.PID, 59 Cgroup: ns.Cgroup, 60 Net: ns.NET, 61 Mnt: ns.MNT, 62 Ipc: ns.IPC, 63 } 64 65 lc := iopodman.Container{ 66 Id: containerID, 67 Image: batchInfo.ConConfig.RootfsImageName, 68 Imageid: batchInfo.ConConfig.RootfsImageID, 69 Command: batchInfo.ConConfig.Spec.Process.Args, 70 Createdat: batchInfo.ConConfig.CreatedTime.Format(time.RFC3339), 71 Runningfor: time.Since(batchInfo.ConConfig.CreatedTime).String(), 72 Status: batchInfo.ConState.String(), 73 Ports: ports, 74 Names: batchInfo.ConConfig.Name, 75 Labels: batchInfo.ConConfig.Labels, 76 Mounts: mounts, 77 Containerrunning: batchInfo.ConState == define.ContainerStateRunning, 78 Namespaces: namespace, 79 } 80 if batchInfo.Size != nil { 81 lc.Rootfssize = batchInfo.Size.RootFsSize 82 lc.Rwsize = batchInfo.Size.RwSize 83 } 84 return lc 85 } 86 87 func makeListPodContainers(containerID string, batchInfo BatchContainerStruct) iopodman.ListPodContainerInfo { 88 lc := iopodman.ListPodContainerInfo{ 89 Id: containerID, 90 Status: batchInfo.ConState.String(), 91 Name: batchInfo.ConConfig.Name, 92 } 93 return lc 94 } 95 96 func makeListPod(pod *libpod.Pod, batchInfo PsOptions) (iopodman.ListPodData, error) { 97 var listPodsContainers []iopodman.ListPodContainerInfo 98 var errPodData = iopodman.ListPodData{} 99 status, err := pod.GetPodStatus() 100 if err != nil { 101 return errPodData, err 102 } 103 containers, err := pod.AllContainers() 104 if err != nil { 105 return errPodData, err 106 } 107 for _, ctr := range containers { 108 batchInfo, err := BatchContainerOp(ctr, batchInfo) 109 if err != nil { 110 return errPodData, err 111 } 112 113 listPodsContainers = append(listPodsContainers, makeListPodContainers(ctr.ID(), batchInfo)) 114 } 115 listPod := iopodman.ListPodData{ 116 Createdat: pod.CreatedTime().Format(time.RFC3339), 117 Id: pod.ID(), 118 Name: pod.Name(), 119 Status: status, 120 Cgroup: pod.CgroupParent(), 121 Numberofcontainers: strconv.Itoa(len(listPodsContainers)), 122 Containersinfo: listPodsContainers, 123 } 124 return listPod, nil 125 } 126 127 func handlePodCall(call iopodman.VarlinkCall, pod *libpod.Pod, ctrErrs map[string]error, err error) error { 128 if err != nil && ctrErrs == nil { 129 return call.ReplyErrorOccurred(err.Error()) 130 } 131 if ctrErrs != nil { 132 containerErrs := make([]iopodman.PodContainerErrorData, len(ctrErrs)) 133 for ctr, reason := range ctrErrs { 134 ctrErr := iopodman.PodContainerErrorData{Containerid: ctr, Reason: reason.Error()} 135 containerErrs = append(containerErrs, ctrErr) 136 } 137 return call.ReplyPodContainerError(pod.ID(), containerErrs) 138 } 139 140 return nil 141 } 142 143 func stringCompressionToArchiveType(s string) archive.Compression { 144 switch strings.ToUpper(s) { 145 case "BZIP2": 146 return archive.Bzip2 147 case "GZIP": 148 return archive.Gzip 149 case "XZ": 150 return archive.Xz 151 } 152 return archive.Uncompressed 153 } 154 155 func stringPullPolicyToType(s string) buildah.PullPolicy { 156 switch strings.ToUpper(s) { 157 case "PULLIFMISSING": 158 return buildah.PullIfMissing 159 case "PULLALWAYS": 160 return buildah.PullAlways 161 case "PULLNEVER": 162 return buildah.PullNever 163 } 164 return buildah.PullIfMissing 165 } 166 167 func derefBool(inBool *bool) bool { 168 if inBool == nil { 169 return false 170 } 171 return *inBool 172 } 173 174 func derefString(in *string) string { 175 if in == nil { 176 return "" 177 } 178 return *in 179 } 180 181 func makePsOpts(inOpts iopodman.PsOpts) PsOptions { 182 last := 0 183 if inOpts.Last != nil { 184 lastT := *inOpts.Last 185 last = int(lastT) 186 } 187 return PsOptions{ 188 All: inOpts.All, 189 Last: last, 190 Latest: derefBool(inOpts.Latest), 191 NoTrunc: derefBool(inOpts.NoTrunc), 192 Pod: derefBool(inOpts.Pod), 193 Size: derefBool(inOpts.Size), 194 Sort: derefString(inOpts.Sort), 195 Namespace: true, 196 Sync: derefBool(inOpts.Sync), 197 } 198 } 199 200 // forwardOutput is a helper method for varlink endpoints that employ both more and without 201 // more. it is capable of sending updates as the output writer gets them or append them 202 // all to a log. the chan error is the error from the libpod call so we can honor 203 // and error event in that case. 204 func forwardOutput(log []string, c chan error, wantsMore bool, output channel.WriteCloser, reply func(br iopodman.MoreResponse) error) ([]string, error) { 205 done := false 206 for { 207 select { 208 // We need to check if the libpod func being called has returned an 209 // error yet 210 case err := <-c: 211 if err != nil { 212 return nil, err 213 } 214 done = true 215 // if no error is found, we pull what we can from the log writer and 216 // append it to log string slice 217 case line := <-output.Chan(): 218 log = append(log, string(line)) 219 // If the end point is being used in more mode, send what we have 220 if wantsMore { 221 br := iopodman.MoreResponse{ 222 Logs: log, 223 } 224 if err := reply(br); err != nil { 225 return nil, err 226 } 227 // "reset" the log to empty because we are sending what we 228 // get as we get it 229 log = []string{} 230 } 231 } 232 if done { 233 break 234 } 235 } 236 return log, nil 237 }