mirror of https://github.com/containers/podman.git
				
				
				
			
		
			
				
	
	
		
			200 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
			
		
		
	
	
			200 lines
		
	
	
		
			4.9 KiB
		
	
	
	
		
			Go
		
	
	
	
| package libpod
 | |
| 
 | |
| import (
 | |
| 	"fmt"
 | |
| 	"os"
 | |
| 	"path/filepath"
 | |
| 	"sort"
 | |
| 	"strconv"
 | |
| 	"strings"
 | |
| 	"time"
 | |
| 
 | |
| 	"github.com/containers/image/signature"
 | |
| 	"github.com/containers/image/types"
 | |
| 	"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
 | |
| }
 | |
| 
 | |
| // JSONDeepCopy performs a deep copy by performing a JSON encode/decode of the
 | |
| // given structures. From and To should be identically typed structs.
 | |
| func JSONDeepCopy(from, to interface{}) error {
 | |
| 	tmp, err := json.Marshal(from)
 | |
| 	if err != nil {
 | |
| 		return err
 | |
| 	}
 | |
| 	return json.Unmarshal(tmp, to)
 | |
| }
 |