Skip to content

Commit

Permalink
Address code review comments
Browse files Browse the repository at this point in the history
Also improve StoneWork service management
IP address detection for swctl

Signed-off-by: Peter Motičák <[email protected]>
  • Loading branch information
pemoticak committed Jul 20, 2023
1 parent e7133c3 commit e6b0b8e
Show file tree
Hide file tree
Showing 3 changed files with 179 additions and 141 deletions.
84 changes: 56 additions & 28 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ import (
"time"

docker "github.com/fsouza/go-dockerclient"
"github.com/sirupsen/logrus"
vppagent "go.ligato.io/vpp-agent/v3/cmd/agentctl/client"
"go.ligato.io/vpp-agent/v3/cmd/agentctl/client/tlsconfig"

"go.pantheon.tech/stonework/plugins/cnfreg"
)

const (
DefaultHost = "127.0.0.1"
FallbackHost = "127.0.0.1"
DefaultHTTPClientTimeout = 60 * time.Second
DefaultPortHTTP = 9191
DockerComposeServiceLabel = "com.docker.compose.service"
Expand All @@ -42,13 +43,6 @@ const (
// Option is a function that customizes a Client.
type Option func(*Client) error

func WithHost(h string) Option {
return func(c *Client) error {
c.host = h
return nil
}
}

func WithHTTPPort(p uint16) Option {
return func(c *Client) error {
c.httpPort = p
Expand Down Expand Up @@ -86,21 +80,51 @@ type Client struct {
// customized by options.
func NewClient(opts ...Option) (*Client, error) {
c := &Client{
host: DefaultHost,
scheme: "http",
protocol: "tcp",
httpPort: DefaultPortHTTP,
}
var err error

c.dockerClient, err = docker.NewClientFromEnv()
if err != nil {
return nil, err
}

containers, err := c.dockerClient.ListContainers(docker.ListContainersOptions{})
if err != nil {
return nil, err
}

// find IP address of the StoneWork service
for _, container := range containers {
if container.Labels[DockerComposeServiceLabel] != "stonework" {
continue
}
cont, err := c.dockerClient.InspectContainerWithOptions(docker.InspectContainerOptions{ID: container.ID})
if err != nil {
return nil, err
}
for _, nw := range cont.NetworkSettings.Networks {
if nw.IPAddress != "" {
c.host = nw.IPAddress
break
}
}
break
}

for _, o := range opts {
if err = o(c); err != nil {
return nil, err
}
}
if c.host == "" {
logrus.Warnf("could not find StoneWork service management IP address falling back to: %s", FallbackHost)
c.host = FallbackHost
} else {
logrus.Debugf("found StoneWork service management IP address: %s", c.host)
}

return c, nil
}
Expand Down Expand Up @@ -178,36 +202,40 @@ func (c *Client) GetComponents() ([]Component, error) {
}

var components []Component
var foreignContainers []*docker.Container
for _, container := range containers {

metadata := make(map[string]string)
metadata["containerID"] = container.ID
metadata["containerName"] = container.Name
metadata["containerIPAddress"] = container.NetworkSettings.IPAddress
metadata["containerServiceName"] = container.Config.Labels[DockerComposeServiceLabel]
metadata["dockerImage"] = container.Config.Image

logrus.Tracef("found metadata for container: %s, data: %+v", container.Name, metadata)

compo := &component{Metadata: metadata}
after, found := containsPrefix(container.Config.Env, "MICROSERVICE_LABEL=")
if !found {
foreignContainers = append(foreignContainers, container)
compo.Name = container.Config.Labels[DockerComposeServiceLabel]
compo.Mode = ComponentAuxiliary
components = append(components, compo)
continue
}
info, ok := cnfInfos[after]
if !ok {
foreignContainers = append(foreignContainers, container)
continue
if ok {
compo.Name = info.MsLabel
compo.Info = &info
compo.Mode = cnfModeToCompoMode(info.CnfMode)
} else {
compo.Name = container.Config.Labels[DockerComposeServiceLabel]
compo.Mode = ComponentStandalone
}

client, err := vppagent.NewClientWithOpts(vppagent.WithHost(info.IPAddr), vppagent.WithHTTPPort(info.HTTPPort))
if err != nil {
return components, err
}
compo := &component{
agentclient: client,
Name: info.MsLabel,
Mode: cnfModeToCompoMode(info.CnfMode),
Info: &info,
}
components = append(components, compo)
}

for _, fcontainer := range foreignContainers {
compo := &component{
Name: fcontainer.Config.Labels[DockerComposeServiceLabel],
Mode: ComponentForeign,
}
compo.agentclient = client
components = append(components, compo)
}
return components, nil
Expand Down
100 changes: 91 additions & 9 deletions client/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ package client
import (
"context"
"fmt"
"strings"

"go.ligato.io/vpp-agent/v3/cmd/agentctl/api/types"
"go.ligato.io/vpp-agent/v3/cmd/agentctl/client"
Expand All @@ -31,10 +32,15 @@ import (
type ComponentMode int32

const (
// Foreign means the component is not managed by StoneWork
ComponentForeign ComponentMode = iota
ComponentUnknown ComponentMode = iota

// StoneworkModule means the component is a StoneWork module managed by StoneWork
// Auxiliary means the component is not a CNF and is not managed by StoneWork
ComponentAuxiliary

// Standalone means the component is a standalone CNF
ComponentStandalone

// ComponentStonework means the component is a StoneWork module managed by StoneWork
ComponentStoneworkModule

// Stonework means the component is a StoneWork instance
Expand All @@ -48,7 +54,7 @@ type Component interface {
GetMode() ComponentMode
GetInfo() *cnfreg.Info
GetMetadata() map[string]string
SchedulerValues() ([]*kvscheduler.BaseValueStatus, error)
ConfigStatus() (*ConfigCounts, error)
}

type component struct {
Expand Down Expand Up @@ -79,8 +85,8 @@ func (c *component) GetMetadata() map[string]string {
return c.Metadata
}

func (c *component) SchedulerValues() ([]*kvscheduler.BaseValueStatus, error) {
if c.Mode == ComponentForeign {
func (c *component) ConfigStatus() (*ConfigCounts, error) {
if c.Mode == ComponentAuxiliary || c.Mode == ComponentUnknown {
return nil, fmt.Errorf("cannot get scheduler values of component %s, this component in not managed by StoneWork", c.Name)
}
ctx, cancel := context.WithCancel(context.Background())
Expand All @@ -90,18 +96,94 @@ func (c *component) SchedulerValues() ([]*kvscheduler.BaseValueStatus, error) {
if err != nil {
return nil, err
}
return values, nil

var allVals []*kvscheduler.ValueStatus
for _, baseVal := range values {
allVals = append(allVals, baseVal.Value)
allVals = append(allVals, baseVal.DerivedValues...)
}

var res ConfigCounts
for _, val := range allVals {
switch val.State {
case kvscheduler.ValueState_INVALID, kvscheduler.ValueState_FAILED:
res.Err++
case kvscheduler.ValueState_MISSING:
res.Missing++
case kvscheduler.ValueState_PENDING:
res.Pending++
case kvscheduler.ValueState_RETRYING:
res.Retrying++
case kvscheduler.ValueState_UNIMPLEMENTED:
res.Unimplemented++
case kvscheduler.ValueState_CONFIGURED, kvscheduler.ValueState_DISCOVERED, kvscheduler.ValueState_OBTAINED, kvscheduler.ValueState_REMOVED, kvscheduler.ValueState_NONEXISTENT:
res.Ok++
}
}

return &res, nil
}

type ConfigCounts struct {
Ok int
Err int
Missing int
Pending int
Retrying int
Unimplemented int
}

func (cc ConfigCounts) String() string {
var fields []string
if cc.Ok != 0 {
fields = append(fields, fmt.Sprintf("%d OK", cc.Ok))
}
if cc.Err != 0 {
errStr := fmt.Sprintf("%d errors", cc.Ok)
if cc.Err == 1 {
errStr = errStr[:len(errStr)-1]
}
fields = append(fields, errStr)
}
if cc.Missing != 0 {
fields = append(fields, fmt.Sprintf("%d missing", cc.Missing))
}
if cc.Pending != 0 {
fields = append(fields, fmt.Sprintf("%d pending", cc.Pending))
}
if cc.Retrying != 0 {
fields = append(fields, fmt.Sprintf("%d retrying", cc.Retrying))
}
if cc.Unimplemented != 0 {
fields = append(fields, fmt.Sprintf("%d unimplemented", cc.Unimplemented))
}
return strings.Join(fields, ", ")
}

func (c ComponentMode) String() string {
switch c {
case ComponentAuxiliary:
return "auxiliary"
case ComponentStandalone:
return "standalone CNF"
case ComponentStonework:
return "StoneWork"
case ComponentStoneworkModule:
return "StoneWork module"
default:
return "unknown"
}
}

func cnfModeToCompoMode(cm cnfregpb.CnfMode) ComponentMode {
switch cm {
case cnfregpb.CnfMode_STANDALONE:
return ComponentForeign
return ComponentStandalone
case cnfregpb.CnfMode_STONEWORK_MODULE:
return ComponentStoneworkModule
case cnfregpb.CnfMode_STONEWORK:
return ComponentStonework
default:
return ComponentForeign
return ComponentUnknown
}
}
Loading

0 comments on commit e6b0b8e

Please sign in to comment.