github.com/DaoCloud/dao@v0.0.0-20161212064103-c3dbfd13ee36/api/client/network/create.go (about)

     1  package network
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"strings"
     7  
     8  	"golang.org/x/net/context"
     9  
    10  	"github.com/docker/docker/api/client"
    11  	"github.com/docker/docker/cli"
    12  	"github.com/docker/docker/opts"
    13  	runconfigopts "github.com/docker/docker/runconfig/opts"
    14  	"github.com/docker/engine-api/types"
    15  	"github.com/docker/engine-api/types/network"
    16  	"github.com/spf13/cobra"
    17  )
    18  
    19  type createOptions struct {
    20  	name       string
    21  	driver     string
    22  	driverOpts opts.MapOpts
    23  	labels     []string
    24  	internal   bool
    25  	ipv6       bool
    26  
    27  	ipamDriver  string
    28  	ipamSubnet  []string
    29  	ipamIPRange []string
    30  	ipamGateway []string
    31  	ipamAux     opts.MapOpts
    32  	ipamOpt     opts.MapOpts
    33  }
    34  
    35  func newCreateCommand(dockerCli *client.DockerCli) *cobra.Command {
    36  	opts := createOptions{
    37  		driverOpts: *opts.NewMapOpts(nil, nil),
    38  		ipamAux:    *opts.NewMapOpts(nil, nil),
    39  		ipamOpt:    *opts.NewMapOpts(nil, nil),
    40  	}
    41  
    42  	cmd := &cobra.Command{
    43  		Use:   "create [OPTIONS] NETWORK",
    44  		Short: "创建一个网络",
    45  		Args:  cli.ExactArgs(1),
    46  		RunE: func(cmd *cobra.Command, args []string) error {
    47  			opts.name = args[0]
    48  			return runCreate(dockerCli, opts)
    49  		},
    50  	}
    51  
    52  	flags := cmd.Flags()
    53  	flags.StringVarP(&opts.driver, "driver", "d", "bridge", "管理网络所使用的网络驱动")
    54  	flags.VarP(&opts.driverOpts, "opt", "o", "设置指定驱动的选项")
    55  	flags.StringSliceVar(&opts.labels, "label", []string{}, "在一个网络设置元数据")
    56  	flags.BoolVar(&opts.internal, "internal", false, "限制外界对网络的访问能力")
    57  	flags.BoolVar(&opts.ipv6, "ipv6", false, "启用 IPv6 网络")
    58  
    59  	flags.StringVar(&opts.ipamDriver, "ipam-driver", "default", "IP地址管理驱动")
    60  	flags.StringSliceVar(&opts.ipamSubnet, "subnet", []string{}, "CIDR格式的子网信息,代表一个网络段")
    61  	flags.StringSliceVar(&opts.ipamIPRange, "ip-range", []string{}, "从一个子网范围内分配容器IP")
    62  	flags.StringSliceVar(&opts.ipamGateway, "gateway", []string{}, "为主子网设置的IPv4或IPv6网关")
    63  
    64  	flags.Var(&opts.ipamAux, "aux-address", "被网络驱动使用的辅助IPv4或IPv6地址")
    65  	flags.Var(&opts.ipamOpt, "ipam-opt", "设置IP地址管理器的特定参数")
    66  
    67  	return cmd
    68  }
    69  
    70  func runCreate(dockerCli *client.DockerCli, opts createOptions) error {
    71  	client := dockerCli.Client()
    72  
    73  	ipamCfg, err := consolidateIpam(opts.ipamSubnet, opts.ipamIPRange, opts.ipamGateway, opts.ipamAux.GetAll())
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	// Construct network create request body
    79  	nc := types.NetworkCreate{
    80  		Driver:  opts.driver,
    81  		Options: opts.driverOpts.GetAll(),
    82  		IPAM: network.IPAM{
    83  			Driver:  opts.ipamDriver,
    84  			Config:  ipamCfg,
    85  			Options: opts.ipamOpt.GetAll(),
    86  		},
    87  		CheckDuplicate: true,
    88  		Internal:       opts.internal,
    89  		EnableIPv6:     opts.ipv6,
    90  		Labels:         runconfigopts.ConvertKVStringsToMap(opts.labels),
    91  	}
    92  
    93  	resp, err := client.NetworkCreate(context.Background(), opts.name, nc)
    94  	if err != nil {
    95  		return err
    96  	}
    97  	fmt.Fprintf(dockerCli.Out(), "%s\n", resp.ID)
    98  	return nil
    99  }
   100  
   101  // Consolidates the ipam configuration as a group from different related configurations
   102  // user can configure network with multiple non-overlapping subnets and hence it is
   103  // possible to correlate the various related parameters and consolidate them.
   104  // consoidateIpam consolidates subnets, ip-ranges, gateways and auxiliary addresses into
   105  // structured ipam data.
   106  func consolidateIpam(subnets, ranges, gateways []string, auxaddrs map[string]string) ([]network.IPAMConfig, error) {
   107  	if len(subnets) < len(ranges) || len(subnets) < len(gateways) {
   108  		return nil, fmt.Errorf("每一个IP范围或网关必须拥有一个相应的子网地址")
   109  	}
   110  	iData := map[string]*network.IPAMConfig{}
   111  
   112  	// Populate non-overlapping subnets into consolidation map
   113  	for _, s := range subnets {
   114  		for k := range iData {
   115  			ok1, err := subnetMatches(s, k)
   116  			if err != nil {
   117  				return nil, err
   118  			}
   119  			ok2, err := subnetMatches(k, s)
   120  			if err != nil {
   121  				return nil, err
   122  			}
   123  			if ok1 || ok2 {
   124  				return nil, fmt.Errorf("多个子网配置信息有重叠的情况,Docker引擎暂不支持")
   125  			}
   126  		}
   127  		iData[s] = &network.IPAMConfig{Subnet: s, AuxAddress: map[string]string{}}
   128  	}
   129  
   130  	// Validate and add valid ip ranges
   131  	for _, r := range ranges {
   132  		match := false
   133  		for _, s := range subnets {
   134  			ok, err := subnetMatches(s, r)
   135  			if err != nil {
   136  				return nil, err
   137  			}
   138  			if !ok {
   139  				continue
   140  			}
   141  			if iData[s].IPRange != "" {
   142  				return nil, fmt.Errorf("不能配置在同一个子网 (%s)中配置多范围(%s, %s)", s, r, iData[s].IPRange)
   143  			}
   144  			d := iData[s]
   145  			d.IPRange = r
   146  			match = true
   147  		}
   148  		if !match {
   149  			return nil, fmt.Errorf("没有匹配的子网地址 %s", r)
   150  		}
   151  	}
   152  
   153  	// Validate and add valid gateways
   154  	for _, g := range gateways {
   155  		match := false
   156  		for _, s := range subnets {
   157  			ok, err := subnetMatches(s, g)
   158  			if err != nil {
   159  				return nil, err
   160  			}
   161  			if !ok {
   162  				continue
   163  			}
   164  			if iData[s].Gateway != "" {
   165  				return nil, fmt.Errorf("不能配置在同一个子网 (%s)中配置多个网关(%s, %s)", s, g, iData[s].Gateway)
   166  			}
   167  			d := iData[s]
   168  			d.Gateway = g
   169  			match = true
   170  		}
   171  		if !match {
   172  			return nil, fmt.Errorf("没有匹配的子网地址 %s", g)
   173  		}
   174  	}
   175  
   176  	// Validate and add aux-addresses
   177  	for key, aa := range auxaddrs {
   178  		match := false
   179  		for _, s := range subnets {
   180  			ok, err := subnetMatches(s, aa)
   181  			if err != nil {
   182  				return nil, err
   183  			}
   184  			if !ok {
   185  				continue
   186  			}
   187  			iData[s].AuxAddress[key] = aa
   188  			match = true
   189  		}
   190  		if !match {
   191  			return nil, fmt.Errorf("没有找到符合辅助网络地址的子网 %s", aa)
   192  		}
   193  	}
   194  
   195  	idl := []network.IPAMConfig{}
   196  	for _, v := range iData {
   197  		idl = append(idl, *v)
   198  	}
   199  	return idl, nil
   200  }
   201  
   202  func subnetMatches(subnet, data string) (bool, error) {
   203  	var (
   204  		ip net.IP
   205  	)
   206  
   207  	_, s, err := net.ParseCIDR(subnet)
   208  	if err != nil {
   209  		return false, fmt.Errorf("无效的子网地址 %s : %v", s, err)
   210  	}
   211  
   212  	if strings.Contains(data, "/") {
   213  		ip, _, err = net.ParseCIDR(data)
   214  		if err != nil {
   215  			return false, fmt.Errorf("无效的 CIDR %s : %v", data, err)
   216  		}
   217  	} else {
   218  		ip = net.ParseIP(data)
   219  	}
   220  
   221  	return s.Contains(ip), nil
   222  }