Commit ae7830b4 authored by Dr. Stefan Schimanski's avatar Dr. Stefan Schimanski

Pass Mesos cpu and mem values to cadvisor

parent 31ab4f12
...@@ -92,6 +92,11 @@ type kuberTask struct { ...@@ -92,6 +92,11 @@ type kuberTask struct {
type podStatusFunc func() (*api.PodStatus, error) type podStatusFunc func() (*api.PodStatus, error)
type NodeInfo struct {
Cores int
Mem int64 // in bytes
}
// KubernetesExecutor is an mesos executor that runs pods // KubernetesExecutor is an mesos executor that runs pods
// in a minion machine. // in a minion machine.
type KubernetesExecutor struct { type KubernetesExecutor struct {
...@@ -113,6 +118,7 @@ type KubernetesExecutor struct { ...@@ -113,6 +118,7 @@ type KubernetesExecutor struct {
staticPodsConfigPath string staticPodsConfigPath string
podController *framework.Controller podController *framework.Controller
launchGracePeriod time.Duration launchGracePeriod time.Duration
nodeInfos chan<- NodeInfo
} }
type Config struct { type Config struct {
...@@ -127,6 +133,7 @@ type Config struct { ...@@ -127,6 +133,7 @@ type Config struct {
StaticPodsConfigPath string StaticPodsConfigPath string
PodLW cache.ListerWatcher // mandatory, otherwise initialiation will panic PodLW cache.ListerWatcher // mandatory, otherwise initialiation will panic
LaunchGracePeriod time.Duration LaunchGracePeriod time.Duration
NodeInfos chan<- NodeInfo
} }
func (k *KubernetesExecutor) isConnected() bool { func (k *KubernetesExecutor) isConnected() bool {
...@@ -152,6 +159,7 @@ func New(config Config) *KubernetesExecutor { ...@@ -152,6 +159,7 @@ func New(config Config) *KubernetesExecutor {
podStatusFunc: config.PodStatusFunc, podStatusFunc: config.PodStatusFunc,
staticPodsConfigPath: config.StaticPodsConfigPath, staticPodsConfigPath: config.StaticPodsConfigPath,
launchGracePeriod: config.LaunchGracePeriod, launchGracePeriod: config.LaunchGracePeriod,
nodeInfos: config.NodeInfos,
} }
// watch pods from the given pod ListWatch // watch pods from the given pod ListWatch
...@@ -236,6 +244,10 @@ func (k *KubernetesExecutor) Registered(driver bindings.ExecutorDriver, ...@@ -236,6 +244,10 @@ func (k *KubernetesExecutor) Registered(driver bindings.ExecutorDriver,
Pods: []*api.Pod{}, Pods: []*api.Pod{},
Op: kubetypes.SET, Op: kubetypes.SET,
}) })
if slaveInfo != nil && k.nodeInfos != nil {
k.nodeInfos <- nodeInfo(slaveInfo, executorInfo) // leave it behind the upper lock to avoid panics
}
} }
// Reregistered is called when the executor is successfully re-registered with the slave. // Reregistered is called when the executor is successfully re-registered with the slave.
...@@ -255,6 +267,16 @@ func (k *KubernetesExecutor) Reregistered(driver bindings.ExecutorDriver, slaveI ...@@ -255,6 +267,16 @@ func (k *KubernetesExecutor) Reregistered(driver bindings.ExecutorDriver, slaveI
log.Errorf("cannot update node labels: %v", err) log.Errorf("cannot update node labels: %v", err)
} }
} }
if slaveInfo != nil && k.nodeInfos != nil {
// make sure nodeInfos is not nil and send new NodeInfo
k.lock.Lock()
defer k.lock.Unlock()
if k.isDone() {
return
}
k.nodeInfos <- nodeInfo(slaveInfo, nil)
}
} }
// initializeStaticPodsSource unzips the data slice into the static-pods directory // initializeStaticPodsSource unzips the data slice into the static-pods directory
...@@ -796,6 +818,7 @@ func (k *KubernetesExecutor) doShutdown(driver bindings.ExecutorDriver) { ...@@ -796,6 +818,7 @@ func (k *KubernetesExecutor) doShutdown(driver bindings.ExecutorDriver) {
// signal to all listeners that this KubeletExecutor is done! // signal to all listeners that this KubeletExecutor is done!
close(k.terminate) close(k.terminate)
close(k.updateChan) close(k.updateChan)
close(k.nodeInfos)
if k.shutdownAlert != nil { if k.shutdownAlert != nil {
func() { func() {
...@@ -926,3 +949,40 @@ func differentTime(a, b *unversionedapi.Time) bool { ...@@ -926,3 +949,40 @@ func differentTime(a, b *unversionedapi.Time) bool {
func differentPeriod(a, b *int64) bool { func differentPeriod(a, b *int64) bool {
return (a == nil) != (b == nil) || (a != nil && b != nil && *a != *b) return (a == nil) != (b == nil) || (a != nil && b != nil && *a != *b)
} }
func nodeInfo(si *mesos.SlaveInfo, ei *mesos.ExecutorInfo) NodeInfo {
var executorCPU, executorMem float64
// get executor resources
if ei != nil {
for _, r := range ei.GetResources() {
if r == nil || r.GetType() != mesos.Value_SCALAR {
continue
}
switch r.GetName() {
case "cpus":
executorCPU = r.GetScalar().GetValue()
case "mem":
executorMem = r.GetScalar().GetValue()
}
}
}
// get resource capacity of the node
ni := NodeInfo{}
for _, r := range si.GetResources() {
if r == nil || r.GetType() != mesos.Value_SCALAR {
continue
}
switch r.GetName() {
case "cpus":
// We intentionally take the floor of executorCPU because cores are integers
// and we would loose a complete cpu here if the value is <1.
ni.Cores = int(r.GetScalar().GetValue() - float64(int(executorCPU)))
case "mem":
ni.Mem = int64(r.GetScalar().GetValue()-executorMem) * 1024 * 1024
}
}
return ni
}
...@@ -135,8 +135,9 @@ func TestExecutorLaunchAndKillTask(t *testing.T) { ...@@ -135,8 +135,9 @@ func TestExecutorLaunchAndKillTask(t *testing.T) {
mockDriver := &MockExecutorDriver{} mockDriver := &MockExecutorDriver{}
updates := make(chan kubetypes.PodUpdate, 1024) updates := make(chan kubetypes.PodUpdate, 1024)
config := Config{ config := Config{
Docker: dockertools.ConnectToDockerOrDie("fake://"), Docker: dockertools.ConnectToDockerOrDie("fake://"),
Updates: updates, Updates: updates,
NodeInfos: make(chan NodeInfo, 1),
APIClient: client.NewOrDie(&client.Config{ APIClient: client.NewOrDie(&client.Config{
Host: testApiServer.server.URL, Host: testApiServer.server.URL,
Version: testapi.Default.Version(), Version: testapi.Default.Version(),
...@@ -297,8 +298,9 @@ func TestExecutorStaticPods(t *testing.T) { ...@@ -297,8 +298,9 @@ func TestExecutorStaticPods(t *testing.T) {
mockDriver := &MockExecutorDriver{} mockDriver := &MockExecutorDriver{}
config := Config{ config := Config{
Docker: dockertools.ConnectToDockerOrDie("fake://"), Docker: dockertools.ConnectToDockerOrDie("fake://"),
Updates: make(chan kubetypes.PodUpdate, 1), // allow kube-executor source to proceed past init Updates: make(chan kubetypes.PodUpdate, 1), // allow kube-executor source to proceed past init
NodeInfos: make(chan NodeInfo, 1),
APIClient: client.NewOrDie(&client.Config{ APIClient: client.NewOrDie(&client.Config{
Host: testApiServer.server.URL, Host: testApiServer.server.URL,
Version: testapi.Default.Version(), Version: testapi.Default.Version(),
...@@ -379,8 +381,9 @@ func TestExecutorFrameworkMessage(t *testing.T) { ...@@ -379,8 +381,9 @@ func TestExecutorFrameworkMessage(t *testing.T) {
mockDriver := &MockExecutorDriver{} mockDriver := &MockExecutorDriver{}
kubeletFinished := make(chan struct{}) kubeletFinished := make(chan struct{})
config := Config{ config := Config{
Docker: dockertools.ConnectToDockerOrDie("fake://"), Docker: dockertools.ConnectToDockerOrDie("fake://"),
Updates: make(chan kubetypes.PodUpdate, 1024), Updates: make(chan kubetypes.PodUpdate, 1024),
NodeInfos: make(chan NodeInfo, 1),
APIClient: client.NewOrDie(&client.Config{ APIClient: client.NewOrDie(&client.Config{
Host: testApiServer.server.URL, Host: testApiServer.server.URL,
Version: testapi.Default.Version(), Version: testapi.Default.Version(),
...@@ -558,8 +561,9 @@ func TestExecutorShutdown(t *testing.T) { ...@@ -558,8 +561,9 @@ func TestExecutorShutdown(t *testing.T) {
var exitCalled int32 = 0 var exitCalled int32 = 0
updates := make(chan kubetypes.PodUpdate, 1024) updates := make(chan kubetypes.PodUpdate, 1024)
config := Config{ config := Config{
Docker: dockertools.ConnectToDockerOrDie("fake://"), Docker: dockertools.ConnectToDockerOrDie("fake://"),
Updates: updates, Updates: updates,
NodeInfos: make(chan NodeInfo, 1),
ShutdownAlert: func() { ShutdownAlert: func() {
close(kubeletFinished) close(kubeletFinished)
}, },
......
/*
Copyright 2015 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 service
import (
"k8s.io/kubernetes/pkg/kubelet/cadvisor"
cadvisorApi "github.com/google/cadvisor/info/v1"
)
type MesosCadvisor struct {
cadvisor.Interface
cores int
mem int64
}
func NewMesosCadvisor(cores int, mem int64, port uint) (*MesosCadvisor, error) {
c, err := cadvisor.New(port)
if err != nil {
return nil, err
}
return &MesosCadvisor{c, cores, mem}, nil
}
func (mc *MesosCadvisor) MachineInfo() (*cadvisorApi.MachineInfo, error) {
mi, err := mc.Interface.MachineInfo()
if err != nil {
return nil, err
}
// set Mesos provided values
mesosMi := *mi
mesosMi.NumCores = mc.cores
mesosMi.MemoryCapacity = mc.mem
return &mesosMi, nil
}
...@@ -78,7 +78,7 @@ func (s *KubeletExecutorServer) AddFlags(fs *pflag.FlagSet) { ...@@ -78,7 +78,7 @@ func (s *KubeletExecutorServer) AddFlags(fs *pflag.FlagSet) {
fs.DurationVar(&s.LaunchGracePeriod, "mesos-launch-grace-period", s.LaunchGracePeriod, "Launch grace period after which launching tasks will be cancelled. Zero disables launch cancellation.") fs.DurationVar(&s.LaunchGracePeriod, "mesos-launch-grace-period", s.LaunchGracePeriod, "Launch grace period after which launching tasks will be cancelled. Zero disables launch cancellation.")
} }
func (s *KubeletExecutorServer) runExecutor(execUpdates chan<- kubetypes.PodUpdate, kubeletFinished <-chan struct{}, func (s *KubeletExecutorServer) runExecutor(execUpdates chan<- kubetypes.PodUpdate, nodeInfos chan<- executor.NodeInfo, kubeletFinished <-chan struct{},
staticPodsConfigPath string, apiclient *client.Client) error { staticPodsConfigPath string, apiclient *client.Client) error {
exec := executor.New(executor.Config{ exec := executor.New(executor.Config{
Updates: execUpdates, Updates: execUpdates,
...@@ -113,6 +113,7 @@ func (s *KubeletExecutorServer) runExecutor(execUpdates chan<- kubetypes.PodUpda ...@@ -113,6 +113,7 @@ func (s *KubeletExecutorServer) runExecutor(execUpdates chan<- kubetypes.PodUpda
PodLW: cache.NewListWatchFromClient(apiclient, "pods", api.NamespaceAll, PodLW: cache.NewListWatchFromClient(apiclient, "pods", api.NamespaceAll,
fields.OneTermEqualSelector(client.PodHost, s.HostnameOverride), fields.OneTermEqualSelector(client.PodHost, s.HostnameOverride),
), ),
NodeInfos: nodeInfos,
}) })
// initialize driver and initialize the executor with it // initialize driver and initialize the executor with it
...@@ -139,7 +140,7 @@ func (s *KubeletExecutorServer) runExecutor(execUpdates chan<- kubetypes.PodUpda ...@@ -139,7 +140,7 @@ func (s *KubeletExecutorServer) runExecutor(execUpdates chan<- kubetypes.PodUpda
return nil return nil
} }
func (s *KubeletExecutorServer) runKubelet(execUpdates <-chan kubetypes.PodUpdate, kubeletDone chan<- struct{}, func (s *KubeletExecutorServer) runKubelet(execUpdates <-chan kubetypes.PodUpdate, nodeInfos <-chan executor.NodeInfo, kubeletDone chan<- struct{},
staticPodsConfigPath string, apiclient *client.Client) error { staticPodsConfigPath string, apiclient *client.Client) error {
kcfg, err := s.UnsecuredKubeletConfig() kcfg, err := s.UnsecuredKubeletConfig()
if err == nil { if err == nil {
...@@ -179,6 +180,20 @@ func (s *KubeletExecutorServer) runKubelet(execUpdates <-chan kubetypes.PodUpdat ...@@ -179,6 +180,20 @@ func (s *KubeletExecutorServer) runKubelet(execUpdates <-chan kubetypes.PodUpdat
panic("cloud provider must not be set") panic("cloud provider must not be set")
} }
// create custom cAdvisor interface which return the resource values that Mesos reports
ni := <-nodeInfos
cAdvisorInterface, err := NewMesosCadvisor(ni.Cores, ni.Mem, s.CAdvisorPort)
if err != nil {
return err
}
kcfg.CAdvisorInterface = cAdvisorInterface
go func() {
for ni := range nodeInfos {
// TODO(sttts): implement with MachineAllocable mechanism when https://github.com/kubernetes/kubernetes/issues/13984 is finished
log.V(3).Infof("ignoring updated node resources: %v", ni)
}
}()
// create main pod source // create main pod source
updates := kcfg.PodConfig.Channel(MESOS_CFG_SOURCE) updates := kcfg.PodConfig.Channel(MESOS_CFG_SOURCE)
go func() { go func() {
...@@ -217,6 +232,7 @@ func (s *KubeletExecutorServer) Run(hks hyperkube.Interface, _ []string) error { ...@@ -217,6 +232,7 @@ func (s *KubeletExecutorServer) Run(hks hyperkube.Interface, _ []string) error {
// create shared channels // create shared channels
kubeletFinished := make(chan struct{}) kubeletFinished := make(chan struct{})
execUpdates := make(chan kubetypes.PodUpdate, 1) execUpdates := make(chan kubetypes.PodUpdate, 1)
nodeInfos := make(chan executor.NodeInfo, 1)
// create static pods directory // create static pods directory
staticPodsConfigPath := filepath.Join(s.RootDirectory, "static-pods") staticPodsConfigPath := filepath.Join(s.RootDirectory, "static-pods")
...@@ -237,13 +253,13 @@ func (s *KubeletExecutorServer) Run(hks hyperkube.Interface, _ []string) error { ...@@ -237,13 +253,13 @@ func (s *KubeletExecutorServer) Run(hks hyperkube.Interface, _ []string) error {
} }
// start executor // start executor
err = s.runExecutor(execUpdates, kubeletFinished, staticPodsConfigPath, apiclient) err = s.runExecutor(execUpdates, nodeInfos, kubeletFinished, staticPodsConfigPath, apiclient)
if err != nil { if err != nil {
return err return err
} }
// start kubelet, blocking // start kubelet, blocking
return s.runKubelet(execUpdates, kubeletFinished, staticPodsConfigPath, apiclient) return s.runKubelet(execUpdates, nodeInfos, kubeletFinished, staticPodsConfigPath, apiclient)
} }
func defaultBindingAddress() string { func defaultBindingAddress() string {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment