github.com/Shopify/docker@v1.13.1/runconfig/config.go (about)

     1  package runconfig
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"io"
     7  
     8  	"github.com/docker/docker/api/types/container"
     9  	networktypes "github.com/docker/docker/api/types/network"
    10  	"github.com/docker/docker/pkg/sysinfo"
    11  	"github.com/docker/docker/volume"
    12  )
    13  
    14  // ContainerDecoder implements httputils.ContainerDecoder
    15  // calling DecodeContainerConfig.
    16  type ContainerDecoder struct{}
    17  
    18  // DecodeConfig makes ContainerDecoder to implement httputils.ContainerDecoder
    19  func (r ContainerDecoder) DecodeConfig(src io.Reader) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) {
    20  	return DecodeContainerConfig(src)
    21  }
    22  
    23  // DecodeHostConfig makes ContainerDecoder to implement httputils.ContainerDecoder
    24  func (r ContainerDecoder) DecodeHostConfig(src io.Reader) (*container.HostConfig, error) {
    25  	return DecodeHostConfig(src)
    26  }
    27  
    28  // DecodeContainerConfig decodes a json encoded config into a ContainerConfigWrapper
    29  // struct and returns both a Config and a HostConfig struct
    30  // Be aware this function is not checking whether the resulted structs are nil,
    31  // it's your business to do so
    32  func DecodeContainerConfig(src io.Reader) (*container.Config, *container.HostConfig, *networktypes.NetworkingConfig, error) {
    33  	var w ContainerConfigWrapper
    34  
    35  	decoder := json.NewDecoder(src)
    36  	if err := decoder.Decode(&w); err != nil {
    37  		return nil, nil, nil, err
    38  	}
    39  
    40  	hc := w.getHostConfig()
    41  
    42  	// Perform platform-specific processing of Volumes and Binds.
    43  	if w.Config != nil && hc != nil {
    44  
    45  		// Initialize the volumes map if currently nil
    46  		if w.Config.Volumes == nil {
    47  			w.Config.Volumes = make(map[string]struct{})
    48  		}
    49  
    50  		// Now validate all the volumes and binds
    51  		if err := validateMountSettings(w.Config, hc); err != nil {
    52  			return nil, nil, nil, err
    53  		}
    54  	}
    55  
    56  	// Certain parameters need daemon-side validation that cannot be done
    57  	// on the client, as only the daemon knows what is valid for the platform.
    58  	if err := ValidateNetMode(w.Config, hc); err != nil {
    59  		return nil, nil, nil, err
    60  	}
    61  
    62  	// Validate isolation
    63  	if err := ValidateIsolation(hc); err != nil {
    64  		return nil, nil, nil, err
    65  	}
    66  
    67  	// Validate QoS
    68  	if err := ValidateQoS(hc); err != nil {
    69  		return nil, nil, nil, err
    70  	}
    71  
    72  	// Validate Resources
    73  	if err := ValidateResources(hc, sysinfo.New(true)); err != nil {
    74  		return nil, nil, nil, err
    75  	}
    76  	return w.Config, hc, w.NetworkingConfig, nil
    77  }
    78  
    79  // validateMountSettings validates each of the volumes and bind settings
    80  // passed by the caller to ensure they are valid.
    81  func validateMountSettings(c *container.Config, hc *container.HostConfig) error {
    82  	// it is ok to have len(hc.Mounts) > 0 && (len(hc.Binds) > 0 || len (c.Volumes) > 0 || len (hc.Tmpfs) > 0 )
    83  
    84  	// Ensure all volumes and binds are valid.
    85  	for spec := range c.Volumes {
    86  		if _, err := volume.ParseMountRaw(spec, hc.VolumeDriver); err != nil {
    87  			return fmt.Errorf("invalid volume spec %q: %v", spec, err)
    88  		}
    89  	}
    90  	for _, spec := range hc.Binds {
    91  		if _, err := volume.ParseMountRaw(spec, hc.VolumeDriver); err != nil {
    92  			return fmt.Errorf("invalid bind mount spec %q: %v", spec, err)
    93  		}
    94  	}
    95  
    96  	return nil
    97  }