add network create funcs

pull/9294/head
Medya Gh 2020-09-21 15:56:08 -07:00
parent ff051f9a33
commit 9cd42163b1
2 changed files with 140 additions and 0 deletions

View File

@ -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)

View File

@ -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
}