-
Notifications
You must be signed in to change notification settings - Fork 0
/
namespace_linux.go
130 lines (112 loc) · 3.34 KB
/
namespace_linux.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright 2021 xgfone
//
// 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 namespace
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"strconv"
"strings"
"github.com/xgfone/go-exec"
)
// ErrNoNameSpace is returned when no namespace associates with a given process.
var ErrNoNameSpace = errors.New("no namespace")
func execute(name string, args ...string) (string, error) {
return exec.Output(context.Background(), name, args...)
}
// NameSpace is the Linux NameSpace instance.
type NameSpace struct {
Name string
}
// NewNameSpace returns a new NameSpace instance named name.
func NewNameSpace(name string) NameSpace { return NameSpace{Name: name} }
// NewNameSpaceFromPid returns a new NameSpace instance by the process pid.
func NewNameSpaceFromPid(pid int) (NameSpace, error) {
out, err := execute("ip", "netns", "identify", fmt.Sprint(pid))
if err != nil {
return NameSpace{}, err
}
if out = strings.TrimSpace(out); out == "" {
return NameSpace{}, ErrNoNameSpace
}
return NameSpace{Name: out}, nil
}
// GetAllNameSpace returns all the namespace instances.
func GetAllNameSpace() (nss []NameSpace, err error) {
nss = make([]NameSpace, 0, 128)
err = filepath.Walk("/var/run/netns", func(_ string, info os.FileInfo, err error) error {
nss = append(nss, NameSpace{Name: info.Name()})
return err
})
return
}
func (ns NameSpace) String() string {
return fmt.Sprintf("NameSpace(%s)", ns.Name)
}
// Pids returns all the pids in the current namespace.
func (ns NameSpace) Pids() (pids []int, err error) {
out, err := execute("ip", "netns", "pids", ns.Name)
if err == nil {
var v int64
ss := strings.Fields(out)
pids = make([]int, len(ss))
for i, s := range ss {
if v, err = strconv.ParseInt(s, 10, 64); err != nil {
return
}
pids[i] = int(v)
}
}
return
}
// Create creates the namespace.
func (ns NameSpace) Create() (err error) {
if _, err = execute("ip", "netns", "add", ns.Name); err != nil {
if !strings.Contains(err.Error(), "File exists") {
return
}
}
_, err = ns.Exec("ip", "link", "set", "lo", "up")
return
}
// Delete deletes the namespance.
func (ns NameSpace) Delete() (err error) {
if _, err = execute("ip", "netns", "delete", ns.Name); err != nil {
if strings.Contains(err.Error(), "No such file or directory") {
err = nil
}
}
return
}
// IsExist reports whether the namespace exists or not.
func (ns NameSpace) IsExist() (exist bool, err error) {
if _, err = os.Stat("/var/run/netns/" + ns.Name); err == nil {
exist = true
} else if os.IsNotExist(err) {
err = nil
}
return
}
// Exec executes a shell command in the current namespace.
func (ns NameSpace) Exec(cmd string, args ...string) (output string, err error) {
_args := make([]string, 4+len(args))
_args[0] = "netns"
_args[1] = "exec"
_args[2] = ns.Name
_args[3] = cmd
copy(_args[4:], args)
return execute("ip", _args...)
}