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

Commit

Permalink
Hide manifests behind button toggle (#2841)
Browse files Browse the repository at this point in the history
Signed-off-by: Sam Foo <[email protected]>
  • Loading branch information
Sam Foo authored Sep 8, 2021
1 parent d4f47ac commit 3946917
Show file tree
Hide file tree
Showing 13 changed files with 187 additions and 39 deletions.
4 changes: 2 additions & 2 deletions cmd/octant-sample-plugin/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ func main() {
logger.Info("octant-sample-plugin is starting, with logger helper")
service.SetupPluginLogger(service.Info)
// OUTPUT: 2021-08-23T11:35:02.714-0500 INFO octant-sample-plugin plugin/logger.go:43 octant-sample-plugin is starting, with logger helper {"timestamp": "2021-08-23T11:35:02.714-0500"}
log.Println("octant-sample-plugin is starting, with with prefix logger")
// OUTPUT: 2021-08-23T11:35:02.714-0500 INFO octant-sample-plugin plugin/logger.go:43 [INFO] 2021/08/23 11:35:02 octant-sample-plugin is starting, with with prefix logger
log.Println("octant-sample-plugin is starting with prefix logger")
// OUTPUT: 2021-08-23T11:35:02.714-0500 INFO octant-sample-plugin plugin/logger.go:43 [INFO] 2021/08/23 11:35:02 octant-sample-plugin is starting with prefix logger
p.Serve()

}
Expand Down
43 changes: 30 additions & 13 deletions internal/printer/manifest.go → internal/manifest/manifest.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package printer
package manifest

import (
context "context"
"context"
"fmt"
"strings"
"sync"

"github.com/containers/image/v5/image"
imagev5 "github.com/containers/image/v5/image"
"github.com/containers/image/v5/transports/alltransports"
"github.com/containers/image/v5/types"

Expand All @@ -33,15 +33,32 @@ var (
)

func NewManifestConfiguration() *ManifestConfiguration {
mc := &ManifestConfiguration{}
mc := &ManifestConfiguration{
imageCache: make(map[ImageEntry]ImageManifest),
}
return mc
}

func (manifest *ManifestConfiguration) GetImageManifest(ctx context.Context, hostOS, imageName string) (string, string, error) {
func (manifest *ManifestConfiguration) SetManifest(imageEntry ImageEntry, imageManifest ImageManifest) {
manifest.imageCache[imageEntry] = imageManifest
}

func (manifest *ManifestConfiguration) HasEntry(hostOS, imageName string) bool {
imageName = parseName(imageName)
_, ok := manifest.imageCache[ImageEntry{ImageName: imageName, HostOS: hostOS}]
return ok
}

func parseName(imageName string) string {
parts := strings.SplitN(imageName, "://", 2) // if format not specified, assume docker
if len(parts) != 2 {
imageName = "docker://" + imageName
}
return imageName
}

func (manifest *ManifestConfiguration) GetImageManifest(ctx context.Context, hostOS, imageName string) (string, string, error) {
imageName = parseName(imageName)

imageEntry := ImageEntry{ImageName: imageName, HostOS: hostOS}
if _, ok := manifest.imageCache[imageEntry]; ok {
Expand All @@ -62,28 +79,28 @@ func (manifest *ManifestConfiguration) GetImageManifest(ctx context.Context, hos
if err != nil {
return "", "", fmt.Errorf("error creating image source for image %s: %w", imageName, err)
}
defer func() {
err = imageSrc.Close()
}()

rawManifest, _, err := imageSrc.GetManifest(ctx, nil)
if err != nil {
return "", "", fmt.Errorf("error getting manifest for for image %s: %w", imageName, err)
return "", "", fmt.Errorf("error getting manifest for image %s: %w", imageName, err)
}

image, err := image.FromUnparsedImage(ctx, systemCtx, image.UnparsedInstance(imageSrc, nil))
image, err := imagev5.FromUnparsedImage(ctx, systemCtx, imagev5.UnparsedInstance(imageSrc, nil))
if err != nil {
return "", "", fmt.Errorf("error parsing manifest for for image %s: %w", imageName, err)
return "", "", fmt.Errorf("error parsing manifest for image %s: %w", imageName, err)
}

rawConfiguration, err := image.OCIConfig(ctx)
if err != nil {
return "", "", fmt.Errorf("error getting image config blob for for image %s: %w", imageName, err)
return "", "", fmt.Errorf("error getting image config blob for image %s: %w", imageName, err)
}

configOutput, err := json.MarshalIndent(rawConfiguration, "", " ")

if manifest.imageCache == nil {
manifest.imageCache = make(map[ImageEntry]ImageManifest)
}
manifest.imageCache[imageEntry] = ImageManifest{string(rawManifest), string(configOutput)}

return string(rawManifest), string(configOutput), nil
return string(rawManifest), string(configOutput), err
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package printer
package manifest

import (
"context"
"fmt"
"os"
"testing"

"github.com/stretchr/testify/assert"
Expand All @@ -13,6 +13,9 @@ import (
)

func Test_GetImageManifest(t *testing.T) {
if os.Getenv("CI") != "" {
t.Skip("Skipping test in CI to avoid rate limits")
}
tests := []struct {
name string
input string
Expand Down Expand Up @@ -48,7 +51,7 @@ func Test_GetImageManifest(t *testing.T) {
manifestPath: "alpine_manifest.json",
configPath: "alpine_config.json",
hostOS: "windows",
error: "error parsing manifest for for image docker://alpine:3.14.0: choosing image instance: no image found in manifest list for architecture amd64, variant \"\", OS windows",
error: "error parsing manifest for image docker://alpine:3.14.0: choosing image instance: no image found in manifest list for architecture amd64, variant \"\", OS windows",
},
}
mc := NewManifestConfiguration()
Expand All @@ -61,7 +64,6 @@ func Test_GetImageManifest(t *testing.T) {
expectedConfig := string(inputConfig)[:len(inputConfig)-1]

manifest, config, err := mc.GetImageManifest(context.Background(), tt.hostOS, tt.input)
fmt.Println("err", err)
if len(tt.error) > 0 {
assert.EqualError(t, err, tt.error)
return
Expand Down
1 change: 1 addition & 0 deletions internal/modules/overview/overview.go
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,7 @@ func (co *Overview) ActionPaths() map[string]action.DispatcherFunc {
octant.NewCronJobResume(co.dashConfig.ObjectStore(), co.dashConfig.ClusterClient()),
octant.NewObjectUpdaterDispatcher(co.dashConfig.ObjectStore()),
octant.NewApplyYaml(co.logger, co.dashConfig.ObjectStore()),
octant.NewManifest(co.logger),
}

return dispatchers.ToActionPaths()
Expand Down
1 change: 1 addition & 0 deletions internal/octant/actions.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const (
ActionOverviewServiceEditor = "action.octant.dev/serviceEditor"
ActionDeploymentConfiguration = "action.octant.dev/deploymentConfiguration"
ActionUpdateObject = "action.octant.dev/update"
ActionGetManifest = "action.octant.dev/manifest"
)

func sendAlert(alerter action.Alerter, alertType action.AlertType, message string, expiration *time.Time) {
Expand Down
42 changes: 42 additions & 0 deletions internal/octant/manifest.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package octant

import (
"context"
"fmt"

"github.com/vmware-tanzu/octant/internal/manifest"
"github.com/vmware-tanzu/octant/pkg/action"
"github.com/vmware-tanzu/octant/pkg/log"
)

type Manifest struct {
logger log.Logger
}

var _ action.Dispatcher = (*Manifest)(nil)

func NewManifest(logger log.Logger) *Manifest {
return &Manifest{logger: logger}
}

func (m *Manifest) ActionName() string {
return ActionGetManifest
}

func (m *Manifest) Handle(ctx context.Context, _ action.Alerter, payload action.Payload) error {
m.logger.With("payload", payload).Debugf("received action payload")
image, err := payload.String("image")
if err != nil {
return err
}
hostOS, err := payload.String("host")
if err != nil {
return err
}

_, _, err = manifest.ManifestManager.GetImageManifest(ctx, hostOS, image)
if err != nil {
return fmt.Errorf("getting manifest for image %s: %w", image, err)
}
return nil
}
26 changes: 15 additions & 11 deletions internal/printer/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,16 @@ package printer
import (
"context"
"fmt"
"path"
"sort"
"strings"

"github.com/vmware-tanzu/octant/internal/api"
"github.com/vmware-tanzu/octant/internal/util/json"

"github.com/vmware-tanzu/octant/internal/log"
"github.com/vmware-tanzu/octant/internal/manifest"
"github.com/vmware-tanzu/octant/internal/util/json"
"github.com/vmware-tanzu/octant/internal/util/kubernetes"

"path"
"sort"
"strings"
"github.com/vmware-tanzu/octant/pkg/action"

"github.com/vmware-tanzu/octant/internal/octant"

Expand Down Expand Up @@ -128,12 +128,16 @@ func (cc *ContainerConfiguration) Create() (*component.Summary, error) {
sections.AddText("Image ID", containerStatus.ImageID)
}

manifest, configuration, err := ManifestManager.GetImageManifest(cc.context, hostOS, c.Image)
if err == nil {
sections.Add("Image Manifest", component.NewJSONEditor(manifest, true))
sections.Add("Image Configuration", component.NewJSONEditor(configuration, true))
if !manifest.ManifestManager.HasEntry(hostOS, c.Image) {
sections.Add("Image Manifest", component.NewButton("Show Manifest", action.CreatePayload(octant.ActionGetManifest, map[string]interface{}{"host": hostOS, "image": c.Image})))
} else {
sections.Add("Image Manifest", component.NewText(fmt.Sprintf("Unable to load image manifest %s", err)))
manifest, configuration, err := manifest.ManifestManager.GetImageManifest(cc.context, hostOS, c.Image)
if err == nil {
sections.Add("Image Manifest", component.NewJSONEditor(manifest, true))
sections.Add("Image Configuration", component.NewJSONEditor(configuration, true))
} else {
sections.Add("Image Manifest", component.NewText(fmt.Sprintf("Unable to load image manifest %s", err)))
}
}

hostPorts := describeContainerHostPorts(c.Ports)
Expand Down
Loading

0 comments on commit 3946917

Please sign in to comment.