add network create funcs
parent
ff051f9a33
commit
9cd42163b1
|
|
@ -39,12 +39,27 @@ var ErrWindowsContainers = &FailFastError{errors.New("docker container type is w
|
|||
// ErrCPUCountLimit is thrown when docker daemon doesn't have enough CPUs for the requested container
|
||||
var ErrCPUCountLimit = &FailFastError{errors.New("not enough CPUs is available for container")}
|
||||
|
||||
// ErrIPinUse is thrown when the container been given an IP used by another container
|
||||
var ErrIPinUse = &FailFastError{errors.New("can't create with that IP, address already in use")}
|
||||
|
||||
// ErrExitedUnexpectedly is thrown when container is created/started without error but later it exists and it's status is not running anymore.
|
||||
var ErrExitedUnexpectedly = errors.New("container exited unexpectedly")
|
||||
|
||||
// ErrDaemonInfo is thrown when docker/podman info is failing or not responding
|
||||
var ErrDaemonInfo = errors.New("daemon info not responding")
|
||||
|
||||
// ErrNetworkSubnetTaken is thrown when a subnet is taken by another network
|
||||
var ErrNetworkSubnetTaken = errors.New("subnet is taken")
|
||||
|
||||
// ErrNetworkNotFound is when given network was not found
|
||||
var ErrNetworkNotFound = errors.New("kic network not found")
|
||||
|
||||
// ErrNetworkGatewayTaken is when given network gatway is taken
|
||||
var ErrNetworkGatewayTaken = errors.New("network gateway is taken")
|
||||
|
||||
// ErrNetworkInUse is when trying to delete a network which is attached to another container
|
||||
var ErrNetworkInUse = errors.New("can't delete network attached to a running container")
|
||||
|
||||
// LogContainerDebug will print relevant docker/podman infos after a container fails
|
||||
func LogContainerDebug(ociBin string, name string) string {
|
||||
rr, err := containerInspect(ociBin, name)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,125 @@
|
|||
/*
|
||||
Copyright 2019 The Kubernetes Authors All rights reserved.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package oci
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// DefaultSubnet subnet to be used on first cluster
|
||||
const defaultSubnet = "192.168.39.0/24"
|
||||
|
||||
// CreateNetwork creates a network returns gateway and error, minikube creates one network per cluster
|
||||
func CreateNetwork(ociBin string, name string) (net.IP, error) {
|
||||
if ociBin != Docker {
|
||||
return nil, fmt.Errorf("%s network not implemented yet", ociBin)
|
||||
}
|
||||
return createDockerNetwork(name)
|
||||
}
|
||||
|
||||
func createDockerNetwork(name string) (net.IP, error) {
|
||||
// check if the network already exists
|
||||
subnet, gateway, err := dockerNetworkInspect(name)
|
||||
if err == nil {
|
||||
glog.Infof("Found existing network with subnet %s and gateway %s.", subnet, gateway)
|
||||
return gateway, nil
|
||||
}
|
||||
// simple way to create networks, subnet is taken, try one bigger
|
||||
attempt := 0
|
||||
_, subnet, err = net.ParseCIDR(defaultSubnet)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "parse default subnet %s", defaultSubnet)
|
||||
}
|
||||
|
||||
gateway, err = tryCreateDockerNetwork(subnet, name)
|
||||
if err != nil {
|
||||
if err != ErrNetworkSubnetTaken {
|
||||
return nil, errors.Wrapf(err, "error creating network")
|
||||
}
|
||||
// try up to 13 times
|
||||
// we can try up to 255
|
||||
for attempt < 13 {
|
||||
attempt++
|
||||
glog.Infof("Couldn't create network %q at %q subnet will try again with a new subnet ...", name, subnet)
|
||||
// increase 3nd digit by 10 each time
|
||||
// 13 times adding 10 defaultSubnet "192.168.39.0/24"
|
||||
// at most it will add up to 169 which is still less than max allowed 255
|
||||
// this is large enough to try more and not too small to not try enough
|
||||
// can be tuned in the next iterations
|
||||
subnet.IP.To4()[2] += 10
|
||||
gateway, err := tryCreateDockerNetwork(subnet, name)
|
||||
if err == nil {
|
||||
return gateway, nil
|
||||
}
|
||||
if err == ErrNetworkSubnetTaken {
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return gateway, nil
|
||||
}
|
||||
|
||||
func tryCreateDockerNetwork(subnet *net.IPNet, name string) (net.IP, error) {
|
||||
gateway := subnet.IP.To4()
|
||||
gateway[3]++ // first ip for gateway
|
||||
glog.Infof("attempt to create network %q with subnet: %s and gateway %s...", subnet, name, gateway)
|
||||
// options documentation https://docs.docker.com/engine/reference/commandline/network_create/#bridge-driver-options
|
||||
rr, err := runCmd(exec.Command(Docker, "network", "create", "--driver=bridge", fmt.Sprintf("--subnet=%s", subnet), fmt.Sprintf("--gateway=%s", gateway), "-o", "--ip-masq", "-o", "--icc", fmt.Sprintf("--label=%s=%s", CreatedByLabelKey, "true"), name))
|
||||
if err != nil {
|
||||
if strings.Contains(rr.Output(), "Pool overlaps with other one on this address space") {
|
||||
return nil, ErrNetworkSubnetTaken
|
||||
}
|
||||
if strings.Contains(rr.Output(), "failed to allocate gateway") && strings.Contains(rr.Output(), "Address already in use") {
|
||||
return nil, ErrNetworkGatewayTaken
|
||||
}
|
||||
return nil, errors.Wrapf(err, "error creating network")
|
||||
}
|
||||
return gateway, nil
|
||||
}
|
||||
|
||||
// returns subnet and gate if exists
|
||||
func dockerNetworkInspect(name string) (*net.IPNet, net.IP, error) {
|
||||
rr, err := runCmd(exec.Command(Docker, "network", "inspect", name, "--format", "{{(index .IPAM.Config 0).Subnet}},{{(index .IPAM.Config 0).Gateway}}"))
|
||||
if err != nil {
|
||||
if strings.Contains(rr.Output(), "No such network:") {
|
||||
return nil, nil, ErrNetworkNotFound
|
||||
}
|
||||
return nil, nil, err
|
||||
}
|
||||
// results looks like 172.17.0.0/16,172.17.0.1
|
||||
ips := strings.Split(strings.TrimSpace(rr.Stdout.String()), ",")
|
||||
if len(ips) == 0 {
|
||||
return nil, nil, fmt.Errorf("invalid network info")
|
||||
}
|
||||
|
||||
_, subnet, err := net.ParseCIDR(ips[0])
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrapf(err, "parse subnet for %s", name)
|
||||
}
|
||||
var gateway net.IP
|
||||
if len(ips) > 0 {
|
||||
gateway = net.ParseIP(ips[1])
|
||||
}
|
||||
return subnet, gateway, nil
|
||||
}
|
||||
Loading…
Reference in New Issue