2017-11-01 18:59:11 +00:00
|
|
|
package libpod
|
|
|
|
|
|
|
|
import (
|
2017-11-13 18:40:21 +00:00
|
|
|
"fmt"
|
2017-11-01 18:59:11 +00:00
|
|
|
"os"
|
|
|
|
"path/filepath"
|
2018-08-10 18:46:59 +00:00
|
|
|
"sort"
|
2018-02-16 15:38:12 +00:00
|
|
|
"strconv"
|
2017-11-14 14:55:00 +00:00
|
|
|
"strings"
|
2017-11-13 18:40:21 +00:00
|
|
|
"time"
|
2017-11-24 17:31:46 +00:00
|
|
|
|
|
|
|
"github.com/containers/image/signature"
|
|
|
|
"github.com/containers/image/types"
|
2018-02-16 15:38:12 +00:00
|
|
|
spec "github.com/opencontainers/runtime-spec/specs-go"
|
2017-12-04 21:06:06 +00:00
|
|
|
"github.com/pkg/errors"
|
2017-11-01 18:59:11 +00:00
|
|
|
)
|
|
|
|
|
2017-11-14 14:55:00 +00:00
|
|
|
// 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://"
|
|
|
|
)
|
|
|
|
|
2017-11-01 18:59:11 +00:00
|
|
|
// WriteFile writes a provided string to a provided path
|
|
|
|
func WriteFile(content string, path string) error {
|
|
|
|
baseDir := filepath.Dir(path)
|
|
|
|
if baseDir != "" {
|
2018-01-10 13:51:02 +00:00
|
|
|
if _, err := os.Stat(baseDir); err != nil {
|
2017-11-01 18:59:11 +00:00
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
f, err := os.Create(path)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer f.Close()
|
|
|
|
f.WriteString(content)
|
|
|
|
f.Sync()
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2017-11-13 18:40:21 +00:00
|
|
|
// 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)
|
|
|
|
}
|
2017-11-24 17:31:46 +00:00
|
|
|
|
|
|
|
// 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)
|
|
|
|
}
|
2017-12-04 21:06:06 +00:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
2018-02-16 15:38:12 +00:00
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
2018-02-27 18:51:43 +00:00
|
|
|
|
|
|
|
// WaitForFile waits until a file has been created or the given timeout has occurred
|
|
|
|
func WaitForFile(path string, timeout time.Duration) error {
|
|
|
|
done := make(chan struct{})
|
|
|
|
chControl := make(chan struct{})
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
select {
|
|
|
|
case <-chControl:
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
_, err := os.Stat(path)
|
|
|
|
if err == nil {
|
|
|
|
close(done)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
time.Sleep(25 * time.Millisecond)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
select {
|
|
|
|
case <-done:
|
|
|
|
return nil
|
|
|
|
case <-time.After(timeout):
|
|
|
|
close(chControl)
|
|
|
|
return errors.Wrapf(ErrInternal, "timed out waiting for file %s", path)
|
|
|
|
}
|
|
|
|
}
|
2018-08-10 18:46:59 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|
2018-08-23 17:33:10 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
}
|