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