1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
package libpod
import (
"fmt"
"os"
"path/filepath"
"sort"
"strconv"
"strings"
"time"
"github.com/containerd/cgroups"
"github.com/containers/image/signature"
"github.com/containers/image/types"
"github.com/containers/libpod/pkg/util"
"github.com/fsnotify/fsnotify"
spec "github.com/opencontainers/runtime-spec/specs-go"
"github.com/pkg/errors"
)
// Runtime API constants
const (
// DefaultTransport is a prefix that we apply to an image name
// to check docker hub first for the image
DefaultTransport = "docker://"
)
// OpenExclusiveFile opens a file for writing and ensure it doesn't already exist
func OpenExclusiveFile(path string) (*os.File, error) {
baseDir := filepath.Dir(path)
if baseDir != "" {
if _, err := os.Stat(baseDir); err != nil {
return nil, err
}
}
return os.OpenFile(path, os.O_RDWR|os.O_CREATE|os.O_EXCL, 0666)
}
// FuncTimer helps measure the execution time of a function
// For debug purposes, do not leave in code
// used like defer FuncTimer("foo")
func FuncTimer(funcName string) {
elapsed := time.Since(time.Now())
fmt.Printf("%s executed in %d ms\n", funcName, elapsed)
}
// CopyStringStringMap deep copies a map[string]string and returns the result
func CopyStringStringMap(m map[string]string) map[string]string {
n := map[string]string{}
for k, v := range m {
n[k] = v
}
return n
}
// GetPolicyContext creates a signature policy context for the given signature policy path
func GetPolicyContext(path string) (*signature.PolicyContext, error) {
policy, err := signature.DefaultPolicy(&types.SystemContext{SignaturePolicyPath: path})
if err != nil {
return nil, err
}
return signature.NewPolicyContext(policy)
}
// RemoveScientificNotationFromFloat returns a float without any
// scientific notation if the number has any.
// golang does not handle conversion of float64s that have scientific
// notation in them and otherwise stinks. please replace this if you have
// a better implementation.
func RemoveScientificNotationFromFloat(x float64) (float64, error) {
bigNum := strconv.FormatFloat(x, 'g', -1, 64)
breakPoint := strings.IndexAny(bigNum, "Ee")
if breakPoint > 0 {
bigNum = bigNum[:breakPoint]
}
result, err := strconv.ParseFloat(bigNum, 64)
if err != nil {
return x, errors.Wrapf(err, "unable to remove scientific number from calculations")
}
return result, nil
}
// MountExists returns true if dest exists in the list of mounts
func MountExists(specMounts []spec.Mount, dest string) bool {
for _, m := range specMounts {
if m.Destination == dest {
return true
}
}
return false
}
// WaitForFile waits until a file has been created or the given timeout has occurred
func WaitForFile(path string, chWait chan error, timeout time.Duration) (bool, error) {
done := make(chan struct{})
chControl := make(chan struct{})
var inotifyEvents chan fsnotify.Event
var timer chan struct{}
watcher, err := fsnotify.NewWatcher()
if err == nil {
if err := watcher.Add(filepath.Dir(path)); err == nil {
inotifyEvents = watcher.Events
}
defer watcher.Close()
}
if inotifyEvents == nil {
// If for any reason we fail to create the inotify
// watcher, fallback to polling the file
timer = make(chan struct{})
go func() {
select {
case <-chControl:
close(timer)
return
default:
time.Sleep(25 * time.Millisecond)
timer <- struct{}{}
}
}()
}
go func() {
for {
select {
case <-chControl:
return
case <-timer:
_, err := os.Stat(path)
if err == nil {
close(done)
return
}
case <-inotifyEvents:
_, err := os.Stat(path)
if err == nil {
close(done)
return
}
}
}
}()
select {
case e := <-chWait:
return true, e
case <-done:
return false, nil
case <-time.After(timeout):
close(chControl)
return false, errors.Wrapf(ErrInternal, "timed out waiting for file %s", path)
}
}
type byDestination []spec.Mount
func (m byDestination) Len() int {
return len(m)
}
func (m byDestination) Less(i, j int) bool {
return m.parts(i) < m.parts(j)
}
func (m byDestination) Swap(i, j int) {
m[i], m[j] = m[j], m[i]
}
func (m byDestination) parts(i int) int {
return strings.Count(filepath.Clean(m[i].Destination), string(os.PathSeparator))
}
func sortMounts(m []spec.Mount) []spec.Mount {
sort.Sort(byDestination(m))
return m
}
func validPodNSOption(p *Pod, ctrPod string) error {
if p == nil {
return errors.Wrapf(ErrInvalidArg, "pod passed in was nil. Container may not be associated with a pod")
}
if ctrPod == "" {
return errors.Wrapf(ErrInvalidArg, "container is not a member of any pod")
}
if ctrPod != p.ID() {
return errors.Wrapf(ErrInvalidArg, "pod passed in is not the pod the container is associated with")
}
return nil
}
// GetV1CGroups gets the V1 cgroup subsystems and then "filters"
// out any subsystems that are provided by the caller. Passing nil
// for excludes will return the subsystems unfiltered.
//func GetV1CGroups(excludes []string) ([]cgroups.Subsystem, error) {
func GetV1CGroups(excludes []string) cgroups.Hierarchy {
return func() ([]cgroups.Subsystem, error) {
var filtered []cgroups.Subsystem
subSystem, err := cgroups.V1()
if err != nil {
return nil, err
}
for _, s := range subSystem {
// If the name of the subsystem is not in the list of excludes, then
// add it as a keeper.
if !util.StringInSlice(string(s.Name()), excludes) {
filtered = append(filtered, s)
}
}
return filtered, nil
}
}
|