Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor podman #10421

Merged
merged 24 commits into from
Jul 8, 2022
Merged
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e8628fd
feat: move podman client to libpod client
rogercoll May 25, 2022
9dfa0e9
feat: add new container scraper entity
rogercoll May 25, 2022
8cc29c6
feat: add new methods to client
rogercoll May 25, 2022
bb6ceef
feat: new logic to container scraper
rogercoll May 25, 2022
0179ecd
feat: fetch stats per container
rogercoll May 28, 2022
02dce97
feat: add list container test
rogercoll May 28, 2022
8a18a8f
feat: add test case for image attribute
rogercoll May 29, 2022
5c6db0d
feat: update CHANGELOG.md
rogercoll May 29, 2022
b6e1917
fix: linter error
rogercoll May 29, 2022
f54bab0
fix: cross-compile windows tags
rogercoll May 29, 2022
1da7180
Merge branch 'main' into refactor_podman
Jun 3, 2022
52d22e0
Update receiver/podmanreceiver/podman.go
rogercoll Jun 14, 2022
37c5df1
change variable name for listing containers
rogercoll Jun 14, 2022
429a57b
feat: add test for events function
rogercoll Jun 19, 2022
39b3784
feat: use unexported fields
rogercoll Jun 27, 2022
b392e40
Merge branch 'main' into refactor_podman
rogercoll Jun 27, 2022
d717f9d
fix: changelog version entry
rogercoll Jun 27, 2022
d05345c
Merge branch 'main' into refactor_podman
rogercoll Jun 27, 2022
86aff87
Merge branch 'main' into refactor_podman
rogercoll Jul 5, 2022
b2e33b5
add unreleased file
rogercoll Jul 5, 2022
378a494
fix lint errors
rogercoll Jul 5, 2022
62201fc
remove redundant line break
dmitryax Jul 5, 2022
8b76ff8
fix linter issue with go.mod file
rogercoll Jul 8, 2022
7e939c9
Merge branch 'main' into refactor_podman
rogercoll Jul 8, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
- `prometheusreceiver`: Add `target_info` labels to resource attributes. (#11034)
- `saphanareceiver`: Fix component memory query, add better error handling (#11507)
- `sapmexporter`: Add config option to log responses from Splunk APM. (#11425)
- `podmanreceiver`: Fetch containers stats one by one and add container image as metric attribute (#10421)

### 🧰 Bug fixes 🧰

Expand Down
3 changes: 2 additions & 1 deletion receiver/podmanreceiver/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module github.com/open-telemetry/opentelemetry-collector-contrib/receiver/podman
go 1.17

require (

go.uber.org/multierr v1.8.0
dmitryax marked this conversation as resolved.
Show resolved Hide resolved
github.com/stretchr/testify v1.7.5
go.opentelemetry.io/collector v0.54.0
go.opentelemetry.io/collector/pdata v0.54.0
Expand Down Expand Up @@ -32,7 +34,6 @@ require (
go.opentelemetry.io/otel/metric v0.30.0 // indirect
go.opentelemetry.io/otel/trace v1.7.0 // indirect
go.uber.org/atomic v1.9.0 // indirect
go.uber.org/multierr v1.8.0 // indirect
golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad // indirect
golang.org/x/text v0.3.7 // indirect
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"io/ioutil"
"net/http"
"net/url"
"time"

"go.uber.org/zap"
)
Expand All @@ -34,68 +33,24 @@ var (
errNoStatsFound = fmt.Errorf("No stats found")
)

type containerStats struct {
AvgCPU float64
ContainerID string
Name string
PerCPU []uint64
CPU float64
CPUNano uint64
CPUSystemNano uint64
DataPoints int64
SystemNano uint64
MemUsage uint64
MemLimit uint64
MemPerc float64
NetInput uint64
NetOutput uint64
BlockInput uint64
BlockOutput uint64
PIDs uint64
UpTime time.Duration
Duration uint64
}

type containerStatsReportError struct {
Cause string
Message string
Response int64
}

type containerStatsReport struct {
Error containerStatsReportError
Stats []containerStats
}

type clientFactory func(logger *zap.Logger, cfg *Config) (client, error)

type client interface {
ping(context.Context) error
stats(context.Context) ([]containerStats, error)
}

type podmanClient struct {
type libpodClient struct {
conn *http.Client
endpoint string

// The maximum amount of time to wait for Podman API responses
timeout time.Duration
}

func newPodmanClient(logger *zap.Logger, cfg *Config) (client, error) {
func newLibpodClient(logger *zap.Logger, cfg *Config) (PodmanClient, error) {
connection, err := newPodmanConnection(logger, cfg.Endpoint, cfg.SSHKey, cfg.SSHPassphrase)
if err != nil {
return nil, err
}
c := &podmanClient{
c := &libpodClient{
conn: connection,
endpoint: fmt.Sprintf("http://d/v%s/libpod", cfg.APIVersion),
timeout: cfg.Timeout,
}
return c, nil
}

func (c *podmanClient) request(ctx context.Context, path string, params url.Values) (*http.Response, error) {
func (c *libpodClient) request(ctx context.Context, path string, params url.Values) (*http.Response, error) {
req, err := http.NewRequestWithContext(ctx, "GET", c.endpoint+path, nil)
if err != nil {
return nil, err
Expand All @@ -107,13 +62,8 @@ func (c *podmanClient) request(ctx context.Context, path string, params url.Valu
return c.conn.Do(req)
}

func (c *podmanClient) stats(ctx context.Context) ([]containerStats, error) {
params := url.Values{}
params.Add("stream", "false")

statsCtx, cancel := context.WithTimeout(ctx, c.timeout)
defer cancel()
resp, err := c.request(statsCtx, "/containers/stats", params)
func (c *libpodClient) stats(ctx context.Context, options url.Values) ([]containerStats, error) {
resp, err := c.request(ctx, "/containers/stats", options)
if err != nil {
return nil, err
}
Expand All @@ -138,10 +88,28 @@ func (c *podmanClient) stats(ctx context.Context) ([]containerStats, error) {
return report.Stats, nil
}

func (c *podmanClient) ping(ctx context.Context) error {
pingCtx, cancel := context.WithTimeout(ctx, c.timeout)
defer cancel()
resp, err := c.request(pingCtx, "/_ping", nil)
func (c *libpodClient) list(ctx context.Context, options url.Values) ([]container, error) {
resp, err := c.request(ctx, "/containers/json", options)
if err != nil {
return nil, err
}
defer resp.Body.Close()

bytes, err := ioutil.ReadAll(resp.Body)
if err != nil {
return nil, err
}

var report []container
err = json.Unmarshal(bytes, &report)
if err != nil {
return nil, err
}
return report, nil
}

func (c *libpodClient) ping(ctx context.Context) error {
resp, err := c.request(ctx, "/_ping", nil)
if err != nil {
return err
}
Expand All @@ -151,3 +119,50 @@ func (c *podmanClient) ping(ctx context.Context) error {
}
return nil
}

// events returns a stream of events. It's up to the caller to close the stream by canceling the context.
func (c *libpodClient) events(ctx context.Context, options url.Values) (<-chan event, <-chan error) {
events := make(chan event)
errs := make(chan error, 1)

started := make(chan struct{})
go func() {
defer close(errs)

resp, err := c.request(ctx, "/events", options)
if err != nil {
close(started)
errs <- err
return
}
defer resp.Body.Close()

dec := json.NewDecoder(resp.Body)
close(started)
for {
var e event
select {
case <-ctx.Done():
errs <- ctx.Err()
return
default:
err := dec.Decode(&e)
TylerHelmuth marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
errs <- err
return
}

select {
case events <- e:
case <-ctx.Done():
errs <- ctx.Err()
return
}
}
}
}()

<-started

return events, errs
}
Loading