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 }