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