Skip to content
This repository has been archived by the owner on Jul 19, 2018. It is now read-only.

Commit

Permalink
Merge pull request #58 from puppetlabs/DI-489/master/add-container-ca…
Browse files Browse the repository at this point in the history
…pability

(DI-489) Add basic container info capability
  • Loading branch information
jfryman authored Sep 21, 2017
2 parents cf03612 + 8f92f04 commit a354a5a
Show file tree
Hide file tree
Showing 6 changed files with 120 additions and 5 deletions.
101 changes: 101 additions & 0 deletions capabilities/container/container.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package container

import (
"context"
"fmt"
"strings"

"github.com/puppetlabs/lumogon/capabilities/payloadfilter"
"github.com/puppetlabs/lumogon/capabilities/registry"
"github.com/puppetlabs/lumogon/dockeradapter"
"github.com/puppetlabs/lumogon/logging"
"github.com/puppetlabs/lumogon/types"
)

var containerDescription = `The 'container' capability captures detailed container information`

var containerCapability = dockeradapter.DockerAPICapability{
Capability: types.Capability{
Schema: "http://puppet.com/lumogon/capability/container/draft-01/schema#1",
Title: "Container Information",
Name: "container",
Description: containerDescription,
Type: "dockerapi",
Payload: nil,
SupportedOS: map[string]int{"all": 1},
},
Harvest: func(capability *dockeradapter.DockerAPICapability, client dockeradapter.Harvester, id string, target types.TargetContainer) {
logging.Debug("[Container Info] Harvesting container information associated with %s [%s]\n", target.Name, target.ID)
capability.HarvestID = id

containerInfo, err := InspectContainer(client, target.ID)
if err != nil {
capability.PayloadError(err.Error())
return
}

filtered, _ := payloadfilter.Filter(containerInfo)

capability.Payload = filtered
},
}

// InspectContainer Extracts and returns a formatted map[string]interface{} containing
// a subset of information returned by ContainerInspect
func InspectContainer(client dockeradapter.Harvester, targetID string) (map[string]interface{}, error) {
ctx := context.Background()
c, err := client.ContainerInspect(ctx, targetID)
if err != nil {
return nil, err
}

// TODO - **IMPORTANT** this contains only a subset of the information available
// it explicitly avoids including any structured data (ports/mappings etc) pending
// support in the UI, it also avoids any config that could potentially contain
// sensitive data.

result := map[string]interface{}{
"hostname": c.Config.Hostname,
"domainname": c.Config.Domainname,
"user": c.Config.User,
"image": c.Config.Image,
"attachstdin": fmt.Sprintf("%t", c.Config.AttachStdin),
"attachstdout": fmt.Sprintf("%t", c.Config.AttachStdout),
"attachstderr": fmt.Sprintf("%t", c.Config.AttachStderr),
"tty": fmt.Sprintf("%t", c.Config.Tty),
"openstdin": fmt.Sprintf("%t", c.Config.OpenStdin),
"stdinonce": fmt.Sprintf("%t", c.Config.StdinOnce),
"privileged": fmt.Sprintf("%t", c.HostConfig.Privileged),
"publishallports": fmt.Sprintf("%t", c.HostConfig.PublishAllPorts),
"readonlyrootfs": fmt.Sprintf("%t", c.HostConfig.ReadonlyRootfs),
"shmsize": c.HostConfig.ShmSize,
"capadd": strings.Join(c.HostConfig.CapAdd, ", "),
"capdrop": strings.Join(c.HostConfig.CapDrop, ", "),
"runtime": c.HostConfig.Runtime,
"cpushares": c.HostConfig.Resources.CPUShares,
"memory": c.HostConfig.Resources.Memory,
"nanocpus": c.HostConfig.Resources.NanoCPUs,
"cpuperiod": c.HostConfig.Resources.CPUPeriod,
"cpuquota": c.HostConfig.Resources.CPUQuota,
"cpurealtimeperiod": c.HostConfig.Resources.CPURealtimePeriod,
"cpurealtimeruntime": c.HostConfig.Resources.CPURealtimeRuntime,
"cpusetcpus": c.HostConfig.Resources.CpusetCpus,
"cpusetmems": c.HostConfig.Resources.CpusetMems,
"diskquota": c.HostConfig.Resources.DiskQuota,
"kernelmemory": c.HostConfig.Resources.KernelMemory,
"memoryreservation": c.HostConfig.Resources.MemoryReservation,
"memoryswap": c.HostConfig.Resources.MemorySwap,
"memoryswappiness": *c.HostConfig.Resources.MemorySwappiness,
"oomkilldisable": fmt.Sprintf("%t", *c.HostConfig.Resources.OomKillDisable),
"pidslimit": c.HostConfig.Resources.PidsLimit,
}

logging.Debug("[Container Info] Harvested [%+v]\n", result)

return result, nil
}

func init() {
logging.Debug("[Container Info] Initialising capability: %s\n", containerCapability.Title)
registry.Registry.Add(containerCapability)
}
7 changes: 7 additions & 0 deletions capabilities/container/init.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package container

// Init exists to allow container init() functions to run when
// invoked from the capabilities Init function, which is
// itself invoked by the Lumogon command handler.
func Init() {
}
2 changes: 1 addition & 1 deletion capabilities/docker/docker.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ var dockerDescription = `The 'docker' capability captures information related to

var dockerCapability = dockeradapter.DockerAPICapability{
Capability: types.Capability{
Schema: "http://puppet.com/lumogon/capability/label/draft-01/schema#1",
Schema: "http://puppet.com/lumogon/capability/docker/draft-01/schema#1",
Title: "Docker Server Information",
Name: "docker",
Description: dockerDescription,
Expand Down
2 changes: 2 additions & 0 deletions capabilities/init.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package capabilities

import (
"github.com/puppetlabs/lumogon/capabilities/container"
"github.com/puppetlabs/lumogon/capabilities/diff"
"github.com/puppetlabs/lumogon/capabilities/docker"
"github.com/puppetlabs/lumogon/capabilities/host"
Expand All @@ -16,4 +17,5 @@ func Init() {
label.Init()
ospackages.Init()
diff.Init()
container.Init()
}
3 changes: 2 additions & 1 deletion capabilities/payloadfilter/filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@ func filterMap(value map[string]interface{}) (map[string]interface{}, error) {
if coerced != "" {
result[key] = coerced
}

case int, int8, int16, int32, int64:
result[key] = coerced
case map[string]interface{}:
nested, err := filterMap(coerced)
if err != nil {
Expand Down
10 changes: 7 additions & 3 deletions capabilities/payloadfilter/filter_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,19 @@ var filterTests = []filterTest{
false,
},
{
"A map with simple non-string values should fail with an error",
"Native JSON ints should be passed through unchanged",
map[string]interface{}{
"a": 1,
"b": 2,
"c": "3",
"d": "4",
},
map[string]interface{}{},
true,
map[string]interface{}{
"a": 1,
"b": 2,
"c": "3",
"d": "4"},
false,
},
{
"A map with complex non-string values should fail with an error",
Expand Down

0 comments on commit a354a5a

Please sign in to comment.