Implement container signal
This commit is contained in:
parent
a2ddcc2232
commit
d34d482a5f
7 changed files with 119 additions and 14 deletions
|
@ -3,6 +3,8 @@ package v1
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"strconv"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"github.com/Sirupsen/logrus"
|
"github.com/Sirupsen/logrus"
|
||||||
"github.com/crosbymichael/containerd"
|
"github.com/crosbymichael/containerd"
|
||||||
|
@ -15,9 +17,10 @@ func NewServer(supervisor *containerd.Supervisor) http.Handler {
|
||||||
supervisor: supervisor,
|
supervisor: supervisor,
|
||||||
r: r,
|
r: r,
|
||||||
}
|
}
|
||||||
r.HandleFunc("/containers", s.containers).Methods("GET")
|
r.HandleFunc("/containers/{id:.*}/process/{pid:.*}", s.signalPid).Methods("POST")
|
||||||
r.HandleFunc("/containers/{id:.*}", s.createContainer).Methods("POST")
|
r.HandleFunc("/containers/{id:.*}", s.createContainer).Methods("POST")
|
||||||
r.HandleFunc("/containers/{id:.*}", s.deleteContainer).Methods("DELETE")
|
r.HandleFunc("/containers", s.containers).Methods("GET")
|
||||||
|
// r.HandleFunc("/containers/{id:.*}", s.deleteContainer).Methods("DELETE")
|
||||||
return s
|
return s
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,6 +33,39 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||||
s.r.ServeHTTP(w, r)
|
s.r.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *server) signalPid(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var (
|
||||||
|
vars = mux.Vars(r)
|
||||||
|
id = vars["id"]
|
||||||
|
spid = vars["pid"]
|
||||||
|
)
|
||||||
|
pid, err := strconv.Atoi(spid)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var signal Signal
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&signal); err != nil {
|
||||||
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
e := &containerd.SignalEvent{
|
||||||
|
ID: id,
|
||||||
|
Pid: pid,
|
||||||
|
Signal: syscall.Signal(signal.Signal),
|
||||||
|
Err: make(chan error, 1),
|
||||||
|
}
|
||||||
|
s.supervisor.SendEvent(e)
|
||||||
|
if err := <-e.Err; err != nil {
|
||||||
|
status := http.StatusInternalServerError
|
||||||
|
if err == containerd.ErrContainerNotFound {
|
||||||
|
status = http.StatusNotFound
|
||||||
|
}
|
||||||
|
http.Error(w, err.Error(), status)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (s *server) containers(w http.ResponseWriter, r *http.Request) {
|
func (s *server) containers(w http.ResponseWriter, r *http.Request) {
|
||||||
var state State
|
var state State
|
||||||
state.Containers = []Container{}
|
state.Containers = []Container{}
|
||||||
|
@ -49,10 +85,14 @@ func (s *server) containers(w http.ResponseWriter, r *http.Request) {
|
||||||
"container": c.ID(),
|
"container": c.ID(),
|
||||||
}).Error("get processes for container")
|
}).Error("get processes for container")
|
||||||
}
|
}
|
||||||
|
var pids []int
|
||||||
|
for _, p := range processes {
|
||||||
|
pids = append(pids, p.Pid())
|
||||||
|
}
|
||||||
state.Containers = append(state.Containers, Container{
|
state.Containers = append(state.Containers, Container{
|
||||||
ID: c.ID(),
|
ID: c.ID(),
|
||||||
BundlePath: c.Path(),
|
BundlePath: c.Path(),
|
||||||
Processes: processes,
|
Processes: pids,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
if err := json.NewEncoder(w).Encode(&state); err != nil {
|
if err := json.NewEncoder(w).Encode(&state); err != nil {
|
||||||
|
@ -61,14 +101,6 @@ func (s *server) containers(w http.ResponseWriter, r *http.Request) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *server) events(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *server) deleteContainer(w http.ResponseWriter, r *http.Request) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *server) createContainer(w http.ResponseWriter, r *http.Request) {
|
func (s *server) createContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
id := mux.Vars(r)["id"]
|
id := mux.Vars(r)["id"]
|
||||||
var c Container
|
var c Container
|
||||||
|
@ -76,6 +108,10 @@ func (s *server) createContainer(w http.ResponseWriter, r *http.Request) {
|
||||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
if c.BundlePath == "" {
|
||||||
|
http.Error(w, "empty bundle path", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
e := &containerd.StartContainerEvent{
|
e := &containerd.StartContainerEvent{
|
||||||
ID: id,
|
ID: id,
|
||||||
BundlePath: c.BundlePath,
|
BundlePath: c.BundlePath,
|
||||||
|
|
|
@ -9,3 +9,7 @@ type Container struct {
|
||||||
BundlePath string `json:"bundlePath,omitempty"`
|
BundlePath string `json:"bundlePath,omitempty"`
|
||||||
Processes []int `json:"processes,omitempty"`
|
Processes []int `json:"processes,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Signal struct {
|
||||||
|
Signal int `json:"signal"`
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,12 @@
|
||||||
package containerd
|
package containerd
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
|
type Process interface {
|
||||||
|
Pid() int
|
||||||
|
Signal(os.Signal) error
|
||||||
|
}
|
||||||
|
|
||||||
type Container interface {
|
type Container interface {
|
||||||
ID() string
|
ID() string
|
||||||
Start() error
|
Start() error
|
||||||
|
@ -7,5 +14,5 @@ type Container interface {
|
||||||
Pid() (int, error)
|
Pid() (int, error)
|
||||||
SetExited(status int)
|
SetExited(status int)
|
||||||
Delete() error
|
Delete() error
|
||||||
Processes() ([]int, error)
|
Processes() ([]Process, error)
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ var (
|
||||||
ErrBundleNotFound = errors.New("containerd: bundle not found")
|
ErrBundleNotFound = errors.New("containerd: bundle not found")
|
||||||
ErrContainerNotFound = errors.New("containerd: container not found")
|
ErrContainerNotFound = errors.New("containerd: container not found")
|
||||||
ErrContainerExists = errors.New("containerd: container already exists")
|
ErrContainerExists = errors.New("containerd: container already exists")
|
||||||
|
ErrProcessNotFound = errors.New("containerd: processs not found for container")
|
||||||
|
|
||||||
// Internal errors
|
// Internal errors
|
||||||
errShutdown = errors.New("containerd: supervisor is shutdown")
|
errShutdown = errors.New("containerd: supervisor is shutdown")
|
||||||
|
|
13
event.go
13
event.go
|
@ -1,5 +1,7 @@
|
||||||
package containerd
|
package containerd
|
||||||
|
|
||||||
|
import "os"
|
||||||
|
|
||||||
type Event interface {
|
type Event interface {
|
||||||
String() string
|
String() string
|
||||||
}
|
}
|
||||||
|
@ -44,3 +46,14 @@ type GetContainersEvent struct {
|
||||||
func (c *GetContainersEvent) String() string {
|
func (c *GetContainersEvent) String() string {
|
||||||
return "get containers"
|
return "get containers"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SignalEvent struct {
|
||||||
|
ID string
|
||||||
|
Pid int
|
||||||
|
Signal os.Signal
|
||||||
|
Err chan error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *SignalEvent) String() string {
|
||||||
|
return "signal event"
|
||||||
|
}
|
||||||
|
|
|
@ -158,6 +158,22 @@ func init() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type libcontainerProcess struct {
|
||||||
|
pid int
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *libcontainerProcess) Pid() int {
|
||||||
|
return p.pid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (p *libcontainerProcess) Signal(s os.Signal) error {
|
||||||
|
proc, err := os.FindProcess(p.pid)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return proc.Signal(s)
|
||||||
|
}
|
||||||
|
|
||||||
type libcontainerContainer struct {
|
type libcontainerContainer struct {
|
||||||
c libcontainer.Container
|
c libcontainer.Container
|
||||||
initProcess *libcontainer.Process
|
initProcess *libcontainer.Process
|
||||||
|
@ -192,8 +208,18 @@ func (c *libcontainerContainer) Delete() error {
|
||||||
return c.c.Destroy()
|
return c.c.Destroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *libcontainerContainer) Processes() ([]int, error) {
|
func (c *libcontainerContainer) Processes() ([]Process, error) {
|
||||||
return c.c.Processes()
|
pids, err := c.c.Processes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
var proceses []Process
|
||||||
|
for _, pid := range pids {
|
||||||
|
proceses = append(proceses, &libcontainerProcess{
|
||||||
|
pid: pid,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return proceses, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewRuntime(stateDir string) (Runtime, error) {
|
func NewRuntime(stateDir string) (Runtime, error) {
|
||||||
|
|
|
@ -92,6 +92,24 @@ func (s *Supervisor) Start(events chan Event) error {
|
||||||
e.Containers = append(e.Containers, c)
|
e.Containers = append(e.Containers, c)
|
||||||
}
|
}
|
||||||
e.Err <- nil
|
e.Err <- nil
|
||||||
|
case *SignalEvent:
|
||||||
|
container, ok := s.containers[e.ID]
|
||||||
|
if !ok {
|
||||||
|
e.Err <- ErrContainerNotFound
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
processes, err := container.Processes()
|
||||||
|
if err != nil {
|
||||||
|
e.Err <- err
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for _, p := range processes {
|
||||||
|
if p.Pid() == e.Pid {
|
||||||
|
e.Err <- p.Signal(e.Signal)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
e.Err <- ErrProcessNotFound
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
Loading…
Reference in a new issue