github.com/yuyangjack/moby@v0.0.0-20190814082046-288be08dc2ec/api/common.go (about)

     1  package api
     2  
     3  import (
     4  	"encoding/json"
     5  	"encoding/pem"
     6  	"fmt"
     7  	"mime"
     8  	"os"
     9  	"path/filepath"
    10  	"sort"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"github.com/sirupsen/logrus"
    15  	"github.com/docker/docker/api/types"
    16  	"github.com/docker/docker/pkg/ioutils"
    17  	"github.com/docker/docker/pkg/system"
    18  	"github.com/docker/libtrust"
    19  )
    20  
    21  // Common constants for daemon and client.
    22  const (
    23  	// DefaultVersion of Current REST API
    24  	DefaultVersion string = "1.26"
    25  
    26  	// NoBaseImageSpecifier is the symbol used by the FROM
    27  	// command to specify that no base image is to be used.
    28  	NoBaseImageSpecifier string = "scratch"
    29  )
    30  
    31  // byPortInfo is a temporary type used to sort types.Port by its fields
    32  type byPortInfo []types.Port
    33  
    34  func (r byPortInfo) Len() int      { return len(r) }
    35  func (r byPortInfo) Swap(i, j int) { r[i], r[j] = r[j], r[i] }
    36  func (r byPortInfo) Less(i, j int) bool {
    37  	if r[i].PrivatePort != r[j].PrivatePort {
    38  		return r[i].PrivatePort < r[j].PrivatePort
    39  	}
    40  
    41  	if r[i].IP != r[j].IP {
    42  		return r[i].IP < r[j].IP
    43  	}
    44  
    45  	if r[i].PublicPort != r[j].PublicPort {
    46  		return r[i].PublicPort < r[j].PublicPort
    47  	}
    48  
    49  	return r[i].Type < r[j].Type
    50  }
    51  
    52  // DisplayablePorts returns formatted string representing open ports of container
    53  // e.g. "0.0.0.0:80->9090/tcp, 9988/tcp"
    54  // it's used by command 'docker ps'
    55  func DisplayablePorts(ports []types.Port) string {
    56  	type portGroup struct {
    57  		first uint16
    58  		last  uint16
    59  	}
    60  	groupMap := make(map[string]*portGroup)
    61  	var result []string
    62  	var hostMappings []string
    63  	var groupMapKeys []string
    64  	sort.Sort(byPortInfo(ports))
    65  	for _, port := range ports {
    66  		current := port.PrivatePort
    67  		portKey := port.Type
    68  		if port.IP != "" {
    69  			if port.PublicPort != current {
    70  				hostMappings = append(hostMappings, fmt.Sprintf("%s:%d->%d/%s", port.IP, port.PublicPort, port.PrivatePort, port.Type))
    71  				continue
    72  			}
    73  			portKey = fmt.Sprintf("%s/%s", port.IP, port.Type)
    74  		}
    75  		group := groupMap[portKey]
    76  
    77  		if group == nil {
    78  			groupMap[portKey] = &portGroup{first: current, last: current}
    79  			// record order that groupMap keys are created
    80  			groupMapKeys = append(groupMapKeys, portKey)
    81  			continue
    82  		}
    83  		if current == (group.last + 1) {
    84  			group.last = current
    85  			continue
    86  		}
    87  
    88  		result = append(result, formGroup(portKey, group.first, group.last))
    89  		groupMap[portKey] = &portGroup{first: current, last: current}
    90  	}
    91  	for _, portKey := range groupMapKeys {
    92  		g := groupMap[portKey]
    93  		result = append(result, formGroup(portKey, g.first, g.last))
    94  	}
    95  	result = append(result, hostMappings...)
    96  	return strings.Join(result, ", ")
    97  }
    98  
    99  func formGroup(key string, start, last uint16) string {
   100  	parts := strings.Split(key, "/")
   101  	groupType := parts[0]
   102  	var ip string
   103  	if len(parts) > 1 {
   104  		ip = parts[0]
   105  		groupType = parts[1]
   106  	}
   107  	group := strconv.Itoa(int(start))
   108  	if start != last {
   109  		group = fmt.Sprintf("%s-%d", group, last)
   110  	}
   111  	if ip != "" {
   112  		group = fmt.Sprintf("%s:%s->%s", ip, group, group)
   113  	}
   114  	return fmt.Sprintf("%s/%s", group, groupType)
   115  }
   116  
   117  // MatchesContentType validates the content type against the expected one
   118  func MatchesContentType(contentType, expectedType string) bool {
   119  	mimetype, _, err := mime.ParseMediaType(contentType)
   120  	if err != nil {
   121  		logrus.Errorf("Error parsing media type: %s error: %v", contentType, err)
   122  	}
   123  	return err == nil && mimetype == expectedType
   124  }
   125  
   126  // LoadOrCreateTrustKey attempts to load the libtrust key at the given path,
   127  // otherwise generates a new one
   128  func LoadOrCreateTrustKey(trustKeyPath string) (libtrust.PrivateKey, error) {
   129  	err := system.MkdirAll(filepath.Dir(trustKeyPath), 0700)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  	trustKey, err := libtrust.LoadKeyFile(trustKeyPath)
   134  	if err == libtrust.ErrKeyFileDoesNotExist {
   135  		trustKey, err = libtrust.GenerateECP256PrivateKey()
   136  		if err != nil {
   137  			return nil, fmt.Errorf("Error generating key: %s", err)
   138  		}
   139  		encodedKey, err := serializePrivateKey(trustKey, filepath.Ext(trustKeyPath))
   140  		if err != nil {
   141  			return nil, fmt.Errorf("Error serializing key: %s", err)
   142  		}
   143  		if err := ioutils.AtomicWriteFile(trustKeyPath, encodedKey, os.FileMode(0600)); err != nil {
   144  			return nil, fmt.Errorf("Error saving key file: %s", err)
   145  		}
   146  	} else if err != nil {
   147  		return nil, fmt.Errorf("Error loading key file %s: %s", trustKeyPath, err)
   148  	}
   149  	return trustKey, nil
   150  }
   151  
   152  func serializePrivateKey(key libtrust.PrivateKey, ext string) (encoded []byte, err error) {
   153  	if ext == ".json" || ext == ".jwk" {
   154  		encoded, err = json.Marshal(key)
   155  		if err != nil {
   156  			return nil, fmt.Errorf("unable to encode private key JWK: %s", err)
   157  		}
   158  	} else {
   159  		pemBlock, err := key.PEMBlock()
   160  		if err != nil {
   161  			return nil, fmt.Errorf("unable to encode private key PEM: %s", err)
   162  		}
   163  		encoded = pem.EncodeToMemory(pemBlock)
   164  	}
   165  	return
   166  }