Skip to content

Commit

Permalink
podman handler: Work in progress.
Browse files Browse the repository at this point in the history
Signed-off-by: Paweł Szulik <pawel.szulik@intel.com>
  • Loading branch information
Paweł Szulik committed Jan 11, 2022
1 parent 5cfac3f commit ce6f39a
Show file tree
Hide file tree
Showing 23 changed files with 2,697 additions and 146 deletions.
7 changes: 3 additions & 4 deletions cmd/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,11 @@ require (
github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7
github.com/influxdb/influxdb v0.9.6-0.20151125225445-9eab56311373
github.com/mesos/mesos-go v0.0.7-0.20180413204204-29de6ff97b48
github.com/pquerna/ffjson v0.0.0-20171002144729-d49c2bc1aa13 // indirect
github.com/prometheus/client_golang v1.8.0
github.com/stretchr/testify v1.7.0
golang.org/x/oauth2 v0.0.0-20200902213428-5d25da1a8d43
google.golang.org/api v0.34.0
golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602
google.golang.org/api v0.44.0
gopkg.in/olivere/elastic.v2 v2.0.12
k8s.io/klog/v2 v2.4.0
k8s.io/klog/v2 v2.9.0
k8s.io/utils v0.0.0-20201110183641-67b214c5f920
)
878 changes: 830 additions & 48 deletions cmd/go.sum

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions cmd/internal/container/install/install.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,5 +21,6 @@ import (
_ "github.com/google/cadvisor/container/containerd/install"
_ "github.com/google/cadvisor/container/crio/install"
_ "github.com/google/cadvisor/container/docker/install"
_ "github.com/google/cadvisor/container/podman/install"
_ "github.com/google/cadvisor/container/systemd/install"
)
3 changes: 3 additions & 0 deletions cmd/internal/pages/assets/html/containers.html
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ <h1>{{.DisplayName}}</h1>
<div class="col-sm-12">
<h4><a href="../docker">Docker Containers</a></h4>
</div>
<div class="col-sm-12">
<h4><a href="../podman">Podman Containers</a></h4>
</div>
{{end}}
{{if .Subcontainers}}
<div class="col-sm-12">
Expand Down
6 changes: 3 additions & 3 deletions cmd/internal/pages/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,12 @@ func toStatusKV(status info.DockerStatus) ([]keyVal, []keyVal) {
ds = append(ds, keyVal{Key: k, Value: v})
}
return []keyVal{
{Key: "Docker Version", Value: status.Version},
{Key: "Docker API Version", Value: status.APIVersion},
{Key: "Version", Value: status.Version},
{Key: "API Version", Value: status.APIVersion},
{Key: "Kernel Version", Value: status.KernelVersion},
{Key: "OS Version", Value: status.OS},
{Key: "Host Name", Value: status.Hostname},
{Key: "Docker Root Directory", Value: status.RootDir},
{Key: "Root Directory", Value: status.RootDir},
{Key: "Execution Driver", Value: status.ExecDriver},
{Key: "Number of Images", Value: strconv.Itoa(status.NumImages)},
{Key: "Number of Containers", Value: strconv.Itoa(status.NumContainers)},
Expand Down
8 changes: 8 additions & 0 deletions cmd/internal/pages/pages.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,12 @@ func dockerHandler(containerManager manager.Manager) auth.AuthenticatedHandlerFu
}
}

func podmanHandlerNoAuth(containerManager manager.Manager) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
servePodmanPage(containerManager, w, r.URL)
}
}

