Add mesos containerizer support
This commit includes support for collecting container stats launched by mesos containerizer.
This commit is contained in:
parent
2df69b73de
commit
ed0e3f0f43
@ -36,6 +36,7 @@ const (
|
|||||||
ContainerTypeSystemd
|
ContainerTypeSystemd
|
||||||
ContainerTypeCrio
|
ContainerTypeCrio
|
||||||
ContainerTypeContainerd
|
ContainerTypeContainerd
|
||||||
|
ContainerTypeMesos
|
||||||
)
|
)
|
||||||
|
|
||||||
// Interface for container operation handlers.
|
// Interface for container operation handlers.
|
||||||
|
162
container/mesos/client.go
Normal file
162
container/mesos/client.go
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
// Copyright 2018 Google Inc. 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 mesos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/Rican7/retry"
|
||||||
|
"github.com/Rican7/retry/strategy"
|
||||||
|
"github.com/mesos/mesos-go/api/v1/lib"
|
||||||
|
"github.com/mesos/mesos-go/api/v1/lib/agent"
|
||||||
|
"github.com/mesos/mesos-go/api/v1/lib/agent/calls"
|
||||||
|
mclient "github.com/mesos/mesos-go/api/v1/lib/client"
|
||||||
|
"github.com/mesos/mesos-go/api/v1/lib/encoding/codecs"
|
||||||
|
"github.com/mesos/mesos-go/api/v1/lib/httpcli"
|
||||||
|
"net/url"
|
||||||
|
"sync"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
maxRetryAttempts = 3
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
mesosClientOnce sync.Once
|
||||||
|
mesosClient *client
|
||||||
|
)
|
||||||
|
|
||||||
|
type client struct {
|
||||||
|
hc *httpcli.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
type mesosAgentClient interface {
|
||||||
|
ContainerInfo(id string) (*containerInfo, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type containerInfo struct {
|
||||||
|
cntr *mContainer
|
||||||
|
labels map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
// Client is an interface to query mesos agent http endpoints
|
||||||
|
func Client() (mesosAgentClient, error) {
|
||||||
|
mesosClientOnce.Do(func() {
|
||||||
|
// Start Client
|
||||||
|
apiURL := url.URL{
|
||||||
|
Scheme: "http",
|
||||||
|
Host: *MesosAgentAddress,
|
||||||
|
Path: "/api/v1",
|
||||||
|
}
|
||||||
|
|
||||||
|
mesosClient = &client{
|
||||||
|
hc: httpcli.New(
|
||||||
|
httpcli.Endpoint(apiURL.String()),
|
||||||
|
httpcli.Codec(codecs.ByMediaType[codecs.MediaTypeProtobuf]),
|
||||||
|
httpcli.Do(httpcli.With(httpcli.Timeout(*MesosAgentTimeout))),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
})
|
||||||
|
return mesosClient, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainerInfo returns the container information of the given container id
|
||||||
|
func (self *client) ContainerInfo(id string) (*containerInfo, error) {
|
||||||
|
c, err := self.getContainer(id)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get labels of the container
|
||||||
|
l, err := self.getLabels(c)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &containerInfo{
|
||||||
|
cntr: c,
|
||||||
|
labels: l,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *client) getContainer(id string) (*mContainer, error) {
|
||||||
|
// Get all containers
|
||||||
|
cntrs, err := self.getContainers()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if there is a container with given id and return the container
|
||||||
|
for _, c := range cntrs.Containers {
|
||||||
|
if c.ContainerID.Value == id {
|
||||||
|
return &c, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("can't locate container %s", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *client) getContainers() (mContainers, error) {
|
||||||
|
req := calls.NonStreaming(calls.GetContainers())
|
||||||
|
result, err := self.fetchAndDecode(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to get mesos containers: %v", err)
|
||||||
|
}
|
||||||
|
cntrs := result.GetContainers
|
||||||
|
return cntrs, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *client) getLabels(c *mContainer) (map[string]string, error) {
|
||||||
|
// Get mesos agent state which contains all containers labels
|
||||||
|
var s state
|
||||||
|
req := calls.NonStreaming(calls.GetState())
|
||||||
|
result, err := self.fetchAndDecode(req)
|
||||||
|
if err != nil {
|
||||||
|
return map[string]string{}, fmt.Errorf("failed to get mesos agent state: %v", err)
|
||||||
|
}
|
||||||
|
s.st = result.GetState
|
||||||
|
|
||||||
|
// Fetch labels from state object
|
||||||
|
labels, err := s.FetchLabels(c.FrameworkID.Value, c.ExecutorID.Value)
|
||||||
|
if err != nil {
|
||||||
|
return labels, fmt.Errorf("error while fetching labels from executor: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *client) fetchAndDecode(req calls.RequestFunc) (*agent.Response, error) {
|
||||||
|
var res mesos.Response
|
||||||
|
var err error
|
||||||
|
|
||||||
|
// Send request
|
||||||
|
err = retry.Retry(
|
||||||
|
func(attempt uint) error {
|
||||||
|
res, err = mesosClient.hc.Send(req, mclient.ResponseClassSingleton, nil)
|
||||||
|
return err
|
||||||
|
},
|
||||||
|
strategy.Limit(maxRetryAttempts),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error fetching %s: %s", req.Call(), err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decode the result
|
||||||
|
var target agent.Response
|
||||||
|
err = res.Decode(&target)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("error while decoding response body from %s: %s", res, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &target, nil
|
||||||
|
}
|
40
container/mesos/client_test.go
Normal file
40
container/mesos/client_test.go
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
// Copyright 2018 Google Inc. 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 mesos
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
type FakeMesosAgentClient struct {
|
||||||
|
cntrInfo map[string]*containerInfo
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *FakeMesosAgentClient) ContainerInfo(id string) (*containerInfo, error) {
|
||||||
|
if c.err != nil {
|
||||||
|
return nil, c.err
|
||||||
|
}
|
||||||
|
cInfo, ok := c.cntrInfo[id]
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("can't locate container %s", id)
|
||||||
|
}
|
||||||
|
return cInfo, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func fakeMesosAgentClient(cntrInfo map[string]*containerInfo, err error) mesosAgentClient {
|
||||||
|
return &FakeMesosAgentClient{
|
||||||
|
err: err,
|
||||||
|
cntrInfo: cntrInfo,
|
||||||
|
}
|
||||||
|
}
|
153
container/mesos/factory.go
Normal file
153
container/mesos/factory.go
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
// Copyright 2018 Google Inc. 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 mesos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"flag"
|
||||||
|
"fmt"
|
||||||
|
"path"
|
||||||
|
"regexp"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"github.com/google/cadvisor/container"
|
||||||
|
"github.com/google/cadvisor/container/libcontainer"
|
||||||
|
"github.com/google/cadvisor/fs"
|
||||||
|
info "github.com/google/cadvisor/info/v1"
|
||||||
|
"github.com/google/cadvisor/manager/watcher"
|
||||||
|
)
|
||||||
|
|
||||||
|
var MesosAgentAddress = flag.String("mesos_agent", "127.0.0.1:5051", "Mesos agent address")
|
||||||
|
var MesosAgentTimeout = flag.Duration("mesos_agent_timeout", 10*time.Second, "Mesos agent timeout")
|
||||||
|
|
||||||
|
// The namespace under which mesos aliases are unique.
|
||||||
|
const MesosNamespace = "mesos"
|
||||||
|
|
||||||
|
// Regexp that identifies mesos cgroups, containers started with
|
||||||
|
// --cgroup-parent have another prefix than 'mesos'
|
||||||
|
var mesosCgroupRegexp = regexp.MustCompile(`([a-z-0-9]{36})`)
|
||||||
|
|
||||||
|
// mesosFactory implements the interface ContainerHandlerFactory
|
||||||
|
type mesosFactory struct {
|
||||||
|
machineInfoFactory info.MachineInfoFactory
|
||||||
|
|
||||||
|
// Information about the cgroup subsystems.
|
||||||
|
cgroupSubsystems libcontainer.CgroupSubsystems
|
||||||
|
|
||||||
|
// Information about mounted filesystems.
|
||||||
|
fsInfo fs.FsInfo
|
||||||
|
|
||||||
|
ignoreMetrics map[container.MetricKind]struct{}
|
||||||
|
|
||||||
|
client mesosAgentClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mesosFactory) String() string {
|
||||||
|
return MesosNamespace
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mesosFactory) NewContainerHandler(name string, inHostNamespace bool) (container.ContainerHandler, error) {
|
||||||
|
client, err := Client()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return newMesosContainerHandler(
|
||||||
|
name,
|
||||||
|
&self.cgroupSubsystems,
|
||||||
|
self.machineInfoFactory,
|
||||||
|
self.fsInfo,
|
||||||
|
self.ignoreMetrics,
|
||||||
|
inHostNamespace,
|
||||||
|
client,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ContainerNameToMesosId returns the Mesos ID from the full container name.
|
||||||
|
func ContainerNameToMesosId(name string) string {
|
||||||
|
id := path.Base(name)
|
||||||
|
|
||||||
|
if matches := mesosCgroupRegexp.FindStringSubmatch(id); matches != nil {
|
||||||
|
return matches[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
// isContainerName returns true if the cgroup with associated name
|
||||||
|
// corresponds to a mesos container.
|
||||||
|
func isContainerName(name string) bool {
|
||||||
|
// always ignore .mount cgroup even if associated with mesos and delegate to systemd
|
||||||
|
if strings.HasSuffix(name, ".mount") {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return mesosCgroupRegexp.MatchString(path.Base(name))
|
||||||
|
}
|
||||||
|
|
||||||
|
// The mesos factory can handle any container.
|
||||||
|
func (self *mesosFactory) CanHandleAndAccept(name string) (handle bool, accept bool, err error) {
|
||||||
|
// if the container is not associated with mesos, we can't handle it or accept it.
|
||||||
|
if !isContainerName(name) {
|
||||||
|
return false, false, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the container is known to mesos and it is active.
|
||||||
|
id := ContainerNameToMesosId(name)
|
||||||
|
|
||||||
|
c, err := self.client.ContainerInfo(id)
|
||||||
|
if err != nil {
|
||||||
|
return false, true, fmt.Errorf("error getting running container: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
pid := int(*c.cntr.ContainerStatus.ExecutorPID)
|
||||||
|
if pid <= 0 {
|
||||||
|
return false, true, fmt.Errorf("mesos container pid: %d is invalid", pid)
|
||||||
|
}
|
||||||
|
|
||||||
|
return true, true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mesosFactory) DebugInfo() map[string][]string {
|
||||||
|
return map[string][]string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func Register(
|
||||||
|
machineInfoFactory info.MachineInfoFactory,
|
||||||
|
fsInfo fs.FsInfo,
|
||||||
|
ignoreMetrics container.MetricSet,
|
||||||
|
) error {
|
||||||
|
client, err := Client()
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("unable to create mesos agent client: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
cgroupSubsystems, err := libcontainer.GetCgroupSubsystems()
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("failed to get cgroup subsystems: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
glog.V(1).Infof("Registering mesos factory")
|
||||||
|
factory := &mesosFactory{
|
||||||
|
machineInfoFactory: machineInfoFactory,
|
||||||
|
cgroupSubsystems: cgroupSubsystems,
|
||||||
|
fsInfo: fsInfo,
|
||||||
|
ignoreMetrics: ignoreMetrics,
|
||||||
|
client: client,
|
||||||
|
}
|
||||||
|
container.RegisterContainerHandlerFactory(factory, []watcher.ContainerWatchSource{watcher.Raw})
|
||||||
|
return nil
|
||||||
|
}
|
85
container/mesos/factory_test.go
Normal file
85
container/mesos/factory_test.go
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
// Copyright 2018 Google Inc. 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 mesos
|
||||||
|
|
||||||
|
import (
|
||||||
|
containerlibcontainer "github.com/google/cadvisor/container/libcontainer"
|
||||||
|
"github.com/mesos/mesos-go/api/v1/lib"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestIsContainerName(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "/system.slice/var-lib-mesos-provisioner-containers-04e20821-d67d3-4bf7-96b4-7d4495f50b28-backends-overlay-rootfses-6d97be39-7359-4bb7-a46b-e55c6771da81.mount",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "/mesos/04e20821-67d3-4bf7-96b4-7d4495f50b28",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
if actual := isContainerName(test.name); actual != test.expected {
|
||||||
|
t.Errorf("%s: expected: %v, actual: %v", test.name, test.expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
func TestCanHandleAndAccept(t *testing.T) {
|
||||||
|
as := assert.New(t)
|
||||||
|
testContainers := make(map[string]*containerInfo)
|
||||||
|
var pid uint32 = 123
|
||||||
|
testContainer := &containerInfo{
|
||||||
|
cntr: &mContainer{
|
||||||
|
ContainerStatus: &mesos.ContainerStatus{
|
||||||
|
ExecutorPID: &pid,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
testContainers["04e20821-67d3-4bf7-96b4-7d4495f50b28"] = testContainer
|
||||||
|
|
||||||
|
f := &mesosFactory{
|
||||||
|
machineInfoFactory: nil,
|
||||||
|
cgroupSubsystems: containerlibcontainer.CgroupSubsystems{},
|
||||||
|
fsInfo: nil,
|
||||||
|
ignoreMetrics: nil,
|
||||||
|
client: fakeMesosAgentClient(testContainers, nil),
|
||||||
|
}
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
expected bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "/mesos/04e20821-67d3-4bf7-96b4-7d4495f50b28",
|
||||||
|
expected: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "/system.slice/var-lib-mesos-provisioner-containers-04e20821-d67d3-4bf7-96b4-7d4495f50b28-backends-overlay-rootfses-6d97be39-7359-4bb7-a46b-e55c6771da81.mount",
|
||||||
|
expected: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, test := range tests {
|
||||||
|
b1, b2, err := f.CanHandleAndAccept(test.name)
|
||||||
|
as.Nil(err)
|
||||||
|
as.Equal(b1, test.expected)
|
||||||
|
as.Equal(b2, test.expected)
|
||||||
|
}
|
||||||
|
}
|
210
container/mesos/handler.go
Normal file
210
container/mesos/handler.go
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
// Copyright 2018 Google Inc. 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.
|
||||||
|
|
||||||
|
// Handler for "mesos" containers.
|
||||||
|
package mesos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"path"
|
||||||
|
|
||||||
|
"github.com/google/cadvisor/container"
|
||||||
|
"github.com/google/cadvisor/container/common"
|
||||||
|
containerlibcontainer "github.com/google/cadvisor/container/libcontainer"
|
||||||
|
"github.com/google/cadvisor/fs"
|
||||||
|
info "github.com/google/cadvisor/info/v1"
|
||||||
|
|
||||||
|
cgroupfs "github.com/opencontainers/runc/libcontainer/cgroups/fs"
|
||||||
|
libcontainerconfigs "github.com/opencontainers/runc/libcontainer/configs"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mesosContainerHandler struct {
|
||||||
|
// Name of the container for this handler.
|
||||||
|
name string
|
||||||
|
|
||||||
|
// machineInfoFactory provides info.MachineInfo
|
||||||
|
machineInfoFactory info.MachineInfoFactory
|
||||||
|
|
||||||
|
// Absolute path to the cgroup hierarchies of this container.
|
||||||
|
// (e.g.: "cpu" -> "/sys/fs/cgroup/cpu/test")
|
||||||
|
cgroupPaths map[string]string
|
||||||
|
|
||||||
|
// File System Info
|
||||||
|
fsInfo fs.FsInfo
|
||||||
|
|
||||||
|
// Metrics to be ignored.
|
||||||
|
ignoreMetrics container.MetricSet
|
||||||
|
|
||||||
|
labels map[string]string
|
||||||
|
|
||||||
|
// Reference to the container
|
||||||
|
reference info.ContainerReference
|
||||||
|
|
||||||
|
libcontainerHandler *containerlibcontainer.Handler
|
||||||
|
}
|
||||||
|
|
||||||
|
func isRootCgroup(name string) bool {
|
||||||
|
return name == "/"
|
||||||
|
}
|
||||||
|
|
||||||
|
func newMesosContainerHandler(
|
||||||
|
name string,
|
||||||
|
cgroupSubsystems *containerlibcontainer.CgroupSubsystems,
|
||||||
|
machineInfoFactory info.MachineInfoFactory,
|
||||||
|
fsInfo fs.FsInfo,
|
||||||
|
ignoreMetrics container.MetricSet,
|
||||||
|
inHostNamespace bool,
|
||||||
|
client mesosAgentClient,
|
||||||
|
) (container.ContainerHandler, error) {
|
||||||
|
cgroupPaths := common.MakeCgroupPaths(cgroupSubsystems.MountPoints, name)
|
||||||
|
for key, val := range cgroupSubsystems.MountPoints {
|
||||||
|
cgroupPaths[key] = path.Join(val, name)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Generate the equivalent cgroup manager for this container.
|
||||||
|
cgroupManager := &cgroupfs.Manager{
|
||||||
|
Cgroups: &libcontainerconfigs.Cgroup{
|
||||||
|
Name: name,
|
||||||
|
},
|
||||||
|
Paths: cgroupPaths,
|
||||||
|
}
|
||||||
|
|
||||||
|
rootFs := "/"
|
||||||
|
if !inHostNamespace {
|
||||||
|
rootFs = "/rootfs"
|
||||||
|
}
|
||||||
|
|
||||||
|
id := ContainerNameToMesosId(name)
|
||||||
|
|
||||||
|
cinfo, err := client.ContainerInfo(id)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
labels := cinfo.labels
|
||||||
|
pid := int(*cinfo.cntr.ContainerStatus.ExecutorPID)
|
||||||
|
|
||||||
|
libcontainerHandler := containerlibcontainer.NewHandler(cgroupManager, rootFs, pid, ignoreMetrics)
|
||||||
|
|
||||||
|
reference := info.ContainerReference{
|
||||||
|
Id: id,
|
||||||
|
Name: name,
|
||||||
|
Namespace: MesosNamespace,
|
||||||
|
Aliases: []string{id, name},
|
||||||
|
}
|
||||||
|
|
||||||
|
handler := &mesosContainerHandler{
|
||||||
|
name: name,
|
||||||
|
machineInfoFactory: machineInfoFactory,
|
||||||
|
cgroupPaths: cgroupPaths,
|
||||||
|
fsInfo: fsInfo,
|
||||||
|
ignoreMetrics: ignoreMetrics,
|
||||||
|
labels: labels,
|
||||||
|
reference: reference,
|
||||||
|
libcontainerHandler: libcontainerHandler,
|
||||||
|
}
|
||||||
|
|
||||||
|
return handler, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mesosContainerHandler) ContainerReference() (info.ContainerReference, error) {
|
||||||
|
// We only know the container by its one name.
|
||||||
|
return self.reference, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing to start up.
|
||||||
|
func (self *mesosContainerHandler) Start() {}
|
||||||
|
|
||||||
|
// Nothing to clean up.
|
||||||
|
func (self *mesosContainerHandler) Cleanup() {}
|
||||||
|
|
||||||
|
func (self *mesosContainerHandler) GetSpec() (info.ContainerSpec, error) {
|
||||||
|
// TODO: Since we dont collect disk usage and network stats for mesos containers, we set
|
||||||
|
// hasFilesystem and hasNetwork to false. Revisit when we support disk usage, network
|
||||||
|
// stats for mesos containers.
|
||||||
|
hasNetwork := false
|
||||||
|
hasFilesystem := false
|
||||||
|
|
||||||
|
spec, err := common.GetSpec(self.cgroupPaths, self.machineInfoFactory, hasNetwork, hasFilesystem)
|
||||||
|
if err != nil {
|
||||||
|
return spec, err
|
||||||
|
}
|
||||||
|
|
||||||
|
spec.Labels = self.labels
|
||||||
|
|
||||||
|
return spec, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mesosContainerHandler) getFsStats(stats *info.ContainerStats) error {
|
||||||
|
|
||||||
|
mi, err := self.machineInfoFactory.GetMachineInfo()
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if !self.ignoreMetrics.Has(container.DiskIOMetrics) {
|
||||||
|
common.AssignDeviceNamesToDiskStats((*common.MachineInfoNamer)(mi), &stats.DiskIo)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mesosContainerHandler) GetStats() (*info.ContainerStats, error) {
|
||||||
|
stats, err := self.libcontainerHandler.GetStats()
|
||||||
|
if err != nil {
|
||||||
|
return stats, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get filesystem stats.
|
||||||
|
err = self.getFsStats(stats)
|
||||||
|
if err != nil {
|
||||||
|
return stats, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return stats, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mesosContainerHandler) GetCgroupPath(resource string) (string, error) {
|
||||||
|
path, ok := self.cgroupPaths[resource]
|
||||||
|
if !ok {
|
||||||
|
return "", fmt.Errorf("could not find path for resource %q for container %q\n", resource, self.name)
|
||||||
|
}
|
||||||
|
return path, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mesosContainerHandler) GetContainerLabels() map[string]string {
|
||||||
|
return self.labels
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mesosContainerHandler) GetContainerIPAddress() string {
|
||||||
|
// the IP address for the mesos container corresponds to the system ip address.
|
||||||
|
return "127.0.0.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mesosContainerHandler) ListContainers(listType container.ListType) ([]info.ContainerReference, error) {
|
||||||
|
return common.ListContainers(self.name, self.cgroupPaths, listType)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mesosContainerHandler) ListProcesses(listType container.ListType) ([]int, error) {
|
||||||
|
return self.libcontainerHandler.GetProcesses()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mesosContainerHandler) Exists() bool {
|
||||||
|
return common.CgroupExists(self.cgroupPaths)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *mesosContainerHandler) Type() container.ContainerType {
|
||||||
|
return container.ContainerTypeMesos
|
||||||
|
}
|
111
container/mesos/handler_test.go
Normal file
111
container/mesos/handler_test.go
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
// Copyright 2018 Google Inc. 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 mesos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/google/cadvisor/container"
|
||||||
|
containerlibcontainer "github.com/google/cadvisor/container/libcontainer"
|
||||||
|
"github.com/google/cadvisor/fs"
|
||||||
|
info "github.com/google/cadvisor/info/v1"
|
||||||
|
"github.com/mesos/mesos-go/api/v1/lib"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PopulateContainer() *mContainer {
|
||||||
|
var pid uint32 = 123
|
||||||
|
cntr := &mContainer{
|
||||||
|
ContainerStatus: &mesos.ContainerStatus{ExecutorPID: &pid},
|
||||||
|
}
|
||||||
|
return cntr
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestContainerReference(t *testing.T) {
|
||||||
|
as := assert.New(t)
|
||||||
|
type testCase struct {
|
||||||
|
client mesosAgentClient
|
||||||
|
name string
|
||||||
|
machineInfoFactory info.MachineInfoFactory
|
||||||
|
fsInfo fs.FsInfo
|
||||||
|
cgroupSubsystems *containerlibcontainer.CgroupSubsystems
|
||||||
|
inHostNamespace bool
|
||||||
|
ignoreMetrics container.MetricSet
|
||||||
|
|
||||||
|
hasErr bool
|
||||||
|
errContains string
|
||||||
|
checkReference *info.ContainerReference
|
||||||
|
}
|
||||||
|
for _, ts := range []testCase{
|
||||||
|
{
|
||||||
|
fakeMesosAgentClient(nil, fmt.Errorf("no client returned")),
|
||||||
|
"/mesos/04e20821-67d3-4bf7-96b4-7d4495f50b28",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
&containerlibcontainer.CgroupSubsystems{},
|
||||||
|
false,
|
||||||
|
nil,
|
||||||
|
|
||||||
|
true,
|
||||||
|
"no client returned",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fakeMesosAgentClient(nil, nil),
|
||||||
|
"/mesos/04e20821-67d3-4bf7-96b4-7d4495f50b28",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
&containerlibcontainer.CgroupSubsystems{},
|
||||||
|
false,
|
||||||
|
nil,
|
||||||
|
|
||||||
|
true,
|
||||||
|
"can't locate container 04e20821-67d3-4bf7-96b4-7d4495f50b28",
|
||||||
|
nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
fakeMesosAgentClient(map[string]*containerInfo{"04e20821-67d3-4bf7-96b4-7d4495f50b28": {cntr: PopulateContainer()}}, nil),
|
||||||
|
"/mesos/04e20821-67d3-4bf7-96b4-7d4495f50b28",
|
||||||
|
nil,
|
||||||
|
nil,
|
||||||
|
&containerlibcontainer.CgroupSubsystems{},
|
||||||
|
false,
|
||||||
|
nil,
|
||||||
|
|
||||||
|
false,
|
||||||
|
"",
|
||||||
|
&info.ContainerReference{
|
||||||
|
Id: "04e20821-67d3-4bf7-96b4-7d4495f50b28",
|
||||||
|
Name: "/mesos/04e20821-67d3-4bf7-96b4-7d4495f50b28",
|
||||||
|
Aliases: []string{"04e20821-67d3-4bf7-96b4-7d4495f50b28", "/mesos/04e20821-67d3-4bf7-96b4-7d4495f50b28"},
|
||||||
|
Namespace: MesosNamespace,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
handler, err := newMesosContainerHandler(ts.name, ts.cgroupSubsystems, ts.machineInfoFactory, ts.fsInfo, ts.ignoreMetrics, ts.inHostNamespace, ts.client)
|
||||||
|
if ts.hasErr {
|
||||||
|
as.NotNil(err)
|
||||||
|
if ts.errContains != "" {
|
||||||
|
as.Contains(err.Error(), ts.errContains)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ts.checkReference != nil {
|
||||||
|
cr, err := handler.ContainerReference()
|
||||||
|
as.Nil(err)
|
||||||
|
as.Equal(*ts.checkReference, cr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
122
container/mesos/mesos_agent.go
Normal file
122
container/mesos/mesos_agent.go
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
// Copyright 2018 Google Inc. 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 mesos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/mesos/mesos-go/api/v1/lib"
|
||||||
|
"github.com/mesos/mesos-go/api/v1/lib/agent"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
cpus = "cpus"
|
||||||
|
schedulerSLA = "scheduler_sla"
|
||||||
|
framework = "framework"
|
||||||
|
source = "source"
|
||||||
|
revocable = "revocable"
|
||||||
|
nonRevocable = "non_revocable"
|
||||||
|
)
|
||||||
|
|
||||||
|
type mContainers *agent.Response_GetContainers
|
||||||
|
type mContainer = agent.Response_GetContainers_Container
|
||||||
|
|
||||||
|
type (
|
||||||
|
state struct {
|
||||||
|
st *agent.Response_GetState
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetFramework finds a framework with the given id and returns nil if not found. Note that
|
||||||
|
// this is different from the framework name.
|
||||||
|
func (s *state) GetFramework(id string) (*mesos.FrameworkInfo, error) {
|
||||||
|
for _, fw := range s.st.GetFrameworks.Frameworks {
|
||||||
|
if fw.FrameworkInfo.ID.Value == id {
|
||||||
|
return &fw.FrameworkInfo, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unable to find framework id %s", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetExecutor finds an executor with the given ID and returns nil if not found. Note that
|
||||||
|
// this is different from the executor name.
|
||||||
|
func (s *state) GetExecutor(id string) (*mesos.ExecutorInfo, error) {
|
||||||
|
for _, exec := range s.st.GetExecutors.Executors {
|
||||||
|
if exec.ExecutorInfo.ExecutorID.Value == id {
|
||||||
|
return &exec.ExecutorInfo, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unable to find executor with id %s", id)
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetTask returns a task launched by given executor.
|
||||||
|
func (s *state) GetTask(exID string) (*mesos.Task, error) {
|
||||||
|
for _, t := range s.st.GetTasks.LaunchedTasks {
|
||||||
|
if t.ExecutorID.Value == exID {
|
||||||
|
return &t, nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("unable to find task matching executor id %s", exID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state) fetchLabelsFromTask(exID string, labels map[string]string) error {
|
||||||
|
t, err := s.GetTask(exID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Identify revocability. Can be removed once we have a proper label
|
||||||
|
for _, resource := range t.Resources {
|
||||||
|
if resource.Name == cpus {
|
||||||
|
if resource.Revocable != nil {
|
||||||
|
labels[schedulerSLA] = revocable
|
||||||
|
} else {
|
||||||
|
labels[schedulerSLA] = nonRevocable
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, l := range t.Labels.Labels {
|
||||||
|
labels[l.Key] = *l.Value
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *state) FetchLabels(fwID string, exID string) (map[string]string, error) {
|
||||||
|
labels := make(map[string]string)
|
||||||
|
|
||||||
|
// Look for the framework which launched the container.
|
||||||
|
fw, err := s.GetFramework(fwID)
|
||||||
|
if err != nil {
|
||||||
|
return labels, fmt.Errorf("framework ID %q not found: %v", fwID, err)
|
||||||
|
}
|
||||||
|
labels[framework] = fw.Name
|
||||||
|
|
||||||
|
// Get the executor info of the container which contains all the task info.
|
||||||
|
exec, err := s.GetExecutor(exID)
|
||||||
|
if err != nil {
|
||||||
|
return labels, fmt.Errorf("executor ID %q not found: %v", exID, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
labels[source] = *exec.Source
|
||||||
|
|
||||||
|
err = s.fetchLabelsFromTask(exID, labels)
|
||||||
|
if err != nil {
|
||||||
|
return labels, fmt.Errorf("failed to fetch labels from task with executor ID %s", exID)
|
||||||
|
}
|
||||||
|
|
||||||
|
return labels, nil
|
||||||
|
}
|
129
container/mesos/mesos_agent_test.go
Normal file
129
container/mesos/mesos_agent_test.go
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
// Copyright 2018 Google Inc. 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 mesos
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"github.com/mesos/mesos-go/api/v1/lib"
|
||||||
|
"github.com/mesos/mesos-go/api/v1/lib/agent"
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func PopulateFrameworks(fwID string) *agent.Response_GetFrameworks {
|
||||||
|
fws := &agent.Response_GetFrameworks{}
|
||||||
|
fws.Frameworks = make([]agent.Response_GetFrameworks_Framework, 1)
|
||||||
|
fw := &agent.Response_GetFrameworks_Framework{}
|
||||||
|
fw.FrameworkInfo = mesos.FrameworkInfo{
|
||||||
|
ID: &mesos.FrameworkID{Value: fwID},
|
||||||
|
Name: "TestFramework",
|
||||||
|
}
|
||||||
|
fws.Frameworks[0] = *fw
|
||||||
|
return fws
|
||||||
|
}
|
||||||
|
|
||||||
|
func PopulateExecutors(exID string) *agent.Response_GetExecutors {
|
||||||
|
execs := &agent.Response_GetExecutors{}
|
||||||
|
execs.Executors = make([]agent.Response_GetExecutors_Executor, 1)
|
||||||
|
exec := &agent.Response_GetExecutors_Executor{}
|
||||||
|
source := "source1"
|
||||||
|
exec.ExecutorInfo = mesos.ExecutorInfo{
|
||||||
|
ExecutorID: mesos.ExecutorID{Value: exID},
|
||||||
|
Source: &source,
|
||||||
|
}
|
||||||
|
execs.Executors[0] = *exec
|
||||||
|
return execs
|
||||||
|
}
|
||||||
|
|
||||||
|
func PopulateTasks() *agent.Response_GetTasks {
|
||||||
|
tasks := &agent.Response_GetTasks{}
|
||||||
|
tasks.LaunchedTasks = make([]mesos.Task, 1)
|
||||||
|
|
||||||
|
task := mesos.Task{
|
||||||
|
ExecutorID: &mesos.ExecutorID{Value: "exec-id1"},
|
||||||
|
}
|
||||||
|
|
||||||
|
task.Resources = make([]mesos.Resource, 1)
|
||||||
|
resource := mesos.Resource{
|
||||||
|
Name: cpus,
|
||||||
|
Revocable: nil,
|
||||||
|
}
|
||||||
|
task.Resources[0] = resource
|
||||||
|
|
||||||
|
task.Labels = &mesos.Labels{
|
||||||
|
Labels: make([]mesos.Label, 1),
|
||||||
|
}
|
||||||
|
labelValue := "value1"
|
||||||
|
label := mesos.Label{
|
||||||
|
Key: "key1",
|
||||||
|
Value: &labelValue,
|
||||||
|
}
|
||||||
|
task.Labels.Labels[0] = label
|
||||||
|
|
||||||
|
tasks.LaunchedTasks[0] = task
|
||||||
|
return tasks
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestFetchLabels(t *testing.T) {
|
||||||
|
type testCase struct {
|
||||||
|
frameworkID string
|
||||||
|
executorID string
|
||||||
|
agentState *agent.Response_GetState
|
||||||
|
expectedError error
|
||||||
|
expectedLabels map[string]string
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, ts := range []testCase{
|
||||||
|
{
|
||||||
|
frameworkID: "fw-id1",
|
||||||
|
executorID: "exec-id1",
|
||||||
|
agentState: &agent.Response_GetState{
|
||||||
|
GetFrameworks: PopulateFrameworks("fw-id1"),
|
||||||
|
GetExecutors: PopulateExecutors("exec-id1"),
|
||||||
|
GetTasks: PopulateTasks(),
|
||||||
|
},
|
||||||
|
expectedError: nil,
|
||||||
|
expectedLabels: map[string]string{
|
||||||
|
framework: "TestFramework",
|
||||||
|
source: "source1",
|
||||||
|
schedulerSLA: nonRevocable,
|
||||||
|
"key1": "value1",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
frameworkID: "fw-id2",
|
||||||
|
executorID: "exec-id1",
|
||||||
|
agentState: &agent.Response_GetState{
|
||||||
|
GetFrameworks: PopulateFrameworks("fw-id1"),
|
||||||
|
GetExecutors: PopulateExecutors("exec-id1"),
|
||||||
|
GetTasks: PopulateTasks(),
|
||||||
|
},
|
||||||
|
expectedError: fmt.Errorf("framework ID \"fw-id2\" not found: unable to find framework id fw-id2"),
|
||||||
|
expectedLabels: map[string]string{},
|
||||||
|
},
|
||||||
|
} {
|
||||||
|
|
||||||
|
var s state
|
||||||
|
s.st = ts.agentState
|
||||||
|
|
||||||
|
actualLabels, err := s.FetchLabels(ts.frameworkID, ts.executorID)
|
||||||
|
if ts.expectedError == nil {
|
||||||
|
assert.Nil(t, err)
|
||||||
|
} else {
|
||||||
|
assert.Equal(t, ts.expectedError.Error(), err.Error())
|
||||||
|
}
|
||||||
|
assert.Equal(t, ts.expectedLabels, actualLabels)
|
||||||
|
}
|
||||||
|
}
|
@ -33,6 +33,7 @@ import (
|
|||||||
"github.com/google/cadvisor/container/containerd"
|
"github.com/google/cadvisor/container/containerd"
|
||||||
"github.com/google/cadvisor/container/crio"
|
"github.com/google/cadvisor/container/crio"
|
||||||
"github.com/google/cadvisor/container/docker"
|
"github.com/google/cadvisor/container/docker"
|
||||||
|
"github.com/google/cadvisor/container/mesos"
|
||||||
"github.com/google/cadvisor/container/raw"
|
"github.com/google/cadvisor/container/raw"
|
||||||
"github.com/google/cadvisor/container/rkt"
|
"github.com/google/cadvisor/container/rkt"
|
||||||
"github.com/google/cadvisor/container/systemd"
|
"github.com/google/cadvisor/container/systemd"
|
||||||
@ -321,6 +322,11 @@ func (self *manager) Start() error {
|
|||||||
glog.V(5).Infof("Registration of the crio container factory failed: %v", err)
|
glog.V(5).Infof("Registration of the crio container factory failed: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
err = mesos.Register(self, self.fsInfo, self.ignoreMetrics)
|
||||||
|
if err != nil {
|
||||||
|
glog.V(5).Infof("Registration of the mesos container factory failed: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
err = systemd.Register(self, self.fsInfo, self.ignoreMetrics)
|
err = systemd.Register(self, self.fsInfo, self.ignoreMetrics)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
glog.V(5).Infof("Registration of the systemd container factory failed: %v", err)
|
glog.V(5).Infof("Registration of the systemd container factory failed: %v", err)
|
||||||
|
Loading…
Reference in New Issue
Block a user