mirror of
https://github.com/clearlinux/rkt.git
synced 2026-08-18 21:16:13 +00:00
net: stage1 gc will clean up networking
This commit is contained in:
@@ -51,7 +51,7 @@ After preparation completes, while still holding the exclusive lock (the lock is
|
||||
|
||||
`rkt run` transitions directly from #Prepare to #Run by renaming `$var/prepare/$uuid` to `$var/run/$uuid`, entirely skipping the #Prepared phase.
|
||||
|
||||
Should #Prepare fail or be interrupted, `$var/prepare/$uuid` will be left in an unlocked state. Any directory in `$var/prepare` in an unlocked state is considered a failed prepare. `rkt gc` identifies failed prepares in need of cleanup by trying to acquire a shared lock on all directories in `$var/prepare`, renaming successfully locked directories to `$var/garbage` where they are then deleted.
|
||||
Should #Prepare fail or be interrupted, `$var/prepare/$uuid` will be left in an unlocked state. Any directory in `$var/prepare` in an unlocked state is considered a failed prepare. `rkt gc` identifies failed prepares in need of clean up by trying to acquire a shared lock on all directories in `$var/prepare`, renaming successfully locked directories to `$var/garbage` where they are then deleted.
|
||||
|
||||
## Prepared
|
||||
|
||||
@@ -91,7 +91,7 @@ Marked exited pods dwell in the `$var/exited-garbage` directory for a grace peri
|
||||
|
||||
A side-effect of the rename operation responsible for moving a pod from `$var/run` to `$var/exited-garbage` is an update to the pod directory's change time. The sweep operation takes advantage of this in honoring the necessary grace period before discarding exited pods. This grace period currently defaults to 30 minutes, and may be explicitly specified using the `--grace-period duration` flag with `rkt gc`. Note that this grace period begins from the time a pod was marked by `rkt gc`, not when the pod exited. A pod becomes eligible for marking upon exit, but will not become marked until a subsequent `rkt gc` is performed.
|
||||
|
||||
The change times of all directories found in `$var/exited-garbage` are compared against the current time. Directories having sufficiently old change times are locked exclusively and cleaned up. If a lock acquisition fails, the directory is skipped. Failed exclusive lock acquisitions may occur if the garbage pod is currently being accessed via `rkt status`, or deleted by a concurrent `rkt gc`, for example. The skipped pods will be revisited on a subsequent `rkt gc` invocation's sweep pass. During the cleanup, pod's stage1 gc entry point is first executed. This gives a stage1 to cleanup anything related to the environment shared between containers. Currently, this cleans up the private networking artifacts. After the completion of the gc entrypoint, the pod directory is recursively deleted.
|
||||
The change times of all directories found in `$var/exited-garbage` are compared against the current time. Directories having sufficiently old change times are locked exclusively and cleaned up. If a lock acquisition fails, the directory is skipped. Failed exclusive lock acquisitions may occur if the garbage pod is currently being accessed via `rkt status`, or deleted by a concurrent `rkt gc`, for example. The skipped pods will be revisited on a subsequent `rkt gc` invocation's sweep pass. During the cleanup, the pod's stage1 gc entry point is first executed. This gives the stage1 a chance to clean up anything related to the environment shared between containers. The default stage1 uses the gc entrypoint to clean up the private networking artifacts. After the completion of the gc entrypoint, the pod directory is recursively deleted.
|
||||
|
||||
## Pulse
|
||||
|
||||
|
||||
@@ -1,122 +0,0 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// 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 networking
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"path"
|
||||
"sort"
|
||||
|
||||
"github.com/coreos/rkt/common"
|
||||
rktnet "github.com/coreos/rkt/networking/net"
|
||||
)
|
||||
|
||||
// Net encodes a network plugin.
|
||||
type Net struct {
|
||||
rktnet.Net
|
||||
args string
|
||||
}
|
||||
|
||||
// Absolute path where users place their net configs
|
||||
const UserNetPath = "/etc/rkt/net.d"
|
||||
|
||||
// Default net path relative to stage1 root
|
||||
const DefaultNetPath = "etc/rkt/net.d/99-default.conf"
|
||||
|
||||
func listFiles(dir string) ([]string, error) {
|
||||
dirents, err := ioutil.ReadDir(dir)
|
||||
switch {
|
||||
case err == nil:
|
||||
case os.IsNotExist(err):
|
||||
return nil, nil
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
files := []string{}
|
||||
for _, dent := range dirents {
|
||||
if dent.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
files = append(files, dent.Name())
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func netExists(nets []Net, name string) bool {
|
||||
for _, n := range nets {
|
||||
if n.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func loadUserNets() ([]Net, error) {
|
||||
files, err := listFiles(UserNetPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sort.Strings(files)
|
||||
|
||||
nets := make([]Net, 0, len(files))
|
||||
|
||||
for _, filename := range files {
|
||||
filepath := path.Join(UserNetPath, filename)
|
||||
n := Net{}
|
||||
if err := rktnet.LoadNet(filepath, &n); err != nil {
|
||||
return nil, fmt.Errorf("error loading %v: %v", filepath, err)
|
||||
}
|
||||
|
||||
if n.Name == "default" {
|
||||
log.Printf(`Overriding "default" network with %v`, filename)
|
||||
}
|
||||
|
||||
if netExists(nets, n.Name) {
|
||||
// "default" is slightly special
|
||||
log.Printf("%q network already defined, ignoring %v", filename)
|
||||
continue
|
||||
}
|
||||
|
||||
nets = append(nets, n)
|
||||
}
|
||||
|
||||
return nets, nil
|
||||
}
|
||||
|
||||
// Loads nets specified by user and default one from stage1
|
||||
func (e *podEnv) loadNets() ([]Net, error) {
|
||||
nets, err := loadUserNets()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !netExists(nets, "default") {
|
||||
defPath := path.Join(common.Stage1RootfsPath(e.rktRoot), DefaultNetPath)
|
||||
defNet := Net{}
|
||||
if err := rktnet.LoadNet(defPath, &defNet); err != nil {
|
||||
return nil, fmt.Errorf("error loading net: %v", err)
|
||||
}
|
||||
nets = append(nets, defNet)
|
||||
}
|
||||
|
||||
return nets, nil
|
||||
}
|
||||
+4
-23
@@ -19,15 +19,13 @@ import (
|
||||
"io/ioutil"
|
||||
gonet "net"
|
||||
"os"
|
||||
"reflect"
|
||||
)
|
||||
|
||||
// Net describes a network.
|
||||
type Net struct {
|
||||
Filename string
|
||||
Name string `json:"name,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
IPAM struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Type string `json:"type,omitempty"`
|
||||
IPAM struct {
|
||||
Type string `json:"type,omitempty"`
|
||||
} `json:"ipam,omitempty"`
|
||||
}
|
||||
@@ -39,24 +37,7 @@ func LoadNet(path string, n interface{}) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err = json.Unmarshal(c, n); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// populate n.Filename if exists
|
||||
v := reflect.ValueOf(n)
|
||||
if v.Kind() == reflect.Ptr {
|
||||
v = v.Elem()
|
||||
if v.Kind() == reflect.Struct {
|
||||
if fn := v.FieldByName("Filename"); fn.IsValid() {
|
||||
if fn.Type().Kind() == reflect.String && fn.CanSet() {
|
||||
fn.SetString(path)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
return json.Unmarshal(c, n)
|
||||
}
|
||||
|
||||
// this is what net plugin returns to rkt
|
||||
|
||||
+12
-12
@@ -32,22 +32,22 @@ import (
|
||||
const UserNetPluginsPath = "/usr/lib/rkt/plugins/net"
|
||||
const BuiltinNetPluginsPath = "usr/lib/rkt/plugins/net"
|
||||
|
||||
func (e *podEnv) netPluginAdd(n *Net, netns, args, ifName string) (ip, hostIP net.IP, err error) {
|
||||
output, err := e.execNetPlugin("ADD", n, netns, args, ifName)
|
||||
func (e *podEnv) netPluginAdd(n *activeNet, netns string) (ip, hostIP net.IP, err error) {
|
||||
output, err := e.execNetPlugin("ADD", n, netns)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
ifConf := rktnet.IfConfig{}
|
||||
if err = json.Unmarshal(output, &ifConf); err != nil {
|
||||
return nil, nil, fmt.Errorf("error parsing %q output: %v", n.Name, err)
|
||||
return nil, nil, fmt.Errorf("error parsing %q output: %v", n.Conf.Name, err)
|
||||
}
|
||||
|
||||
return ifConf.IP, ifConf.HostIP, nil
|
||||
}
|
||||
|
||||
func (e *podEnv) netPluginDel(n *Net, netns, args, ifName string) error {
|
||||
_, err := e.execNetPlugin("DEL", n, netns, args, ifName)
|
||||
func (e *podEnv) netPluginDel(n *activeNet, netns string) error {
|
||||
_, err := e.execNetPlugin("DEL", n, netns)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -80,20 +80,20 @@ func envVars(vars [][2]string) []string {
|
||||
return env
|
||||
}
|
||||
|
||||
func (e *podEnv) execNetPlugin(cmd string, n *Net, netns, args, ifName string) ([]byte, error) {
|
||||
pluginPath := e.findNetPlugin(n.Type)
|
||||
func (e *podEnv) execNetPlugin(cmd string, n *activeNet, netns string) ([]byte, error) {
|
||||
pluginPath := e.findNetPlugin(n.Conf.Type)
|
||||
if pluginPath == "" {
|
||||
return nil, fmt.Errorf("Could not find plugin %q", n.Type)
|
||||
return nil, fmt.Errorf("Could not find plugin %q", n.Conf.Type)
|
||||
}
|
||||
|
||||
vars := [][2]string{
|
||||
{"RKT_NETPLUGIN_COMMAND", cmd},
|
||||
{"RKT_NETPLUGIN_PODID", e.podID.String()},
|
||||
{"RKT_NETPLUGIN_NETNS", netns},
|
||||
{"RKT_NETPLUGIN_ARGS", args},
|
||||
{"RKT_NETPLUGIN_IFNAME", ifName},
|
||||
{"RKT_NETPLUGIN_NETNAME", n.Name},
|
||||
{"RKT_NETPLUGIN_NETCONF", n.Filename},
|
||||
{"RKT_NETPLUGIN_ARGS", n.Runtime.Args},
|
||||
{"RKT_NETPLUGIN_IFNAME", n.Runtime.IfName},
|
||||
{"RKT_NETPLUGIN_NETNAME", n.Conf.Name},
|
||||
{"RKT_NETPLUGIN_NETCONF", n.Runtime.ConfPath},
|
||||
{"RKT_NETPLUGIN_IPAMPATH", strings.Join(e.pluginPaths(), ":")},
|
||||
}
|
||||
|
||||
|
||||
@@ -16,6 +16,7 @@ package netinfo
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
@@ -24,9 +25,11 @@ import (
|
||||
const filename = "net-info.json"
|
||||
|
||||
type NetInfo struct {
|
||||
NetName string `json:"netName"`
|
||||
IfName string `json:"ifName"`
|
||||
IP string `json:"ip"`
|
||||
NetName string `json:"netName"`
|
||||
ConfPath string `json:"netConf"`
|
||||
IfName string `json:"ifName"`
|
||||
IP net.IP `json:"ip"`
|
||||
Args string `json:"args"`
|
||||
}
|
||||
|
||||
func LoadAt(cdirfd int) ([]NetInfo, error) {
|
||||
|
||||
+101
-167
@@ -16,16 +16,15 @@ package networking
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"syscall"
|
||||
|
||||
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/spec/schema/types"
|
||||
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/vishvananda/netlink"
|
||||
|
||||
rktnet "github.com/coreos/rkt/networking/net"
|
||||
"github.com/coreos/rkt/networking/netinfo"
|
||||
"github.com/coreos/rkt/networking/util"
|
||||
)
|
||||
@@ -35,21 +34,6 @@ const (
|
||||
selfNetNS = "/proc/self/ns/net"
|
||||
)
|
||||
|
||||
type activeNet struct {
|
||||
Net
|
||||
ifName string
|
||||
ip net.IP
|
||||
hostIP net.IP // kludge for default network
|
||||
}
|
||||
|
||||
// "base" struct that's populated from the beginning
|
||||
// describing the environment in which the pod
|
||||
// is running in
|
||||
type podEnv struct {
|
||||
rktRoot string
|
||||
podID types.UUID
|
||||
}
|
||||
|
||||
// ForwardedPort describes a port that will be
|
||||
// forwarded (mapped) from the host to the pod
|
||||
type ForwardedPort struct {
|
||||
@@ -62,19 +46,14 @@ type ForwardedPort struct {
|
||||
type Networking struct {
|
||||
podEnv
|
||||
|
||||
MetadataIP net.IP
|
||||
HostIP net.IP
|
||||
|
||||
podID types.UUID
|
||||
hostNS *os.File
|
||||
podNS *os.File
|
||||
podNSPath string
|
||||
nets []activeNet
|
||||
hostNS *os.File
|
||||
nets []activeNet
|
||||
}
|
||||
|
||||
// Setup produces a Networking object for a given pod ID.
|
||||
// Setup creates a new networking namespace and executes network
|
||||
// plugins to setup private networking. It returns in the new pod
|
||||
// namespace
|
||||
func Setup(rktRoot string, podID types.UUID, fps []ForwardedPort) (*Networking, error) {
|
||||
var err error
|
||||
n := Networking{
|
||||
podEnv: podEnv{
|
||||
rktRoot: rktRoot,
|
||||
@@ -82,69 +61,115 @@ func Setup(rktRoot string, podID types.UUID, fps []ForwardedPort) (*Networking,
|
||||
},
|
||||
}
|
||||
|
||||
defer func() {
|
||||
// cleanup on error
|
||||
if err != nil {
|
||||
n.Teardown()
|
||||
}
|
||||
}()
|
||||
|
||||
if n.hostNS, n.podNS, err = basicNetNS(); err != nil {
|
||||
hostNS, podNS, err := basicNetNS()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// we're in podNS!
|
||||
n.hostNS = hostNS
|
||||
|
||||
n.podNSPath = filepath.Join(rktRoot, "netns")
|
||||
if err = bindMountFile(selfNetNS, n.podNSPath); err != nil {
|
||||
nspath := n.podNSPath()
|
||||
|
||||
if err = bindMountFile(selfNetNS, nspath); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nets, err := n.loadNets()
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if err := syscall.Unmount(nspath, 0); err != nil {
|
||||
log.Printf("Error unmounting %q: %v", nspath, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
n.nets, err = n.loadNets()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("error loading network definitions: %v", err)
|
||||
}
|
||||
|
||||
err = withNetNS(n.podNS, n.hostNS, func() error {
|
||||
n.nets, err = n.setupNets(n.podNSPath, nets)
|
||||
if err != nil {
|
||||
err = withNetNS(podNS, hostNS, func() error {
|
||||
if err := n.setupNets(n.nets); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if len(n.nets) == 0 {
|
||||
return fmt.Errorf("no nets successfully configured")
|
||||
}
|
||||
|
||||
// last net is the default
|
||||
n.MetadataIP = n.nets[len(n.nets)-1].ip
|
||||
n.HostIP = n.nets[len(n.nets)-1].hostIP
|
||||
|
||||
return n.forwardPorts(fps, n.MetadataIP)
|
||||
return n.forwardPorts(fps, n.GetDefaultIP())
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err = n.saveNetInfo(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &n, nil
|
||||
}
|
||||
|
||||
// Load creates the Networking object from saved state.
|
||||
// Assumes the current netns is that of the host.
|
||||
func Load(rktRoot string, podID *types.UUID) (*Networking, error) {
|
||||
// the current directory is pod root
|
||||
pdirfd, err := syscall.Open(rktRoot, syscall.O_RDONLY|syscall.O_DIRECTORY, 0)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("Failed to open pod root directory (%v): %v", rktRoot, err)
|
||||
}
|
||||
defer syscall.Close(pdirfd)
|
||||
|
||||
nis, err := netinfo.LoadAt(pdirfd)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
hostNS, err := os.Open(selfNetNS)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
nets := []activeNet{}
|
||||
for _, ni := range nis {
|
||||
conf := &rktnet.Net{}
|
||||
if err := rktnet.LoadNet(ni.ConfPath, conf); err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
log.Printf("Error loading %q: %v; ignoring", ni.ConfPath, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// make a copy of ni to make it a unique object as it's saved via ptr
|
||||
rti := ni
|
||||
nets = append(nets, activeNet{
|
||||
Conf: conf,
|
||||
Runtime: &rti,
|
||||
})
|
||||
}
|
||||
|
||||
return &Networking{
|
||||
podEnv: podEnv{
|
||||
rktRoot: rktRoot,
|
||||
podID: *podID,
|
||||
},
|
||||
hostNS: hostNS,
|
||||
nets: nets,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (n *Networking) GetDefaultIP() net.IP {
|
||||
if len(n.nets) == 0 {
|
||||
return nil
|
||||
}
|
||||
return n.nets[len(n.nets)-1].Runtime.IP
|
||||
}
|
||||
|
||||
func (n *Networking) GetDefaultHostIP() net.IP {
|
||||
if len(n.nets) == 0 {
|
||||
return nil
|
||||
}
|
||||
return n.nets[len(n.nets)-1].hostIP
|
||||
}
|
||||
|
||||
// Teardown cleans up a produced Networking object.
|
||||
func (n *Networking) Teardown() {
|
||||
// Teardown everything in reverse order of setup.
|
||||
// This is called during error cases as well, so
|
||||
// not everything may be setup.
|
||||
// N.B. better to keep going in case of errors
|
||||
// to get as much cleaned up as possible.
|
||||
// This should be indempotent -- be tolerant of
|
||||
// missing stuff
|
||||
|
||||
if n.podNS == nil || n.hostNS == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err := n.EnterHostNS(); err != nil {
|
||||
log.Print(err)
|
||||
if err := n.enterHostNS(); err != nil {
|
||||
log.Printf("Error switching to host netns: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
@@ -152,14 +177,13 @@ func (n *Networking) Teardown() {
|
||||
log.Printf("Error removing forwarded ports: %v", err)
|
||||
}
|
||||
|
||||
n.teardownNets(n.podNSPath, n.nets)
|
||||
n.teardownNets(n.nets)
|
||||
|
||||
if n.podNSPath == "" {
|
||||
return
|
||||
}
|
||||
|
||||
if err := syscall.Unmount(n.podNSPath, 0); err != nil {
|
||||
log.Printf("Error unmounting %q: %v", n.podNSPath, err)
|
||||
if err := syscall.Unmount(n.podNSPath(), 0); err != nil {
|
||||
// if already unmounted, umount(2) returns EINVAL
|
||||
if !os.IsNotExist(err) && err != syscall.EINVAL {
|
||||
log.Printf("Error unmounting %q: %v", n.podNSPath(), err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -181,88 +205,17 @@ func basicNetNS() (hostNS, podNS *os.File, err error) {
|
||||
return
|
||||
}
|
||||
|
||||
// EnterHostNS moves into the host's network namespace.
|
||||
func (n *Networking) EnterHostNS() error {
|
||||
// enterHostNS moves into the host's network namespace.
|
||||
func (n *Networking) enterHostNS() error {
|
||||
return util.SetNS(n.hostNS, syscall.CLONE_NEWNET)
|
||||
}
|
||||
|
||||
// EnterPodNS moves into the pod's network namespace.
|
||||
func (n *Networking) EnterPodNS() error {
|
||||
return util.SetNS(n.podNS, syscall.CLONE_NEWNET)
|
||||
}
|
||||
|
||||
func (e *podEnv) netDir() string {
|
||||
return filepath.Join(e.rktRoot, "net")
|
||||
}
|
||||
|
||||
func (e *podEnv) setupNets(netns string, nets []Net) ([]activeNet, error) {
|
||||
err := os.MkdirAll(e.netDir(), 0755)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
active := []activeNet{}
|
||||
|
||||
for i, nt := range nets {
|
||||
log.Printf("Setup: executing net-plugin %v", nt.Type)
|
||||
|
||||
an := activeNet{
|
||||
Net: nt,
|
||||
ifName: fmt.Sprintf(ifnamePattern, i),
|
||||
}
|
||||
|
||||
if an.Filename, err = copyFileToDir(nt.Filename, e.netDir()); err != nil {
|
||||
err = fmt.Errorf("error copying %q to %q: %v", nt.Filename, e.netDir(), err)
|
||||
break
|
||||
}
|
||||
|
||||
an.ip, an.hostIP, err = e.netPluginAdd(&nt, netns, nt.args, an.ifName)
|
||||
if err != nil {
|
||||
err = fmt.Errorf("error adding network %q: %v", nt.Name, err)
|
||||
break
|
||||
}
|
||||
|
||||
active = append(active, an)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
e.teardownNets(netns, active)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return active, nil
|
||||
}
|
||||
|
||||
func (e *podEnv) teardownNets(netns string, nets []activeNet) {
|
||||
for i := len(nets) - 1; i >= 0; i-- {
|
||||
nt := nets[i]
|
||||
|
||||
log.Printf("Teardown: executing net-plugin %v", nt.Type)
|
||||
|
||||
err := e.netPluginDel(&nt.Net, netns, nt.args, nt.ifName)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting %q: %v", nt.Name, err)
|
||||
}
|
||||
|
||||
// Delete the conf file to signal that the network was
|
||||
// torn down (or at least attempted to)
|
||||
if err = os.Remove(nt.Filename); err != nil {
|
||||
log.Printf("Error deleting %q: %v", nt.Filename, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// saveNetInfo writes out the info about active nets
|
||||
// Save writes out the info about active nets
|
||||
// for "rkt list" and friends to display
|
||||
func (e *Networking) saveNetInfo() error {
|
||||
func (e *Networking) Save() error {
|
||||
nis := []netinfo.NetInfo{}
|
||||
for _, n := range e.nets {
|
||||
ni := netinfo.NetInfo{
|
||||
NetName: n.Name,
|
||||
IfName: n.ifName,
|
||||
IP: n.ip.String(),
|
||||
}
|
||||
nis = append(nis, ni)
|
||||
nis = append(nis, *n.Runtime)
|
||||
}
|
||||
|
||||
return netinfo.Save(e.rktRoot, nis)
|
||||
@@ -338,22 +291,3 @@ func bindMountFile(src, dst string) error {
|
||||
|
||||
return syscall.Mount(src, dst, "none", syscall.MS_BIND, "")
|
||||
}
|
||||
|
||||
func copyFileToDir(src, dstdir string) (string, error) {
|
||||
dst := filepath.Join(dstdir, filepath.Base(src))
|
||||
|
||||
s, err := os.Open(src)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
d, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
_, err = io.Copy(d, s)
|
||||
return dst, err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,232 @@
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// 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 networking
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
|
||||
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/spec/schema/types"
|
||||
|
||||
"github.com/coreos/rkt/common"
|
||||
rktnet "github.com/coreos/rkt/networking/net"
|
||||
"github.com/coreos/rkt/networking/netinfo"
|
||||
)
|
||||
|
||||
const (
|
||||
// Absolute path where users place their net configs
|
||||
UserNetPath = "/etc/rkt/net.d"
|
||||
|
||||
// Default net path relative to stage1 root
|
||||
DefaultNetPath = "etc/rkt/net.d/99-default.conf"
|
||||
)
|
||||
|
||||
// "base" struct that's populated from the beginning
|
||||
// describing the environment in which the pod
|
||||
// is running in
|
||||
type podEnv struct {
|
||||
rktRoot string
|
||||
podID types.UUID
|
||||
}
|
||||
|
||||
type activeNet struct {
|
||||
Conf *rktnet.Net
|
||||
Runtime *netinfo.NetInfo
|
||||
hostIP net.IP // kludge for default network
|
||||
}
|
||||
|
||||
// Loads nets specified by user and default one from stage1
|
||||
func (e *podEnv) loadNets() ([]activeNet, error) {
|
||||
nets, err := loadUserNets()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !netExists(nets, "default") {
|
||||
defPath := path.Join(common.Stage1RootfsPath(e.rktRoot), DefaultNetPath)
|
||||
n, err := loadNet(defPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
nets = append(nets, *n)
|
||||
}
|
||||
|
||||
return nets, nil
|
||||
}
|
||||
|
||||
func (e *podEnv) podNSPath() string {
|
||||
return filepath.Join(e.rktRoot, "netns")
|
||||
}
|
||||
|
||||
func (e *podEnv) netDir() string {
|
||||
return filepath.Join(e.rktRoot, "net")
|
||||
}
|
||||
|
||||
func (e *podEnv) setupNets(nets []activeNet) error {
|
||||
err := os.MkdirAll(e.netDir(), 0755)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
i := 0
|
||||
defer func() {
|
||||
if err != nil {
|
||||
e.teardownNets(nets[:i])
|
||||
}
|
||||
}()
|
||||
|
||||
nspath := e.podNSPath()
|
||||
|
||||
n := activeNet{}
|
||||
for i, n = range nets {
|
||||
log.Printf("Setup: executing net-plugin %v", n.Conf.Type)
|
||||
|
||||
n.Runtime.IfName = fmt.Sprintf(ifnamePattern, i)
|
||||
if n.Runtime.ConfPath, err = copyFileToDir(n.Runtime.ConfPath, e.netDir()); err != nil {
|
||||
return fmt.Errorf("error copying %q to %q: %v", n.Runtime.ConfPath, e.netDir(), err)
|
||||
}
|
||||
|
||||
n.Runtime.IP, n.hostIP, err = e.netPluginAdd(&n, nspath)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error adding network %q: %v", n.Conf.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *podEnv) teardownNets(nets []activeNet) {
|
||||
nspath := e.podNSPath()
|
||||
|
||||
for i := len(nets) - 1; i >= 0; i-- {
|
||||
log.Printf("Teardown: executing net-plugin %v", nets[i].Conf.Type)
|
||||
|
||||
err := e.netPluginDel(&nets[i], nspath)
|
||||
if err != nil {
|
||||
log.Printf("Error deleting %q: %v", nets[i].Conf.Name, err)
|
||||
}
|
||||
|
||||
// Delete the conf file to signal that the network was
|
||||
// torn down (or at least attempted to)
|
||||
if err = os.Remove(nets[i].Runtime.ConfPath); err != nil {
|
||||
log.Printf("Error deleting %q: %v", nets[i].Runtime.ConfPath, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func listFiles(dir string) ([]string, error) {
|
||||
dirents, err := ioutil.ReadDir(dir)
|
||||
switch {
|
||||
case err == nil:
|
||||
case os.IsNotExist(err):
|
||||
return nil, nil
|
||||
default:
|
||||
return nil, err
|
||||
}
|
||||
|
||||
files := []string{}
|
||||
for _, dent := range dirents {
|
||||
if dent.IsDir() {
|
||||
continue
|
||||
}
|
||||
|
||||
files = append(files, dent.Name())
|
||||
}
|
||||
|
||||
return files, nil
|
||||
}
|
||||
|
||||
func netExists(nets []activeNet, name string) bool {
|
||||
for _, n := range nets {
|
||||
if n.Conf.Name == name {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func loadNet(filepath string) (*activeNet, error) {
|
||||
n := &rktnet.Net{}
|
||||
if err := rktnet.LoadNet(filepath, n); err != nil {
|
||||
return nil, fmt.Errorf("error loading %v: %v", filepath, err)
|
||||
}
|
||||
|
||||
return &activeNet{
|
||||
Conf: n,
|
||||
Runtime: &netinfo.NetInfo{
|
||||
NetName: n.Name,
|
||||
ConfPath: filepath,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func copyFileToDir(src, dstdir string) (string, error) {
|
||||
dst := filepath.Join(dstdir, filepath.Base(src))
|
||||
|
||||
s, err := os.Open(src)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer s.Close()
|
||||
|
||||
d, err := os.Create(dst)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
defer d.Close()
|
||||
|
||||
_, err = io.Copy(d, s)
|
||||
return dst, err
|
||||
}
|
||||
|
||||
func loadUserNets() ([]activeNet, error) {
|
||||
files, err := listFiles(UserNetPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sort.Strings(files)
|
||||
|
||||
nets := make([]activeNet, 0, len(files))
|
||||
|
||||
for _, filename := range files {
|
||||
filepath := path.Join(UserNetPath, filename)
|
||||
n, err := loadNet(filepath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// "default" is slightly special
|
||||
if n.Conf.Name == "default" {
|
||||
log.Printf(`Overriding "default" network with %v`, filename)
|
||||
}
|
||||
|
||||
if netExists(nets, n.Conf.Name) {
|
||||
log.Printf("%q network already defined, ignoring %v", n.Conf.Name, filename)
|
||||
continue
|
||||
}
|
||||
|
||||
nets = append(nets, *n)
|
||||
}
|
||||
|
||||
return nets, nil
|
||||
}
|
||||
+2
-7
@@ -1,4 +1,4 @@
|
||||
// Copyright 2014 CoreOS, Inc.
|
||||
// Copyright 2015 CoreOS, Inc.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
@@ -17,7 +17,6 @@
|
||||
package stage0
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
@@ -48,9 +47,5 @@ func GC(pdir string, uuid *types.UUID, debug bool) error {
|
||||
Stderr: os.Stderr,
|
||||
Dir: pdir,
|
||||
}
|
||||
if err := c.Run(); err != nil {
|
||||
return fmt.Errorf("error running gc: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return c.Run()
|
||||
}
|
||||
|
||||
+52
-2
@@ -17,10 +17,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"os"
|
||||
"runtime"
|
||||
|
||||
"github.com/coreos/rkt/Godeps/_workspace/src/github.com/appc/spec/schema/types"
|
||||
|
||||
"github.com/coreos/rkt/networking"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Fprintln(os.Stderr, "Hello from stage1 GC")
|
||||
var (
|
||||
debug bool
|
||||
)
|
||||
|
||||
func init() {
|
||||
flag.BoolVar(&debug, "debug", false, "Run in debug mode")
|
||||
|
||||
// this ensures that main runs only on main thread (thread group leader).
|
||||
// since namespace ops (unshare, setns) are done for a single thread, we
|
||||
// must ensure that the goroutine does not jump from OS thread to thread
|
||||
runtime.LockOSThread()
|
||||
}
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
|
||||
if !debug {
|
||||
log.SetOutput(ioutil.Discard)
|
||||
}
|
||||
|
||||
podID, err := types.NewUUID(flag.Arg(0))
|
||||
if err != nil {
|
||||
fmt.Fprintln(os.Stderr, "UUID is missing or malformed")
|
||||
os.Exit(1)
|
||||
}
|
||||
|
||||
if err := gcNetworking(podID); err != nil {
|
||||
fmt.Fprintln(os.Stderr, err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func gcNetworking(podID *types.UUID) error {
|
||||
n, err := networking.Load(".", podID)
|
||||
switch {
|
||||
case err == nil:
|
||||
n.Teardown()
|
||||
case os.IsNotExist(err):
|
||||
// probably ran without --private-net
|
||||
default:
|
||||
return fmt.Errorf("Failed loading networking state: %v", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
+5
-5
@@ -236,14 +236,14 @@ func stage1() int {
|
||||
}
|
||||
defer n.Teardown()
|
||||
|
||||
p.MetadataServiceURL = common.MetadataServicePublicURL(n.HostIP)
|
||||
|
||||
if err = n.EnterPodNS(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to switch to pod netns: %v\n", err)
|
||||
if err = n.Save(); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to save networking state %v\n", err)
|
||||
return 6
|
||||
}
|
||||
|
||||
if err = registerPod(p, n.MetadataIP); err != nil {
|
||||
p.MetadataServiceURL = common.MetadataServicePublicURL(n.GetDefaultHostIP())
|
||||
|
||||
if err = registerPod(p, n.GetDefaultIP()); err != nil {
|
||||
fmt.Fprintf(os.Stderr, "Failed to register pod: %v\n", err)
|
||||
return 6
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user