github.com/runcom/containerd@v0.0.0-20160708090337-9bff9f934c0d/api/grpc/server/server.go (about) 1 package server 2 3 import ( 4 "bufio" 5 "errors" 6 "fmt" 7 "os" 8 "strconv" 9 "strings" 10 "syscall" 11 "time" 12 13 "google.golang.org/grpc" 14 "google.golang.org/grpc/codes" 15 16 "github.com/docker/containerd" 17 "github.com/docker/containerd/api/grpc/types" 18 "github.com/docker/containerd/runtime" 19 "github.com/docker/containerd/supervisor" 20 "github.com/golang/protobuf/ptypes" 21 "golang.org/x/net/context" 22 ) 23 24 type apiServer struct { 25 sv *supervisor.Supervisor 26 } 27 28 // NewServer returns grpc server instance 29 func NewServer(sv *supervisor.Supervisor) types.APIServer { 30 return &apiServer{ 31 sv: sv, 32 } 33 } 34 35 func (s *apiServer) GetServerVersion(ctx context.Context, c *types.GetServerVersionRequest) (*types.GetServerVersionResponse, error) { 36 return &types.GetServerVersionResponse{ 37 Major: containerd.VersionMajor, 38 Minor: containerd.VersionMinor, 39 Patch: containerd.VersionPatch, 40 Revision: containerd.GitCommit, 41 }, nil 42 } 43 44 func (s *apiServer) CreateContainer(ctx context.Context, c *types.CreateContainerRequest) (*types.CreateContainerResponse, error) { 45 if c.BundlePath == "" { 46 return nil, errors.New("empty bundle path") 47 } 48 e := &supervisor.StartTask{} 49 e.ID = c.Id 50 e.BundlePath = c.BundlePath 51 e.Stdin = c.Stdin 52 e.Stdout = c.Stdout 53 e.Stderr = c.Stderr 54 e.Labels = c.Labels 55 e.NoPivotRoot = c.NoPivotRoot 56 e.Runtime = c.Runtime 57 e.RuntimeArgs = c.RuntimeArgs 58 e.StartResponse = make(chan supervisor.StartResponse, 1) 59 if c.Checkpoint != "" { 60 e.CheckpointDir = c.CheckpointDir 61 e.Checkpoint = &runtime.Checkpoint{ 62 Name: c.Checkpoint, 63 } 64 } 65 s.sv.SendTask(e) 66 if err := <-e.ErrorCh(); err != nil { 67 return nil, err 68 } 69 r := <-e.StartResponse 70 apiC, err := createAPIContainer(r.Container, false) 71 if err != nil { 72 return nil, err 73 } 74 return &types.CreateContainerResponse{ 75 Container: apiC, 76 }, nil 77 } 78 79 func (s *apiServer) CreateCheckpoint(ctx context.Context, r *types.CreateCheckpointRequest) (*types.CreateCheckpointResponse, error) { 80 e := &supervisor.CreateCheckpointTask{} 81 e.ID = r.Id 82 e.CheckpointDir = r.CheckpointDir 83 e.Checkpoint = &runtime.Checkpoint{ 84 Name: r.Checkpoint.Name, 85 Exit: r.Checkpoint.Exit, 86 TCP: r.Checkpoint.Tcp, 87 UnixSockets: r.Checkpoint.UnixSockets, 88 Shell: r.Checkpoint.Shell, 89 EmptyNS: r.Checkpoint.EmptyNS, 90 } 91 92 s.sv.SendTask(e) 93 if err := <-e.ErrorCh(); err != nil { 94 return nil, err 95 } 96 return &types.CreateCheckpointResponse{}, nil 97 } 98 99 func (s *apiServer) DeleteCheckpoint(ctx context.Context, r *types.DeleteCheckpointRequest) (*types.DeleteCheckpointResponse, error) { 100 if r.Name == "" { 101 return nil, errors.New("checkpoint name cannot be empty") 102 } 103 e := &supervisor.DeleteCheckpointTask{} 104 e.ID = r.Id 105 e.CheckpointDir = r.CheckpointDir 106 e.Checkpoint = &runtime.Checkpoint{ 107 Name: r.Name, 108 } 109 s.sv.SendTask(e) 110 if err := <-e.ErrorCh(); err != nil { 111 return nil, err 112 } 113 return &types.DeleteCheckpointResponse{}, nil 114 } 115 116 func (s *apiServer) ListCheckpoint(ctx context.Context, r *types.ListCheckpointRequest) (*types.ListCheckpointResponse, error) { 117 e := &supervisor.GetContainersTask{} 118 s.sv.SendTask(e) 119 if err := <-e.ErrorCh(); err != nil { 120 return nil, err 121 } 122 var container runtime.Container 123 for _, c := range e.Containers { 124 if c.ID() == r.Id { 125 container = c 126 break 127 } 128 } 129 if container == nil { 130 return nil, grpc.Errorf(codes.NotFound, "no such containers") 131 } 132 var out []*types.Checkpoint 133 checkpoints, err := container.Checkpoints(r.CheckpointDir) 134 if err != nil { 135 return nil, err 136 } 137 for _, c := range checkpoints { 138 out = append(out, &types.Checkpoint{ 139 Name: c.Name, 140 Tcp: c.TCP, 141 Shell: c.Shell, 142 UnixSockets: c.UnixSockets, 143 // TODO: figure out timestamp 144 //Timestamp: c.Timestamp, 145 }) 146 } 147 return &types.ListCheckpointResponse{Checkpoints: out}, nil 148 } 149 150 func (s *apiServer) Signal(ctx context.Context, r *types.SignalRequest) (*types.SignalResponse, error) { 151 e := &supervisor.SignalTask{} 152 e.ID = r.Id 153 e.PID = r.Pid 154 e.Signal = syscall.Signal(int(r.Signal)) 155 s.sv.SendTask(e) 156 if err := <-e.ErrorCh(); err != nil { 157 return nil, err 158 } 159 return &types.SignalResponse{}, nil 160 } 161 162 func (s *apiServer) State(ctx context.Context, r *types.StateRequest) (*types.StateResponse, error) { 163 e := &supervisor.GetContainersTask{} 164 e.ID = r.Id 165 s.sv.SendTask(e) 166 if err := <-e.ErrorCh(); err != nil { 167 return nil, err 168 } 169 m := s.sv.Machine() 170 state := &types.StateResponse{ 171 Machine: &types.Machine{ 172 Cpus: uint32(m.Cpus), 173 Memory: uint64(m.Memory), 174 }, 175 } 176 for _, c := range e.Containers { 177 apiC, err := createAPIContainer(c, true) 178 if err != nil { 179 return nil, err 180 } 181 state.Containers = append(state.Containers, apiC) 182 } 183 return state, nil 184 } 185 186 func createAPIContainer(c runtime.Container, getPids bool) (*types.Container, error) { 187 processes, err := c.Processes() 188 if err != nil { 189 return nil, grpc.Errorf(codes.Internal, "get processes for container: "+err.Error()) 190 } 191 var procs []*types.Process 192 for _, p := range processes { 193 oldProc := p.Spec() 194 stdio := p.Stdio() 195 proc := &types.Process{ 196 Pid: p.ID(), 197 SystemPid: uint32(p.SystemPid()), 198 Terminal: oldProc.Terminal, 199 Args: oldProc.Args, 200 Env: oldProc.Env, 201 Cwd: oldProc.Cwd, 202 Stdin: stdio.Stdin, 203 Stdout: stdio.Stdout, 204 Stderr: stdio.Stderr, 205 } 206 proc.User = &types.User{ 207 Uid: oldProc.User.UID, 208 Gid: oldProc.User.GID, 209 AdditionalGids: oldProc.User.AdditionalGids, 210 } 211 proc.Capabilities = oldProc.Capabilities 212 proc.ApparmorProfile = oldProc.ApparmorProfile 213 proc.SelinuxLabel = oldProc.SelinuxLabel 214 proc.NoNewPrivileges = oldProc.NoNewPrivileges 215 for _, rl := range oldProc.Rlimits { 216 proc.Rlimits = append(proc.Rlimits, &types.Rlimit{ 217 Type: rl.Type, 218 Soft: rl.Soft, 219 Hard: rl.Hard, 220 }) 221 } 222 procs = append(procs, proc) 223 } 224 var pids []int 225 state := c.State() 226 if getPids && (state == runtime.Running || state == runtime.Paused) { 227 if pids, err = c.Pids(); err != nil { 228 return nil, grpc.Errorf(codes.Internal, "get all pids for container: "+err.Error()) 229 } 230 } 231 return &types.Container{ 232 Id: c.ID(), 233 BundlePath: c.Path(), 234 Processes: procs, 235 Labels: c.Labels(), 236 Status: string(state), 237 Pids: toUint32(pids), 238 Runtime: c.Runtime(), 239 }, nil 240 } 241 242 func toUint32(its []int) []uint32 { 243 o := []uint32{} 244 for _, i := range its { 245 o = append(o, uint32(i)) 246 } 247 return o 248 } 249 250 func (s *apiServer) UpdateContainer(ctx context.Context, r *types.UpdateContainerRequest) (*types.UpdateContainerResponse, error) { 251 e := &supervisor.UpdateTask{} 252 e.ID = r.Id 253 e.State = runtime.State(r.Status) 254 if r.Resources != nil { 255 rs := r.Resources 256 e.Resources = &runtime.Resource{} 257 if rs.CpuShares != 0 { 258 e.Resources.CPUShares = int64(rs.CpuShares) 259 } 260 if rs.BlkioWeight != 0 { 261 e.Resources.BlkioWeight = uint16(rs.BlkioWeight) 262 } 263 if rs.CpuPeriod != 0 { 264 e.Resources.CPUPeriod = int64(rs.CpuPeriod) 265 } 266 if rs.CpuQuota != 0 { 267 e.Resources.CPUQuota = int64(rs.CpuQuota) 268 } 269 if rs.CpusetCpus != "" { 270 e.Resources.CpusetCpus = rs.CpusetCpus 271 } 272 if rs.CpusetMems != "" { 273 e.Resources.CpusetMems = rs.CpusetMems 274 } 275 if rs.KernelMemoryLimit != 0 { 276 e.Resources.KernelMemory = int64(rs.KernelMemoryLimit) 277 } 278 if rs.KernelTCPMemoryLimit != 0 { 279 e.Resources.KernelTCPMemory = int64(rs.KernelTCPMemoryLimit) 280 } 281 if rs.MemoryLimit != 0 { 282 e.Resources.Memory = int64(rs.MemoryLimit) 283 } 284 if rs.MemoryReservation != 0 { 285 e.Resources.MemoryReservation = int64(rs.MemoryReservation) 286 } 287 if rs.MemorySwap != 0 { 288 e.Resources.MemorySwap = int64(rs.MemorySwap) 289 } 290 } 291 s.sv.SendTask(e) 292 if err := <-e.ErrorCh(); err != nil { 293 return nil, err 294 } 295 return &types.UpdateContainerResponse{}, nil 296 } 297 298 func (s *apiServer) UpdateProcess(ctx context.Context, r *types.UpdateProcessRequest) (*types.UpdateProcessResponse, error) { 299 e := &supervisor.UpdateProcessTask{} 300 e.ID = r.Id 301 e.PID = r.Pid 302 e.Height = int(r.Height) 303 e.Width = int(r.Width) 304 e.CloseStdin = r.CloseStdin 305 s.sv.SendTask(e) 306 if err := <-e.ErrorCh(); err != nil { 307 return nil, err 308 } 309 return &types.UpdateProcessResponse{}, nil 310 } 311 312 func (s *apiServer) Events(r *types.EventsRequest, stream types.API_EventsServer) error { 313 t := time.Time{} 314 if r.Timestamp != nil { 315 from, err := ptypes.Timestamp(r.Timestamp) 316 if err != nil { 317 return err 318 } 319 t = from 320 } 321 events := s.sv.Events(t) 322 defer s.sv.Unsubscribe(events) 323 for e := range events { 324 tsp, err := ptypes.TimestampProto(e.Timestamp) 325 if err != nil { 326 return err 327 } 328 if err := stream.Send(&types.Event{ 329 Id: e.ID, 330 Type: e.Type, 331 Timestamp: tsp, 332 Pid: e.PID, 333 Status: uint32(e.Status), 334 }); err != nil { 335 return err 336 } 337 } 338 return nil 339 } 340 341 func convertToPb(st *runtime.Stat) *types.StatsResponse { 342 tsp, _ := ptypes.TimestampProto(st.Timestamp) 343 pbSt := &types.StatsResponse{ 344 Timestamp: tsp, 345 CgroupStats: &types.CgroupStats{}, 346 } 347 systemUsage, _ := getSystemCPUUsage() 348 pbSt.CgroupStats.CpuStats = &types.CpuStats{ 349 CpuUsage: &types.CpuUsage{ 350 TotalUsage: st.CPU.Usage.Total, 351 PercpuUsage: st.CPU.Usage.Percpu, 352 UsageInKernelmode: st.CPU.Usage.Kernel, 353 UsageInUsermode: st.CPU.Usage.User, 354 }, 355 ThrottlingData: &types.ThrottlingData{ 356 Periods: st.CPU.Throttling.Periods, 357 ThrottledPeriods: st.CPU.Throttling.ThrottledPeriods, 358 ThrottledTime: st.CPU.Throttling.ThrottledTime, 359 }, 360 SystemUsage: systemUsage, 361 } 362 pbSt.CgroupStats.MemoryStats = &types.MemoryStats{ 363 Cache: st.Memory.Cache, 364 Usage: &types.MemoryData{ 365 Usage: st.Memory.Usage.Usage, 366 MaxUsage: st.Memory.Usage.Max, 367 Failcnt: st.Memory.Usage.Failcnt, 368 Limit: st.Memory.Usage.Limit, 369 }, 370 SwapUsage: &types.MemoryData{ 371 Usage: st.Memory.Swap.Usage, 372 MaxUsage: st.Memory.Swap.Max, 373 Failcnt: st.Memory.Swap.Failcnt, 374 Limit: st.Memory.Swap.Limit, 375 }, 376 KernelUsage: &types.MemoryData{ 377 Usage: st.Memory.Kernel.Usage, 378 MaxUsage: st.Memory.Kernel.Max, 379 Failcnt: st.Memory.Kernel.Failcnt, 380 Limit: st.Memory.Kernel.Limit, 381 }, 382 Stats: st.Memory.Raw, 383 } 384 pbSt.CgroupStats.BlkioStats = &types.BlkioStats{ 385 IoServiceBytesRecursive: convertBlkioEntryToPb(st.Blkio.IoServiceBytesRecursive), 386 IoServicedRecursive: convertBlkioEntryToPb(st.Blkio.IoServicedRecursive), 387 IoQueuedRecursive: convertBlkioEntryToPb(st.Blkio.IoQueuedRecursive), 388 IoServiceTimeRecursive: convertBlkioEntryToPb(st.Blkio.IoServiceTimeRecursive), 389 IoWaitTimeRecursive: convertBlkioEntryToPb(st.Blkio.IoWaitTimeRecursive), 390 IoMergedRecursive: convertBlkioEntryToPb(st.Blkio.IoMergedRecursive), 391 IoTimeRecursive: convertBlkioEntryToPb(st.Blkio.IoTimeRecursive), 392 SectorsRecursive: convertBlkioEntryToPb(st.Blkio.SectorsRecursive), 393 } 394 pbSt.CgroupStats.HugetlbStats = make(map[string]*types.HugetlbStats) 395 for k, st := range st.Hugetlb { 396 pbSt.CgroupStats.HugetlbStats[k] = &types.HugetlbStats{ 397 Usage: st.Usage, 398 MaxUsage: st.Max, 399 Failcnt: st.Failcnt, 400 } 401 } 402 pbSt.CgroupStats.PidsStats = &types.PidsStats{ 403 Current: st.Pids.Current, 404 Limit: st.Pids.Limit, 405 } 406 return pbSt 407 } 408 409 func convertBlkioEntryToPb(b []runtime.BlkioEntry) []*types.BlkioStatsEntry { 410 var pbEs []*types.BlkioStatsEntry 411 for _, e := range b { 412 pbEs = append(pbEs, &types.BlkioStatsEntry{ 413 Major: e.Major, 414 Minor: e.Minor, 415 Op: e.Op, 416 Value: e.Value, 417 }) 418 } 419 return pbEs 420 } 421 422 const nanoSecondsPerSecond = 1e9 423 424 // getSystemCPUUsage returns the host system's cpu usage in 425 // nanoseconds. An error is returned if the format of the underlying 426 // file does not match. 427 // 428 // Uses /proc/stat defined by POSIX. Looks for the cpu 429 // statistics line and then sums up the first seven fields 430 // provided. See `man 5 proc` for details on specific field 431 // information. 432 func getSystemCPUUsage() (uint64, error) { 433 var line string 434 f, err := os.Open("/proc/stat") 435 if err != nil { 436 return 0, err 437 } 438 bufReader := bufio.NewReaderSize(nil, 128) 439 defer func() { 440 bufReader.Reset(nil) 441 f.Close() 442 }() 443 bufReader.Reset(f) 444 err = nil 445 for err == nil { 446 line, err = bufReader.ReadString('\n') 447 if err != nil { 448 break 449 } 450 parts := strings.Fields(line) 451 switch parts[0] { 452 case "cpu": 453 if len(parts) < 8 { 454 return 0, fmt.Errorf("bad format of cpu stats") 455 } 456 var totalClockTicks uint64 457 for _, i := range parts[1:8] { 458 v, err := strconv.ParseUint(i, 10, 64) 459 if err != nil { 460 return 0, fmt.Errorf("error parsing cpu stats") 461 } 462 totalClockTicks += v 463 } 464 return (totalClockTicks * nanoSecondsPerSecond) / 465 clockTicksPerSecond, nil 466 } 467 } 468 return 0, fmt.Errorf("bad stats format") 469 } 470 471 func (s *apiServer) Stats(ctx context.Context, r *types.StatsRequest) (*types.StatsResponse, error) { 472 e := &supervisor.StatsTask{} 473 e.ID = r.Id 474 e.Stat = make(chan *runtime.Stat, 1) 475 s.sv.SendTask(e) 476 if err := <-e.ErrorCh(); err != nil { 477 return nil, err 478 } 479 stats := <-e.Stat 480 t := convertToPb(stats) 481 return t, nil 482 }