Skip to content

Commit

Permalink
Support push + reset cfg from topology manager grpc service (#183)
Browse files Browse the repository at this point in the history
* Topology manager implement config push rpcs

* fix topo file

* Revert config push tm behavior

* gofmt

* fmt proto

* Refactor topo manager

* Fix topo cmd tests

* Write topo test

* fix issues

* Address review comments

* tests

* Add topo test

* Fix lint

* fix lint

* fix test

* fix topo create

* Address review comments

* Update test
  • Loading branch information
alexmasi authored Aug 15, 2022
1 parent 1e161cb commit 0069183
Show file tree
Hide file tree
Showing 9 changed files with 1,517 additions and 799 deletions.
4 changes: 4 additions & 0 deletions api/clientset/v1beta1/topology.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ func (t *topologyClient) Get(ctx context.Context, name string, opts metav1.GetOp
}

func (t *topologyClient) Create(ctx context.Context, topology *topologyv1.Topology, opts metav1.CreateOptions) (*topologyv1.Topology, error) {
topology.TypeMeta = metav1.TypeMeta{
Kind: "Topology",
APIVersion: "networkop.co.uk/v1beta1",
}
obj, err := runtime.DefaultUnstructuredConverter.ToUnstructured(topology)
if err != nil {
return nil, fmt.Errorf("failed to convert topology to unstructured: %v", err)
Expand Down
2 changes: 1 addition & 1 deletion api/clientset/v1beta1/topology_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -186,7 +186,7 @@ func TestCreate(t *testing.T) {
if tt.wantErr != "" {
return
}
if s := cmp.Diff(got, tt.want, cmpopts.IgnoreFields(topologyv1.Topology{}, "TypeMeta")); s != "" {
if s := cmp.Diff(got, tt.want); s != "" {
t.Fatalf("Create(%+v) failed: %s", tt.want, s)
}
})
Expand Down
41 changes: 23 additions & 18 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ var (
rootCmd = &cobra.Command{
Use: "kne",
Short: "Kubernetes Network Emulation CLI",
Long: `Kubernetes Network Emulation CLI. Works with meshnet to create
Long: `Kubernetes Network Emulation CLI. Works with meshnet to create
layer 2 topology used by containers to layout networks in a k8s
environment.`,
SilenceUsage: true,
Expand Down Expand Up @@ -123,38 +123,43 @@ func createFn(cmd *cobra.Command, args []string) error {
return err
}
log.Infof(bp)
p := topo.TopologyParams{
TopoName: args[0],
Kubecfg: kubecfg,
TopoNewOptions: []topo.Option{topo.WithBasePath(bp)},
Timeout: timeout,
DryRun: dryrun,
}
return topo.CreateTopology(cmd.Context(), p)
topopb, err := topo.Load(args[0])
if err != nil {
return fmt.Errorf("%s: %w", cmd.Use, err)
}
tm, err := topo.New(topopb, topo.WithKubecfg(kubecfg), topo.WithBasePath(bp))
if err != nil {
return fmt.Errorf("%s: %w", cmd.Use, err)
}
if dryrun {
return nil
}
return tm.Create(cmd.Context(), timeout)
}

func deleteFn(cmd *cobra.Command, args []string) error {
p := topo.TopologyParams{
TopoName: args[0],
Kubecfg: kubecfg,
topopb, err := topo.Load(args[0])
if err != nil {
return fmt.Errorf("%s: %w", cmd.Use, err)
}
tm, err := topo.New(topopb, topo.WithKubecfg(kubecfg))
if err != nil {
return fmt.Errorf("%s: %w", cmd.Use, err)
}
return topo.DeleteTopology(cmd.Context(), p)
return tm.Delete(cmd.Context())
}

func showFn(cmd *cobra.Command, args []string) error {
topopb, err := topo.Load(args[0])
if err != nil {
return fmt.Errorf("%s: %w", cmd.Use, err)
}
t, err := topo.New(kubecfg, topopb)
tm, err := topo.New(topopb, topo.WithKubecfg(kubecfg))
if err != nil {
return fmt.Errorf("%s: %w", cmd.Use, err)
}
if err := t.Load(cmd.Context()); err != nil {
return err
}
out := cmd.OutOrStdout()
r, err := t.Resources(cmd.Context())
r, err := tm.Resources(cmd.Context())
if err != nil {
return err
}
Expand Down
125 changes: 58 additions & 67 deletions cmd/topology/topology.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,14 @@ import (
"path/filepath"

"github.com/openconfig/gnmi/errlist"
cpb "github.com/openconfig/kne/proto/controller"
tpb "github.com/openconfig/kne/proto/topo"
"github.com/openconfig/kne/topo"
"github.com/openconfig/kne/topo/node"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/encoding/prototext"
)

Expand Down Expand Up @@ -72,6 +75,7 @@ func New() *cobra.Command {
var (
skipReset bool
pushConfig bool
opts []topo.Option
)

func fileRelative(p string) (string, error) {
Expand All @@ -82,10 +86,6 @@ func fileRelative(p string) (string, error) {
return filepath.Dir(bp), nil
}

var (
opts []topo.Option
)

func resetCfgFn(cmd *cobra.Command, args []string) error {
if len(args) < 1 || len(args) > 2 {
return fmt.Errorf("%s: invalid args", cmd.Use)
Expand All @@ -98,38 +98,31 @@ func resetCfgFn(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
t, err := topo.New(s, topopb, opts...)
tOpts := append(opts, topo.WithKubecfg(s))
tm, err := topo.New(topopb, tOpts...)
if err != nil {
return fmt.Errorf("%s: %w", cmd.Use, err)
}
ctx := cmd.Context()
t.Load(ctx)
nodes := t.Nodes()
nodes := tm.Nodes()
if len(args) > 1 {
n, err := t.Node(args[1])
if err != nil {
return err
}
nodes = []node.Node{n}
nodes = map[string]node.Node{args[1]: nodes[args[1]]}
}
var canReset []node.Node
for _, n := range nodes {
_, ok := n.(node.Resetter)
if !ok {
if skipReset {
continue
}
return fmt.Errorf("node %s is not resettable and --skip not set", n.Name())
}
canReset = append(canReset, n)
}
for _, r := range canReset {
if err := r.(node.Resetter).ResetCfg(ctx); err != nil {
for name := range nodes {
err := tm.ResetCfg(cmd.Context(), name)
switch {
default:
return err
case err == nil:
case status.Code(err) == codes.Unimplemented && !skipReset:
return fmt.Errorf("node %q is not a Resetter and --skip not set", name)
case status.Code(err) == codes.Unimplemented:
log.Infof("Skipping node %q not a Resetter", name)
delete(nodes, name)
continue
}
}
if !pushConfig {
log.Infof("Finished reseting resetable nodes to vendor default configuration")
log.Infof("Finished resetting resettable nodes to vendor default configuration")
return nil
}
log.Infof("Trying to repush devices configs: %q", args[0])
Expand All @@ -138,15 +131,10 @@ func resetCfgFn(cmd *cobra.Command, args []string) error {
return fmt.Errorf("failed to find relative path for topology: %v", err)
}
var errList errlist.List
for _, n := range canReset {
cd := n.GetProto().GetConfig().GetConfigData()
for name, node := range nodes {
cd := node.GetProto().GetConfig().GetConfigData()
if cd == nil {
log.Infof("Skipping node %q no config provided", n.Name())
continue
}
cp, ok := n.(node.ConfigPusher)
if !ok {
log.Infof("Skipping node %q not a ConfigPusher", n.Name())
log.Infof("Skipping node %q no config provided", name)
continue
}
var b []byte
Expand All @@ -158,16 +146,23 @@ func resetCfgFn(cmd *cobra.Command, args []string) error {
if !filepath.IsAbs(cPath) {
cPath = filepath.Join(bp, cPath)
}
log.Infof("Pushing configuration %q to %q", cPath, n.Name())
log.Infof("Pushing configuration %q to %q", cPath, name)
var err error
b, err = os.ReadFile(cPath)
if err != nil {
errList.Add(err)
continue
}
}
if err := cp.ConfigPush(context.Background(), bytes.NewBuffer(b)); err != nil {
err := tm.ConfigPush(cmd.Context(), name, bytes.NewBuffer(b))
switch {
default:
errList.Add(err)
continue
case err == nil:
case status.Code(err) == codes.Unimplemented:
log.Infof("Skipping node %q not a ConfigPusher", name)
continue
}
}
return errList.Err()
Expand All @@ -185,13 +180,12 @@ func pushFn(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
t, err := topo.New(s, topopb, opts...)
tOpts := append(opts, topo.WithKubecfg(s))
tm, err := topo.New(topopb, tOpts...)
if err != nil {
return fmt.Errorf("%s: %w", cmd.Use, err)
}

ctx := cmd.Context()
t.Load(ctx)
fp, err := os.Open(args[2])
if err != nil {
return err
Expand All @@ -201,10 +195,7 @@ func pushFn(cmd *cobra.Command, args []string) error {
log.Warnf("failed to close config file %q", args[2])
}
}()
if err := t.ConfigPush(ctx, args[1], fp); err != nil {
return err
}
return nil
return tm.ConfigPush(cmd.Context(), args[1], fp)
}

func watchFn(cmd *cobra.Command, args []string) error {
Expand All @@ -219,14 +210,12 @@ func watchFn(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
t, err := topo.New(s, topopb)
tOpts := append(opts, topo.WithKubecfg(s))
tm, err := topo.New(topopb, tOpts...)
if err != nil {
return fmt.Errorf("%s: %w", cmd.Use, err)
}
if err := t.Watch(cmd.Context()); err != nil {
return err
}
return nil
return tm.Watch(cmd.Context())
}

func certFn(cmd *cobra.Command, args []string) error {
Expand All @@ -241,38 +230,40 @@ func certFn(cmd *cobra.Command, args []string) error {
if err != nil {
return err
}
t, err := topo.New(s, topopb)
tOpts := append(opts, topo.WithKubecfg(s))
tm, err := topo.New(topopb, tOpts...)
if err != nil {
return fmt.Errorf("%s: %w", cmd.Use, err)
}
t.Load(cmd.Context())
if err != nil {
return fmt.Errorf("%s: %w", cmd.Use, err)
}
n, err := t.Node(args[1])
if err != nil {
return err
}
return topo.GenerateSelfSigned(cmd.Context(), n)
return tm.GenerateSelfSigned(cmd.Context(), args[1])
}

var (
getTopologyServices = topo.GetTopologyServices
)
var newTopologyManager = func(topopb *tpb.Topology, opts ...topo.Option) (TopologyManager, error) {
return topo.New(topopb, opts...)
}

type TopologyManager interface {
Show(ctx context.Context) (*cpb.ShowTopologyResponse, error)
}

func serviceFn(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return fmt.Errorf("%s: missing topology", cmd.Use)
}
kubeCfg, err := cmd.Flags().GetString("kubecfg")
topopb, err := topo.Load(args[0])
if err != nil {
return fmt.Errorf("%s: %w", cmd.Use, err)
}
s, err := cmd.Flags().GetString("kubecfg")
if err != nil {
return err
}
param := topo.TopologyParams{
TopoName: args[0],
Kubecfg: kubeCfg,
tOpts := append(opts, topo.WithKubecfg(s))
tm, err := newTopologyManager(topopb, tOpts...)
if err != nil {
return fmt.Errorf("%s: %w", cmd.Use, err)
}
ts, err := getTopologyServices(cmd.Context(), param)
ts, err := tm.Show(cmd.Context())
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit 0069183

Please sign in to comment.