Skip to content

Commit

Permalink
podman support: Create Podman handler.
Browse files Browse the repository at this point in the history
Signed-off-by: Paweł Szulik <paul.szulik@gmail.com>
  • Loading branch information
Creatone committed Jun 27, 2023
1 parent 1fb7f23 commit fea8256
Show file tree
Hide file tree
Showing 11 changed files with 885 additions and 0 deletions.
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
58 changes: 58 additions & 0 deletions container/podman/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// 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 podman

import (
"context"
"fmt"
"net"
"net/http"
urllib "net/url"
)

type clientKey struct{}

func (c clientKey) String() string {
return "client"
}

type Connection struct {
URI *urllib.URL
Client *http.Client
}

func client(ctx *context.Context) (*Connection, error) {
url, err := urllib.Parse(*endpointFlag)
if err != nil {
return nil, err
}

switch url.Scheme {
case "unix":
connection := Connection{URI: url}
connection.Client = &http.Client{
Transport: &http.Transport{
DialContext: func(ctx context.Context, _, _ string) (net.Conn, error) {
return (&net.Dialer{}).DialContext(ctx, "unix", url.Path)
},
DisableCompression: true,
},
}
*ctx = context.WithValue(*ctx, clientKey{}, &connection)
return &connection, nil
}

return nil, fmt.Errorf("couldn't get podman client")
}
113 changes: 113 additions & 0 deletions container/podman/factory.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
// 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 podman

import (
"flag"
"fmt"
"path"
"sync"
"time"

"github.com/google/cadvisor/container"
"github.com/google/cadvisor/container/docker"
dockerutil "github.com/google/cadvisor/container/docker/utils"
"github.com/google/cadvisor/devicemapper"
"github.com/google/cadvisor/fs"
info "github.com/google/cadvisor/info/v1"
"github.com/google/cadvisor/zfs"
)

const (
rootDirRetries = 5
rootDirRetryPeriod = time.Second
containerBaseName = "container"
)

var (
endpointFlag = flag.String("podman", "unix:///var/run/podman/podman.sock", "podman endpoint")
)

var (
rootDir string
rootDirOnce sync.Once
)

func RootDir() string {
rootDirOnce.Do(func() {
for i := 0; i < rootDirRetries; i++ {
status, err := Status()
if err == nil && status.RootDir != "" {
rootDir = status.RootDir
break
} else {
time.Sleep(rootDirRetryPeriod)
}
}
})
return rootDir
}

type podmanFactory struct {
// Information about the mounted cgroup subsystems.
machineInfoFactory info.MachineInfoFactory

storageDriver docker.StorageDriver
storageDir string

cgroupSubsystem map[string]string

fsInfo fs.FsInfo

metrics container.MetricSet

thinPoolName string
thinPoolWatcher *devicemapper.ThinPoolWatcher

zfsWatcher *zfs.ZfsWatcher
}

func (f *podmanFactory) CanHandleAndAccept(name string) (handle bool, accept bool, err error) {
// Rootless
if path.Base(name) == containerBaseName {
name, _ = path.Split(name)
}
if !dockerutil.IsContainerName(name) {
return false, false, nil
}

id := dockerutil.ContainerNameToId(name)

ctnr, err := InspectContainer(id)
if err != nil || !ctnr.State.Running {
return false, true, fmt.Errorf("error inspecting container: %v", err)
}

return true, true, nil
}

func (f *podmanFactory) DebugInfo() map[string][]string {
return map[string][]string{}
}

func (f *podmanFactory) String() string {
return "podman"
}

func (f *podmanFactory) NewContainerHandler(name string, metadataEnvAllowList []string, inHostNamespace bool) (handler container.ContainerHandler, err error) {
return newPodmanContainerHandler(name, f.machineInfoFactory, f.fsInfo,
f.storageDriver, f.storageDir, f.cgroupSubsystem, inHostNamespace,
metadataEnvAllowList, f.metrics, f.thinPoolName, f.thinPoolWatcher, f.zfsWatcher)
}
54 changes: 54 additions & 0 deletions container/podman/fs.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
// Copyright 2022 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 podman

import (
"encoding/json"
"fmt"
"os"
"path/filepath"

"github.com/google/cadvisor/container/docker"
)

const (
containersJSONFilename = "containers.json"
)

type containersJSON struct {
ID string `json:"id"`
Layer string `json:"layer"`
// rest in unnecessary
}

func rwLayerID(storageDriver docker.StorageDriver, storageDir string, containerID string) (string, error) {
data, err := os.ReadFile(filepath.Join(storageDir, string(storageDriver)+"-containers", containersJSONFilename))
if err != nil {
return "", err
}
var containers []containersJSON
err = json.Unmarshal(data, &containers)
if err != nil {
return "", err
}

for _, c := range containers {
if c.ID == containerID {
return c.Layer, nil
}
}

return "", fmt.Errorf("unable to determine %v rw layer id", containerID)
}
Loading

0 comments on commit fea8256

Please sign in to comment.