Tizen_4.0 base
[platform/upstream/docker-engine.git] / vendor / github.com / docker / cli / cli / command / network / create.go
1 package network
2
3 import (
4         "fmt"
5         "net"
6         "strings"
7
8         "github.com/docker/cli/cli"
9         "github.com/docker/cli/cli/command"
10         "github.com/docker/cli/opts"
11         "github.com/docker/docker/api/types"
12         "github.com/docker/docker/api/types/network"
13         "github.com/pkg/errors"
14         "github.com/spf13/cobra"
15         "golang.org/x/net/context"
16 )
17
18 type createOptions struct {
19         name       string
20         scope      string
21         driver     string
22         driverOpts opts.MapOpts
23         labels     opts.ListOpts
24         internal   bool
25         ipv6       bool
26         attachable bool
27         ingress    bool
28         configOnly bool
29         configFrom string
30
31         ipamDriver  string
32         ipamSubnet  []string
33         ipamIPRange []string
34         ipamGateway []string
35         ipamAux     opts.MapOpts
36         ipamOpt     opts.MapOpts
37 }
38
39 func newCreateCommand(dockerCli *command.DockerCli) *cobra.Command {
40         options := createOptions{
41                 driverOpts: *opts.NewMapOpts(nil, nil),
42                 labels:     opts.NewListOpts(opts.ValidateEnv),
43                 ipamAux:    *opts.NewMapOpts(nil, nil),
44                 ipamOpt:    *opts.NewMapOpts(nil, nil),
45         }
46
47         cmd := &cobra.Command{
48                 Use:   "create [OPTIONS] NETWORK",
49                 Short: "Create a network",
50                 Args:  cli.ExactArgs(1),
51                 RunE: func(cmd *cobra.Command, args []string) error {
52                         options.name = args[0]
53                         return runCreate(dockerCli, options)
54                 },
55         }
56
57         flags := cmd.Flags()
58         flags.StringVarP(&options.driver, "driver", "d", "bridge", "Driver to manage the Network")
59         flags.VarP(&options.driverOpts, "opt", "o", "Set driver specific options")
60         flags.Var(&options.labels, "label", "Set metadata on a network")
61         flags.BoolVar(&options.internal, "internal", false, "Restrict external access to the network")
62         flags.BoolVar(&options.ipv6, "ipv6", false, "Enable IPv6 networking")
63         flags.BoolVar(&options.attachable, "attachable", false, "Enable manual container attachment")
64         flags.SetAnnotation("attachable", "version", []string{"1.25"})
65         flags.BoolVar(&options.ingress, "ingress", false, "Create swarm routing-mesh network")
66         flags.SetAnnotation("ingress", "version", []string{"1.29"})
67         flags.StringVar(&options.scope, "scope", "", "Control the network's scope")
68         flags.SetAnnotation("scope", "version", []string{"1.30"})
69         flags.BoolVar(&options.configOnly, "config-only", false, "Create a configuration only network")
70         flags.SetAnnotation("config-only", "version", []string{"1.30"})
71         flags.StringVar(&options.configFrom, "config-from", "", "The network from which copying the configuration")
72         flags.SetAnnotation("config-from", "version", []string{"1.30"})
73
74         flags.StringVar(&options.ipamDriver, "ipam-driver", "default", "IP Address Management Driver")
75         flags.StringSliceVar(&options.ipamSubnet, "subnet", []string{}, "Subnet in CIDR format that represents a network segment")
76         flags.StringSliceVar(&options.ipamIPRange, "ip-range", []string{}, "Allocate container ip from a sub-range")
77         flags.StringSliceVar(&options.ipamGateway, "gateway", []string{}, "IPv4 or IPv6 Gateway for the master subnet")
78
79         flags.Var(&options.ipamAux, "aux-address", "Auxiliary IPv4 or IPv6 addresses used by Network driver")
80         flags.Var(&options.ipamOpt, "ipam-opt", "Set IPAM driver specific options")
81
82         return cmd
83 }
84
85 func runCreate(dockerCli *command.DockerCli, options createOptions) error {
86         client := dockerCli.Client()
87
88         ipamCfg, err := consolidateIpam(options.ipamSubnet, options.ipamIPRange, options.ipamGateway, options.ipamAux.GetAll())
89         if err != nil {
90                 return err
91         }
92
93         // Construct network create request body
94         nc := types.NetworkCreate{
95                 Driver:  options.driver,
96                 Options: options.driverOpts.GetAll(),
97                 IPAM: &network.IPAM{
98                         Driver:  options.ipamDriver,
99                         Config:  ipamCfg,
100                         Options: options.ipamOpt.GetAll(),
101                 },
102                 CheckDuplicate: true,
103                 Internal:       options.internal,
104                 EnableIPv6:     options.ipv6,
105                 Attachable:     options.attachable,
106                 Ingress:        options.ingress,
107                 Scope:          options.scope,
108                 ConfigOnly:     options.configOnly,
109                 Labels:         opts.ConvertKVStringsToMap(options.labels.GetAll()),
110         }
111
112         if from := options.configFrom; from != "" {
113                 nc.ConfigFrom = &network.ConfigReference{
114                         Network: from,
115                 }
116         }
117
118         resp, err := client.NetworkCreate(context.Background(), options.name, nc)
119         if err != nil {
120                 return err
121         }
122         fmt.Fprintf(dockerCli.Out(), "%s\n", resp.ID)
123         return nil
124 }
125
126 // Consolidates the ipam configuration as a group from different related configurations
127 // user can configure network with multiple non-overlapping subnets and hence it is
128 // possible to correlate the various related parameters and consolidate them.
129 // consolidateIpam consolidates subnets, ip-ranges, gateways and auxiliary addresses into
130 // structured ipam data.
131 // nolint: gocyclo
132 func consolidateIpam(subnets, ranges, gateways []string, auxaddrs map[string]string) ([]network.IPAMConfig, error) {
133         if len(subnets) < len(ranges) || len(subnets) < len(gateways) {
134                 return nil, errors.Errorf("every ip-range or gateway must have a corresponding subnet")
135         }
136         iData := map[string]*network.IPAMConfig{}
137
138         // Populate non-overlapping subnets into consolidation map
139         for _, s := range subnets {
140                 for k := range iData {
141                         ok1, err := subnetMatches(s, k)
142                         if err != nil {
143                                 return nil, err
144                         }
145                         ok2, err := subnetMatches(k, s)
146                         if err != nil {
147                                 return nil, err
148                         }
149                         if ok1 || ok2 {
150                                 return nil, errors.Errorf("multiple overlapping subnet configuration is not supported")
151                         }
152                 }
153                 iData[s] = &network.IPAMConfig{Subnet: s, AuxAddress: map[string]string{}}
154         }
155
156         // Validate and add valid ip ranges
157         for _, r := range ranges {
158                 match := false
159                 for _, s := range subnets {
160                         ok, err := subnetMatches(s, r)
161                         if err != nil {
162                                 return nil, err
163                         }
164                         if !ok {
165                                 continue
166                         }
167                         if iData[s].IPRange != "" {
168                                 return nil, errors.Errorf("cannot configure multiple ranges (%s, %s) on the same subnet (%s)", r, iData[s].IPRange, s)
169                         }
170                         d := iData[s]
171                         d.IPRange = r
172                         match = true
173                 }
174                 if !match {
175                         return nil, errors.Errorf("no matching subnet for range %s", r)
176                 }
177         }
178
179         // Validate and add valid gateways
180         for _, g := range gateways {
181                 match := false
182                 for _, s := range subnets {
183                         ok, err := subnetMatches(s, g)
184                         if err != nil {
185                                 return nil, err
186                         }
187                         if !ok {
188                                 continue
189                         }
190                         if iData[s].Gateway != "" {
191                                 return nil, errors.Errorf("cannot configure multiple gateways (%s, %s) for the same subnet (%s)", g, iData[s].Gateway, s)
192                         }
193                         d := iData[s]
194                         d.Gateway = g
195                         match = true
196                 }
197                 if !match {
198                         return nil, errors.Errorf("no matching subnet for gateway %s", g)
199                 }
200         }
201
202         // Validate and add aux-addresses
203         for key, aa := range auxaddrs {
204                 match := false
205                 for _, s := range subnets {
206                         ok, err := subnetMatches(s, aa)
207                         if err != nil {
208                                 return nil, err
209                         }
210                         if !ok {
211                                 continue
212                         }
213                         iData[s].AuxAddress[key] = aa
214                         match = true
215                 }
216                 if !match {
217                         return nil, errors.Errorf("no matching subnet for aux-address %s", aa)
218                 }
219         }
220
221         idl := []network.IPAMConfig{}
222         for _, v := range iData {
223                 idl = append(idl, *v)
224         }
225         return idl, nil
226 }
227
228 func subnetMatches(subnet, data string) (bool, error) {
229         var (
230                 ip net.IP
231         )
232
233         _, s, err := net.ParseCIDR(subnet)
234         if err != nil {
235                 return false, errors.Errorf("Invalid subnet %s : %v", s, err)
236         }
237
238         if strings.Contains(data, "/") {
239                 ip, _, err = net.ParseCIDR(data)
240                 if err != nil {
241                         return false, errors.Errorf("Invalid cidr %s : %v", data, err)
242                 }
243         } else {
244                 ip = net.ParseIP(data)
245         }
246
247         return s.Contains(ip), nil
248 }