// Register http handlers
func RegisterHandlersDigest(mux httpmux.Mux, containerManager manager.Manager, authenticator *auth.DigestAuth, urlBasePrefix string) error {
// Register the handler for the containers page.
Expand Down Expand Up @@ -127,9 +133,11 @@ func RegisterHandlersBasic(mux httpmux.Mux, containerManager manager.Manager, au
if authenticator != nil {
mux.HandleFunc(ContainersPage, authenticator.Wrap(containerHandler(containerManager)))
mux.HandleFunc(DockerPage, authenticator.Wrap(dockerHandler(containerManager)))
// TODO (Creatone): Add Podman.
} else {
mux.HandleFunc(ContainersPage, containerHandlerNoAuth(containerManager))
mux.HandleFunc(DockerPage, dockerHandlerNoAuth(containerManager))
mux.HandleFunc(PodmanPage, podmanHandlerNoAuth(containerManager))
}

if ContainersPage[len(ContainersPage)-1] == '/' {
Expand Down
138 changes: 138 additions & 0 deletions cmd/internal/pages/podman.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
// Copyright 2021 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 pages

import (
"fmt"
"net/http"
"net/url"
"path"
"time"

"github.com/google/cadvisor/container/podman"
info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/manager"

"k8s.io/klog/v2"
)

const PodmanPage = "/podman/"

func servePodmanPage(m manager.Manager, w http.ResponseWriter, u *url.URL) {
start := time.Now()

containerName := u.Path[len(PodmanPage)-1:]
rootDir := getRootDir(containerName)

var data *pageData

if containerName == "/" {
// Scenario for all containers.
reqParams := info.ContainerInfoRequest{
NumStats: 0,
}
conts, err := m.AllPodmanContainers(&reqParams)
if err != nil {
http.Error(w, fmt.Sprintf("failed to get container %q with error: %v", containerName, err), http.StatusNotFound)
return
}
subcontainers := make([]link, 0, len(conts))
for _, cont := range conts {
subcontainers = append(subcontainers, link{
Text: getContainerDisplayName(cont.ContainerReference),
Link: path.Join(rootDir, PodmanPage, podman.ContainerNameToPodmanID(cont.ContainerReference.Name)),
})
}

// Get Podman status
status, err := podman.Status()
if err != nil {
http.Error(w, fmt.Sprintf("failed to get docker info: %v", err), http.StatusInternalServerError)
return
}

podmanStatus, driverStatus := toStatusKV(info.DockerStatus(status))
// Get Podman Images
images, err := podman.Images()
if err != nil {
http.Error(w, fmt.Sprintf("failed to get podman images: %v", err), http.StatusInternalServerError)
return
}

podmanContainerText := "Podman Containers"
data = &pageData{
DisplayName: podmanContainerText,
ParentContainers: []link{
{
Text: podmanContainerText,
Link: path.Join(rootDir, PodmanPage),
}},
Subcontainers: subcontainers,
Root: rootDir,
DockerStatus: podmanStatus,
DockerDriverStatus: driverStatus,
DockerImages: images,
}
} else {
// Scenario for specific container.
reqParams := info.ContainerInfoRequest{
NumStats: 60,
}
cont, err := m.PodmanContainer(containerName[1:], &reqParams)
if err != nil {
http.Error(w, fmt.Sprintf("failed to get container %v with error: %v", containerName, err), http.StatusNotFound)
return
}
displayName := getContainerDisplayName(cont.ContainerReference)

var parentContainers []link
parentContainers = append(parentContainers, link{
Text: "Podman Containers",
Link: path.Join(rootDir, PodmanPage),
})
parentContainers = append(parentContainers, link{
Text: displayName,
Link: path.Join(rootDir, PodmanPage, podman.ContainerNameToPodmanID(cont.Name)),
})

machineInfo, err := m.GetMachineInfo()
if err != nil {
http.Error(w, fmt.Sprintf("failed to get machine info: %v", err), http.StatusInternalServerError)
return
}
data = &pageData{
DisplayName: displayName,
ContainerName: escapeContainerName(cont.Name),
ParentContainers: parentContainers,
Spec: cont.Spec,
Stats: cont.Stats,
MachineInfo: machineInfo,
ResourcesAvailable: cont.Spec.HasCpu || cont.Spec.HasMemory || cont.Spec.HasNetwork,
CpuAvailable: cont.Spec.HasCpu,
MemoryAvailable: cont.Spec.HasMemory,
NetworkAvailable: cont.Spec.HasNetwork,
FsAvailable: cont.Spec.HasFilesystem,
CustomMetricsAvailable: cont.Spec.HasCustomMetrics,
Root: rootDir,
}
}

err := pageTemplate.Execute(w, data)
if err != nil {
klog.Errorf("Failed to apply template: %s", err)
}

klog.V(5).Infof("Request took %s", time.Since(start))
}
6 changes: 3 additions & 3 deletions cmd/internal/pages/templates.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ const (
ContainerTypeCrio
ContainerTypeContainerd
ContainerTypeMesos
ContainerTypePodman
)

// Interface for container operation handlers.
Expand Down
111 changes: 111 additions & 0 deletions container/docker/fs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package docker

import (
"fmt"

"github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/common"
"github.com/google/cadvisor/fs"
info "github.com/google/cadvisor/info/v1"

"k8s.io/klog/v2"
)

func GetFsStats(
stats *info.ContainerStats,
machineInfoFactory info.MachineInfoFactory,
metrics container.MetricSet,
storageDriver storageDriver,
fsHandler common.FsHandler,
globalFsInfo fs.FsInfo,
poolName string,
rootfsStorageDir string,
zfsParent string,
) error {
mi, err := machineInfoFactory.GetMachineInfo()
if err != nil {
return err
}

if metrics.Has(container.DiskIOMetrics) {
common.AssignDeviceNamesToDiskStats((*common.MachineInfoNamer)(mi), &stats.DiskIo)
}

if metrics.Has(container.DiskUsageMetrics) {
var device string
switch storageDriver {
case devicemapperStorageDriver:
device = poolName
case aufsStorageDriver, overlayStorageDriver, overlay2StorageDriver, vfsStorageDriver:
deviceInfo, err := globalFsInfo.GetDirFsDevice(rootfsStorageDir)
if err != nil {
return fmt.Errorf("unable to determine device info for dir: %v: %v", rootfsStorageDir, err)
}
device = deviceInfo.Device
case zfsStorageDriver:
device = zfsParent
default:
return nil
}

var (
limit uint64
fsType string
)

var fsInfo *info.FsInfo

for _, fs := range mi.Filesystems {
if fs.Device == device {
limit = fs.Capacity
fsType = fs.Type
fsInfo = &fs
break
}
}

fsStat := info.FsStats{Device: device, Type: fsType, Limit: limit}
usage := fsHandler.Usage()
fsStat.BaseUsage = usage.BaseUsageBytes
fsStat.Usage = usage.TotalUsageBytes
fsStat.Inodes = usage.InodeUsage

if fsInfo != nil {
fileSystems, err := globalFsInfo.GetGlobalFsInfo()

if err == nil {
addDiskStats(fileSystems, fsInfo, &fsStat)
} else {
klog.Errorf("Unable to obtain diskstats for filesystem %s: %v", fsStat.Device, err)
}
}

stats.Filesystem = append(stats.Filesystem, fsStat)
}

return nil
}

func addDiskStats(fileSystems []fs.Fs, fsInfo *info.FsInfo, fsStats *info.FsStats) {
if fsInfo == nil {
return
}

for _, fileSys := range fileSystems {
if fsInfo.DeviceMajor == fileSys.DiskStats.Major &&
fsInfo.DeviceMinor == fileSys.DiskStats.Minor {
fsStats.ReadsCompleted = fileSys.DiskStats.ReadsCompleted
fsStats.ReadsMerged = fileSys.DiskStats.ReadsMerged
fsStats.SectorsRead = fileSys.DiskStats.SectorsRead
fsStats.ReadTime = fileSys.DiskStats.ReadTime
fsStats.WritesCompleted = fileSys.DiskStats.WritesCompleted
fsStats.WritesMerged = fileSys.DiskStats.WritesMerged
fsStats.SectorsWritten = fileSys.DiskStats.SectorsWritten
fsStats.WriteTime = fileSys.DiskStats.WriteTime
fsStats.IoInProgress = fileSys.DiskStats.IoInProgress
fsStats.IoTime = fileSys.DiskStats.IoTime
fsStats.WeightedIoTime = fileSys.DiskStats.WeightedIoTime
break
}
}
}
30 changes: 4 additions & 26 deletions container/docker/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ import (
"strings"
"time"

"github.com/opencontainers/runc/libcontainer/cgroups"

"github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/common"
dockerutil "github.com/google/cadvisor/container/docker/utils"
Expand All @@ -31,7 +33,6 @@ import (
"github.com/google/cadvisor/fs"
info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/zfs"
"github.com/opencontainers/runc/libcontainer/cgroups"

dockercontainer "github.com/docker/docker/api/types/container"
docker "github.com/docker/docker/client"
Expand Down Expand Up @@ -432,30 +433,6 @@ func (h *dockerContainerHandler) getFsStats(stats *info.ContainerStats) error {
return nil
}

func addDiskStats(fileSystems []fs.Fs, fsInfo *info.FsInfo, fsStats *info.FsStats) {
if fsInfo == nil {
return
}

for _, fileSys := range fileSystems {
if fsInfo.DeviceMajor == fileSys.DiskStats.Major &&
fsInfo.DeviceMinor == fileSys.DiskStats.Minor {
fsStats.ReadsCompleted = fileSys.DiskStats.ReadsCompleted
fsStats.ReadsMerged = fileSys.DiskStats.ReadsMerged
fsStats.SectorsRead = fileSys.DiskStats.SectorsRead
fsStats.ReadTime = fileSys.DiskStats.ReadTime
fsStats.WritesCompleted = fileSys.DiskStats.WritesCompleted
fsStats.WritesMerged = fileSys.DiskStats.WritesMerged
fsStats.SectorsWritten = fileSys.DiskStats.SectorsWritten
fsStats.WriteTime = fileSys.DiskStats.WriteTime
fsStats.IoInProgress = fileSys.DiskStats.IoInProgress
fsStats.IoTime = fileSys.DiskStats.IoTime
fsStats.WeightedIoTime = fileSys.DiskStats.WeightedIoTime
break
}
}
}

// TODO(vmarmol): Get from libcontainer API instead of cgroup manager when we don't have to support older Dockers.
func (h *dockerContainerHandler) GetStats() (*info.ContainerStats, error) {
stats, err := h.libcontainerHandler.GetStats()
Expand All @@ -471,7 +448,8 @@ func (h *dockerContainerHandler) GetStats() (*info.ContainerStats, error) {
}

// Get filesystem stats.
err = h.getFsStats(stats)
err = GetFsStats(stats, h.machineInfoFactory, h.includedMetrics, h.storageDriver,
h.fsHandler, h.fsInfo, h.poolName, h.rootfsStorageDir, h.zfsParent)
if err != nil {
return stats, err
}
Expand Down
Loading

0 comments on commit ce6f39a

Please sign in to comment.