Created
July 11, 2019 15:28
-
-
Save bryanl/bd910b247b069d8932200e48464bea49 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
Copyright (c) 2019 VMware, Inc. All Rights Reserved. | |
SPDX-License-Identifier: Apache-2.0 | |
*/ | |
package main | |
import ( | |
"context" | |
"fmt" | |
"log" | |
"sync" | |
"time" | |
"github.com/pkg/errors" | |
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" | |
"k8s.io/apimachinery/pkg/runtime" | |
"k8s.io/apimachinery/pkg/runtime/schema" | |
"github.com/vmware/octant/pkg/action" | |
"github.com/vmware/octant/pkg/plugin" | |
"github.com/vmware/octant/pkg/plugin/api" | |
"github.com/vmware/octant/pkg/store" | |
"github.com/vmware/octant/pkg/view/component" | |
"github.com/vmware/octant/pkg/view/flexlayout" | |
) | |
func main() { | |
podGVK := schema.GroupVersionKind{Version: "v1", Kind: "Pod"} | |
capabilities := plugin.Capabilities{ | |
SupportsPrinterConfig: []schema.GroupVersionKind{podGVK}, | |
SupportsTab: []schema.GroupVersionKind{podGVK}, | |
} | |
tabHandler := HandlePrintTab(handleTab) | |
printHandler := HandlePrint(handlePrint) | |
objectStatusHandler := HandleObjectStatus(handleObjectStatus) | |
p, err := NewPlugin("plugin-name", "a description", capabilities, tabHandler, printHandler, objectStatusHandler) | |
if err != nil { | |
log.Fatal(err) | |
} | |
p.Serve() | |
} | |
func handleTab(dashboardClient Dashboard, object runtime.Object) (*component.Tab, error) { | |
if object == nil { | |
return nil, errors.New("object is nil") | |
} | |
layout := flexlayout.New() | |
section := layout.AddSection() | |
err := section.Add(component.NewText("content from a plugin"), component.WidthHalf) | |
if err != nil { | |
return nil, err | |
} | |
tab := component.Tab{ | |
Name: "PluginStub", | |
Contents: *layout.ToComponent("Plugin"), | |
} | |
return &tab, nil | |
} | |
func handlePrint(dashboardClient Dashboard, object runtime.Object) (plugin.PrintResponse, error) { | |
if object == nil { | |
return plugin.PrintResponse{}, errors.Errorf("object is nil") | |
} | |
ctx := context.Background() | |
key, err := store.KeyFromObject(object) | |
if err != nil { | |
return plugin.PrintResponse{}, err | |
} | |
u, err := dashboardClient.Get(ctx, key) | |
if err != nil { | |
return plugin.PrintResponse{}, err | |
} | |
log.Printf("loaded object from objectstore: %v", u) | |
msg := fmt.Sprintf("update from plugin at %s", time.Now().Format(time.RFC3339)) | |
return plugin.PrintResponse{ | |
Config: []component.SummarySection{ | |
{Header: "from-plugin", Content: component.NewText(msg)}, | |
}, | |
Status: []component.SummarySection{ | |
{Header: "from-plugin", Content: component.NewText(msg)}, | |
}, | |
Items: []component.FlexLayoutItem{ | |
{ | |
Width: component.WidthHalf, | |
View: component.NewText("item 1 from plugin"), | |
}, | |
{ | |
Width: component.WidthFull, | |
View: component.NewText("item 2 from plugin"), | |
}, | |
}, | |
}, nil | |
} | |
func handleObjectStatus(dashboardClient Dashboard, object runtime.Object) (plugin.ObjectStatusResponse, error) { | |
if object == nil { | |
return plugin.ObjectStatusResponse{}, errors.New("object is nil") | |
} | |
status := component.PodSummary{ | |
Status: component.NodeStatusError, | |
Details: []component.Component{component.NewText(fmt.Sprintf("Timestamp: %s", time.Now().Format(time.RFC850)))}, | |
} | |
return plugin.ObjectStatusResponse{ | |
ObjectStatus: status, | |
}, nil | |
} | |
type PluginOption func(p *Plugin) error | |
type HandleActionFunc func(dashboardClient Dashboard, payload action.Payload) error | |
func HandleAction(fn HandleActionFunc) PluginOption { | |
return func(p *Plugin) error { | |
p.pluginHandler.handleAction = fn | |
return nil | |
} | |
} | |
type HandlePrintFunc func(dashboardClient Dashboard, object runtime.Object) (plugin.PrintResponse, error) | |
func HandlePrint(fn HandlePrintFunc) PluginOption { | |
return func(p *Plugin) error { | |
p.pluginHandler.print = fn | |
return nil | |
} | |
} | |
type HandleObjectStatusFunc func(dashboardClient Dashboard, object runtime.Object) (plugin.ObjectStatusResponse, error) | |
func HandleObjectStatus(fn HandleObjectStatusFunc) PluginOption { | |
return func(p *Plugin) error { | |
p.pluginHandler.objectStatus = fn | |
return nil | |
} | |
} | |
type HandlePrintTabFunc func(dashboardClient Dashboard, object runtime.Object) (*component.Tab, error) | |
func HandlePrintTab(fn HandlePrintTabFunc) PluginOption { | |
return func(p *Plugin) error { | |
p.pluginHandler.printTab = fn | |
return nil | |
} | |
} | |
type Plugin struct { | |
pluginHandler *pluginHandler | |
} | |
func NewPlugin(name, description string, capabilities plugin.Capabilities, options ...PluginOption) (*Plugin, error) { | |
p := &Plugin{ | |
pluginHandler: &pluginHandler{ | |
name: name, | |
description: description, | |
capabilities: capabilities, | |
}, | |
} | |
for _, option := range options { | |
if err := option(p); err != nil { | |
return nil, err | |
} | |
} | |
if err := p.Validate(); err != nil { | |
return nil, err | |
} | |
return p, nil | |
} | |
func (p *Plugin) Validate() error { | |
if p.pluginHandler.name == "" { | |
return errors.New("plugin requires a name") | |
} | |
if p.pluginHandler.description == "" { | |
return errors.New("plugin requires a description") | |
} | |
return nil | |
} | |
func (p *Plugin) Serve() { | |
ph := &pluginHandler{} | |
plugin.Serve(ph) | |
} | |
type pluginHandler struct { | |
mu sync.Mutex | |
name string | |
description string | |
capabilities plugin.Capabilities | |
print func(dashboardClient Dashboard, object runtime.Object) (plugin.PrintResponse, error) | |
printTab func(dashboardClient Dashboard, object runtime.Object) (*component.Tab, error) | |
objectStatus func(dashboardClient Dashboard, object runtime.Object) (plugin.ObjectStatusResponse, error) | |
handleAction func(dashboardClient Dashboard, payload action.Payload) error | |
dashboardClient Dashboard | |
} | |
func (p *pluginHandler) Register(dashboardAPIAddress string) (plugin.Metadata, error) { | |
p.mu.Lock() | |
defer p.mu.Unlock() | |
client, err := NewDashboard(dashboardAPIAddress) | |
if err != nil { | |
return plugin.Metadata{}, errors.Wrap(err, "create api client") | |
} | |
p.dashboardClient = client | |
return plugin.Metadata{ | |
Name: p.name, | |
Description: p.description, | |
Capabilities: p.capabilities, | |
}, nil | |
} | |
func (p *pluginHandler) Print(object runtime.Object) (plugin.PrintResponse, error) { | |
if p.print == nil { | |
return plugin.PrintResponse{}, nil | |
} | |
return p.print(p.dashboardClient, object) | |
} | |
func (p *pluginHandler) PrintTab(object runtime.Object) (*component.Tab, error) { | |
if p.printTab == nil { | |
return &component.Tab{}, nil | |
} | |
return p.printTab(p.dashboardClient, object) | |
} | |
func (p *pluginHandler) ObjectStatus(object runtime.Object) (plugin.ObjectStatusResponse, error) { | |
if p.objectStatus == nil { | |
return plugin.ObjectStatusResponse{}, nil | |
} | |
return p.objectStatus(p.dashboardClient, object) | |
} | |
func (p *pluginHandler) HandleAction(payload action.Payload) error { | |
if p.handleAction == nil { | |
return nil | |
} | |
return p.handleAction(p.dashboardClient, payload) | |
} | |
var _ plugin.Service = (*pluginHandler)(nil) | |
type Dashboard interface { | |
Close() error | |
List(ctx context.Context, key store.Key) ([]*unstructured.Unstructured, error) | |
Get(ctx context.Context, key store.Key) (*unstructured.Unstructured, error) | |
Update(ctx context.Context, object *unstructured.Unstructured) error | |
PortForward(ctx context.Context, req api.PortForwardRequest) (api.PortForwardResponse, error) | |
CancelPortForward(ctx context.Context, id string) | |
ForceFrontendUpdate(ctx context.Context) error | |
} | |
func NewDashboard(dashboardAPIAddress string) (Dashboard, error) { | |
return api.NewClient(dashboardAPIAddress) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment