1 package podman
2
3 import (
4 "bufio"
5 "bytes"
6 "context"
7 "encoding/json"
8 "fmt"
9 "os/exec"
10 "strings"
11 "time"
12
13 corev1 "k8s.io/api/core/v1"
14 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
15 "k8s.io/apimachinery/pkg/watch"
16 "k8s.io/klog"
17
18 "github.com/redhat-developer/odo/pkg/platform"
19 )
20
21
22 func (o *PodmanCli) GetPodsMatchingSelector(selector string) (*corev1.PodList, error) {
23 podsReport, err := o.getPodsFromSelector(selector)
24 if err != nil {
25 return nil, err
26 }
27
28 var result corev1.PodList
29 for _, podReport := range podsReport {
30 pod, err := o.KubeGenerate(podReport.Name)
31 if err != nil {
32
33 continue
34 }
35
36
37 for c := range pod.Spec.Containers {
38 container := &pod.Spec.Containers[c]
39 prefix := pod.GetName() + "-"
40 container.Name = strings.TrimPrefix(container.Name, prefix)
41 }
42 inspect, err := o.PodInspect(podReport.Name)
43 if err != nil {
44
45 continue
46 }
47 pod.Status.Phase = corev1.PodPhase(inspect.State)
48
49 result.Items = append(result.Items, *pod)
50 }
51 return &result, nil
52 }
53
54
55 func (o *PodmanCli) GetAllResourcesFromSelector(selector string, _ string) ([]unstructured.Unstructured, error) {
56 list, err := o.getPodsFromSelector(selector)
57 if err != nil {
58 return nil, err
59 }
60 for _, pod := range list {
61 klog.V(5).Infof("\npod name: %s", pod.Name)
62 klog.V(5).Infof("labels:")
63 for k, v := range pod.Labels {
64 klog.V(5).Infof(" - %s: %s", k, v)
65 }
66 }
67
68 var result []unstructured.Unstructured
69 for _, pod := range list {
70 u := unstructured.Unstructured{}
71 u.SetName(pod.Name)
72 u.SetLabels(pod.Labels)
73 result = append(result, u)
74 }
75
76 return result, nil
77 }
78
79
80 func (o *PodmanCli) GetAllPodsInNamespaceMatchingSelector(selector string, ns string) (*corev1.PodList, error) {
81
82 return o.GetPodsMatchingSelector(selector)
83 }
84
85
86
87 func (o *PodmanCli) GetRunningPodFromSelector(selector string) (*corev1.Pod, error) {
88 list, err := o.getPodsFromSelector(selector)
89 if err != nil {
90 return nil, err
91 }
92 numPods := len(list)
93 if numPods == 0 {
94 return nil, &platform.PodNotFoundError{Selector: selector}
95 } else if numPods > 1 {
96 return nil, fmt.Errorf("multiple Pods exist for the selector: %v. Only one must be present", selector)
97 }
98
99 podReport := list[0]
100 var pod corev1.Pod
101 pod.SetName(podReport.Name)
102 pod.SetLabels(podReport.Labels)
103
104 inspect, err := o.PodInspect(podReport.Name)
105 if err != nil {
106 return nil, err
107 }
108 if inspect.State != "Running" {
109 return nil, fmt.Errorf("a pod exists but is not in Running state. Current status=%v", inspect.State)
110 }
111
112 for _, container := range podReport.Containers {
113
114 if !strings.HasPrefix(container.Names, podReport.Name+"-") {
115 continue
116 }
117 pod.Spec.Containers = append(pod.Spec.Containers, corev1.Container{
118 Name: strings.TrimPrefix(container.Names, podReport.Name+"-"),
119 })
120 }
121 return &pod, nil
122 }
123
124 func (o *PodmanCli) getPodsFromSelector(selector string) ([]ListPodsReport, error) {
125 args := []string{"pod", "ps", "--format", "json"}
126 selectorAsList := strings.Split(selector, ",")
127 for _, s := range selectorAsList {
128 args = append(args, "--filter=label="+s)
129 }
130 cmd := exec.Command(o.podmanCmd, append(o.containerRunGlobalExtraArgs, args...)...)
131 klog.V(3).Infof("executing %v", cmd.Args)
132 out, err := cmd.Output()
133 if err != nil {
134 if exiterr, ok := err.(*exec.ExitError); ok {
135 err = fmt.Errorf("%s: %s", err, string(exiterr.Stderr))
136 }
137 return nil, err
138 }
139 var list []ListPodsReport
140 if err = json.Unmarshal(out, &list); err != nil {
141 return nil, err
142 }
143 return list, nil
144 }
145
146 type podWatcher struct {
147 stop chan struct{}
148 pods map[string]struct{}
149 events chan watch.Event
150 }
151
152 func (o *PodmanCli) PodWatcher(ctx context.Context, selector string) (watch.Interface, error) {
153
154 watcher := podWatcher{
155 stop: make(chan struct{}),
156 pods: make(map[string]struct{}),
157 events: make(chan watch.Event),
158 }
159 go watcher.watch(o.podmanCmd, o.containerRunGlobalExtraArgs)
160 return watcher, nil
161 }
162
163 func (o podWatcher) watch(podmanCmd string, containerRunGlobalExtraArgs []string) {
164 args := []string{"ps", "--quiet"}
165 args = append(containerRunGlobalExtraArgs, args...)
166 ticker := time.NewTicker(3 * time.Second)
167 for {
168 select {
169 case <-o.stop:
170 return
171 case <-ticker.C:
172 cmd := exec.Command(podmanCmd, args...)
173 out, err := cmd.Output()
174 if err != nil {
175 klog.V(4).Infof("error getting containers from podman: %s", err)
176 continue
177 }
178 scanner := bufio.NewScanner(bytes.NewReader(out))
179 currentPods := make(map[string]struct{})
180 for scanner.Scan() {
181 podName := scanner.Text()
182 currentPods[podName] = struct{}{}
183 if _, ok := o.pods[podName]; !ok {
184 o.events <- watch.Event{
185 Type: watch.Added,
186 }
187 o.pods[podName] = struct{}{}
188 }
189 }
190 for p := range o.pods {
191 if _, ok := currentPods[p]; !ok {
192 o.events <- watch.Event{
193 Type: watch.Deleted,
194 }
195 delete(o.pods, p)
196 }
197 }
198 }
199 }
200 }
201
202 func (o podWatcher) Stop() {
203 o.stop <- struct{}{}
204 }
205
206 func (o podWatcher) ResultChan() <-chan watch.Event {
207 return o.events
208 }
209
View as plain text