mirror of
https://github.com/kubernetes-sigs/kustomize.git
synced 2026-05-17 18:25:26 +00:00
Clean up output format for status events command
This commit is contained in:
@@ -54,7 +54,7 @@ type EventsRunner struct {
|
||||
func (r *EventsRunner) runE(c *cobra.Command, args []string) error {
|
||||
ctx := context.Background()
|
||||
|
||||
resolver, err := r.newResolverFunc(r.Interval)
|
||||
resolver, mapper, err := r.newResolverFunc(r.Interval)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error creating resolver")
|
||||
}
|
||||
@@ -62,7 +62,9 @@ func (r *EventsRunner) runE(c *cobra.Command, args []string) error {
|
||||
// Set up a CaptureIdentifierFilter and run all inputs through the
|
||||
// filter with the pipeline to capture the inventory of resources
|
||||
// which we are interested in.
|
||||
captureFilter := &CaptureIdentifiersFilter{}
|
||||
captureFilter := &CaptureIdentifiersFilter{
|
||||
Mapper: mapper,
|
||||
}
|
||||
filters := []kio.Filter{captureFilter}
|
||||
|
||||
var inputs []kio.Reader
|
||||
|
||||
@@ -200,7 +200,11 @@ func (e *EventOutput) allResources() []ResourceIdentifier {
|
||||
if !event.isResourceUpdateEvent() {
|
||||
continue
|
||||
}
|
||||
r := event.identifier
|
||||
r := ResourceIdentifier{
|
||||
namespace: event.namespace,
|
||||
name: event.name,
|
||||
kind: event.kind,
|
||||
}
|
||||
if _, found := seenResources[r]; !found {
|
||||
resources = append(resources, r)
|
||||
seenResources[r] = true
|
||||
@@ -215,7 +219,12 @@ func (e *EventOutput) statusesForResource(resource ResourceIdentifier) []status.
|
||||
if !event.isResourceUpdateEvent() {
|
||||
continue
|
||||
}
|
||||
if event.identifier.Equals(resource) {
|
||||
identifier := ResourceIdentifier{
|
||||
namespace: event.namespace,
|
||||
name: event.name,
|
||||
kind: event.kind,
|
||||
}
|
||||
if identifier.Equals(resource) {
|
||||
statuses = append(statuses, event.status)
|
||||
}
|
||||
}
|
||||
@@ -223,32 +232,36 @@ func (e *EventOutput) statusesForResource(resource ResourceIdentifier) []status.
|
||||
}
|
||||
|
||||
type EventOutputLine struct {
|
||||
eventType string
|
||||
aggStatus status.Status
|
||||
identifier ResourceIdentifier
|
||||
status status.Status
|
||||
message string
|
||||
eventType wait.EventType
|
||||
aggStatus status.Status
|
||||
kind string
|
||||
namespace string
|
||||
name string
|
||||
status status.Status
|
||||
message string
|
||||
}
|
||||
|
||||
func (e *EventOutputLine) isResourceUpdateEvent() bool {
|
||||
return e.eventType == string(wait.ResourceUpdate)
|
||||
return e.eventType == wait.ResourceUpdate
|
||||
}
|
||||
|
||||
var (
|
||||
eventRegex = regexp.MustCompile(`^\s*` +
|
||||
`(?P<eventType>\S+)\s+` +
|
||||
`(?P<aggStatus>\S+)\s+` +
|
||||
`((?P<resourceType>\S+)\s+` +
|
||||
`(?P<aggStatus>(?:Current|InProgress|Failed|Terminating|Unknown))\s+` +
|
||||
`(?P<message>.*\S)` +
|
||||
`\s*$`)
|
||||
resourceEventRegex = regexp.MustCompile(`^\s*` +
|
||||
`(?P<namespace>\S+)\s+` +
|
||||
`(?P<aggStatus>(?:Current|InProgress|Failed|Terminating|Unknown))\s+` +
|
||||
`(?P<resourceType>\S+)\s+` +
|
||||
`(?P<name>\S+)\s+` +
|
||||
`(?P<status>\S+)\s+` +
|
||||
`(?P<message>.*\S)){0,1}` +
|
||||
`(?P<status>(?:Current|InProgress|Failed|Terminating|Unknown))\s+` +
|
||||
`(?P<message>.*\S)` +
|
||||
`\s*$`)
|
||||
eventHeaderRegex = regexp.MustCompile(`^\s*` +
|
||||
`EVENT TYPE\s+` +
|
||||
`NAMESPACE\s+` +
|
||||
`AGG STATUS\s+` +
|
||||
`TYPE\s+` +
|
||||
`NAMESPACE\s+` +
|
||||
`NAME\s+` +
|
||||
`STATUS\s+` +
|
||||
`MESSAGE` +
|
||||
@@ -262,40 +275,43 @@ func parseEventOutput(_ *testing.T, output string) EventOutput {
|
||||
if len(line) == 0 {
|
||||
continue // Ignore empty lines
|
||||
}
|
||||
|
||||
match := eventHeaderRegex.FindStringSubmatch(line)
|
||||
if match != nil {
|
||||
continue // Ignore headers
|
||||
}
|
||||
|
||||
match = eventRegex.FindStringSubmatch(line)
|
||||
if match != nil {
|
||||
aggStatus := status.FromStringOrDie(match[1])
|
||||
var eventType wait.EventType
|
||||
if aggStatus == status.CurrentStatus {
|
||||
eventType = wait.Completed
|
||||
} else {
|
||||
eventType = wait.Aborted
|
||||
}
|
||||
eventOutput.events = append(eventOutput.events, EventOutputLine{
|
||||
eventType: eventType,
|
||||
aggStatus: aggStatus,
|
||||
message: match[2],
|
||||
})
|
||||
}
|
||||
|
||||
match = resourceEventRegex.FindStringSubmatch(line)
|
||||
if match == nil {
|
||||
eventOutput.unknownLines = append(eventOutput.unknownLines, line)
|
||||
continue
|
||||
}
|
||||
|
||||
eventOutputLine := EventOutputLine{
|
||||
eventType: match[1],
|
||||
eventOutput.events = append(eventOutput.events, EventOutputLine{
|
||||
eventType: wait.ResourceUpdate,
|
||||
aggStatus: status.FromStringOrDie(match[2]),
|
||||
}
|
||||
|
||||
if eventOutputLine.eventType == string(wait.ResourceUpdate) {
|
||||
resourceType := match[4]
|
||||
parts := strings.Split(resourceType, "/")
|
||||
var identifier ResourceIdentifier
|
||||
if len(parts) == 2 {
|
||||
identifier.apiVersion = parts[0]
|
||||
identifier.kind = parts[1]
|
||||
} else {
|
||||
identifier.apiVersion = strings.Join(parts[:2], "/")
|
||||
identifier.kind = parts[2]
|
||||
}
|
||||
identifier.namespace = match[5]
|
||||
identifier.name = match[6]
|
||||
eventOutputLine.identifier = identifier
|
||||
eventOutputLine.status = status.FromStringOrDie(match[7])
|
||||
eventOutputLine.message = match[8]
|
||||
}
|
||||
|
||||
eventOutput.events = append(eventOutput.events, eventOutputLine)
|
||||
kind: match[3],
|
||||
namespace: match[1],
|
||||
name: match[4],
|
||||
status: status.FromStringOrDie(match[5]),
|
||||
message: match[6],
|
||||
})
|
||||
}
|
||||
return eventOutput
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ type FetchRunner struct {
|
||||
func (r *FetchRunner) runE(c *cobra.Command, args []string) error {
|
||||
ctx := context.Background()
|
||||
|
||||
resolver, err := r.newResolverFunc(time.Minute)
|
||||
resolver, mapper, err := r.newResolverFunc(time.Minute)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "error creating resolver")
|
||||
}
|
||||
@@ -58,7 +58,9 @@ func (r *FetchRunner) runE(c *cobra.Command, args []string) error {
|
||||
// Set up a CaptureIdentifierFilter and run all inputs through the
|
||||
// filter with the pipeline to capture the inventory of resources
|
||||
// which we are interested in.
|
||||
captureFilter := &CaptureIdentifiersFilter{}
|
||||
captureFilter := &CaptureIdentifiersFilter{
|
||||
Mapper: mapper,
|
||||
}
|
||||
filters := []kio.Filter{captureFilter}
|
||||
|
||||
var inputs []kio.Reader
|
||||
|
||||
@@ -241,7 +241,7 @@ func (f *FakeClient) List(context.Context, runtime.Object, ...client.ListOption)
|
||||
}
|
||||
|
||||
func fakeResolver(fakeClient client.Reader, mapperTypes ...schema.GroupVersionKind) newResolverFunc {
|
||||
return func(pollInterval time.Duration) (*wait.Resolver, error) {
|
||||
return func(pollInterval time.Duration) (*wait.Resolver, meta.RESTMapper, error) {
|
||||
var groupVersions []schema.GroupVersion
|
||||
for _, gvk := range mapperTypes {
|
||||
groupVersions = append(groupVersions, gvk.GroupVersion())
|
||||
@@ -251,7 +251,7 @@ func fakeResolver(fakeClient client.Reader, mapperTypes ...schema.GroupVersionKi
|
||||
mapper.Add(gvk, meta.RESTScopeNamespace)
|
||||
}
|
||||
|
||||
return wait.NewResolver(fakeClient, mapper, pollInterval), nil
|
||||
return wait.NewResolver(fakeClient, mapper, pollInterval), mapper, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -227,11 +227,11 @@ type eventColumnInfo struct {
|
||||
var (
|
||||
eventColumns = []eventColumnInfo{
|
||||
{
|
||||
header: "EVENT TYPE",
|
||||
header: "NAMESPACE",
|
||||
width: 15,
|
||||
requireResourceUpdateEvent: false,
|
||||
requireResourceUpdateEvent: true,
|
||||
contentFunc: func(event wait.Event) string {
|
||||
return string(event.Type)
|
||||
return event.EventResource.ResourceIdentifier.Namespace
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -247,16 +247,7 @@ var (
|
||||
width: 20,
|
||||
requireResourceUpdateEvent: true,
|
||||
contentFunc: func(event wait.Event) string {
|
||||
return fmt.Sprintf("%s/%s", event.EventResource.ResourceIdentifier.GroupKind.Group,
|
||||
event.EventResource.ResourceIdentifier.GroupKind.Kind)
|
||||
},
|
||||
},
|
||||
{
|
||||
header: "NAMESPACE",
|
||||
width: 15,
|
||||
requireResourceUpdateEvent: true,
|
||||
contentFunc: func(event wait.Event) string {
|
||||
return event.EventResource.ResourceIdentifier.Namespace
|
||||
return event.EventResource.ResourceIdentifier.GroupKind.Kind
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -278,12 +269,20 @@ var (
|
||||
{
|
||||
header: "MESSAGE",
|
||||
width: 50,
|
||||
requireResourceUpdateEvent: true,
|
||||
requireResourceUpdateEvent: false,
|
||||
contentFunc: func(event wait.Event) string {
|
||||
if event.EventResource.Error != nil {
|
||||
return event.EventResource.Error.Error()
|
||||
switch event.Type {
|
||||
case wait.ResourceUpdate:
|
||||
if event.EventResource.Error != nil {
|
||||
return event.EventResource.Error.Error()
|
||||
}
|
||||
return event.EventResource.Message
|
||||
case wait.Aborted:
|
||||
return fmt.Sprint("Operation aborted before all resources have become Current")
|
||||
case wait.Completed:
|
||||
return fmt.Sprint("All resources have become Current")
|
||||
}
|
||||
return event.EventResource.Message
|
||||
return ""
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -308,11 +307,14 @@ func newEventPrinter(out io.Writer, err io.Writer) *EventPrinter {
|
||||
|
||||
func (e *EventPrinter) printEvent(event wait.Event) {
|
||||
for _, column := range eventColumns {
|
||||
var text string
|
||||
if event.Type != wait.ResourceUpdate && column.requireResourceUpdateEvent {
|
||||
continue
|
||||
text = ""
|
||||
} else {
|
||||
text = trimString(column.contentFunc(event), column.width)
|
||||
}
|
||||
format := fmt.Sprintf("%%-%ds ", column.width)
|
||||
printOrDie(e.out, format, trimString(column.contentFunc(event), column.width))
|
||||
printOrDie(e.out, format, text)
|
||||
}
|
||||
printOrDie(e.out, "\n")
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ package cmd
|
||||
import (
|
||||
"time"
|
||||
|
||||
"k8s.io/apimachinery/pkg/api/meta"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
clientgoscheme "k8s.io/client-go/kubernetes/scheme"
|
||||
@@ -25,49 +26,64 @@ func init() {
|
||||
_ = clientgoscheme.AddToScheme(scheme)
|
||||
}
|
||||
|
||||
type newResolverFunc func(pollInterval time.Duration) (*wait.Resolver, error)
|
||||
type newResolverFunc func(pollInterval time.Duration) (*wait.Resolver, meta.RESTMapper, error)
|
||||
|
||||
// newResolver returns a new resolver that can resolve status for resources based
|
||||
// on polling the cluster.
|
||||
func newResolver(pollInterval time.Duration) (*wait.Resolver, error) {
|
||||
func newResolver(pollInterval time.Duration) (*wait.Resolver, meta.RESTMapper, error) {
|
||||
config := ctrl.GetConfigOrDie()
|
||||
mapper, err := apiutil.NewDiscoveryRESTMapper(config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
c, err := client.New(config, client.Options{Scheme: scheme, Mapper: mapper})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return wait.NewResolver(c, mapper, pollInterval), nil
|
||||
return wait.NewResolver(c, mapper, pollInterval), mapper, nil
|
||||
}
|
||||
|
||||
// CaptureIdentifiersFilter implements the Filter interface in the kio package. It
|
||||
// captures the identifiers for all resources passed through the pipeline.
|
||||
type CaptureIdentifiersFilter struct {
|
||||
Identifiers []wait.ResourceIdentifier
|
||||
Mapper meta.RESTMapper
|
||||
}
|
||||
|
||||
var _ kio.Filter = &CaptureIdentifiersFilter{}
|
||||
|
||||
func (f *CaptureIdentifiersFilter) Filter(slice []*yaml.RNode) ([]*yaml.RNode, error) {
|
||||
for i := range slice {
|
||||
meta, err := slice[i].GetMeta()
|
||||
objectMeta, err := slice[i].GetMeta()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// TODO(mortent): Update kyaml library
|
||||
id := meta.GetIdentifier()
|
||||
id := objectMeta.GetIdentifier()
|
||||
gv, err := schema.ParseGroupVersion(id.APIVersion)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
gk := schema.GroupKind{
|
||||
Group: gv.Group,
|
||||
Kind: id.Kind,
|
||||
}
|
||||
mapping, err := f.Mapper.RESTMapping(gk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
var namespace string
|
||||
if mapping.Scope.Name() == meta.RESTScopeNameNamespace && id.Namespace == "" {
|
||||
namespace = "default"
|
||||
} else {
|
||||
namespace = id.Namespace
|
||||
}
|
||||
if IsValidKubernetesResource(id) {
|
||||
f.Identifiers = append(f.Identifiers, wait.ResourceIdentifier{
|
||||
Name: id.Name,
|
||||
Namespace: id.Namespace,
|
||||
Namespace: namespace,
|
||||
GroupKind: schema.GroupKind{
|
||||
Group: gv.Group,
|
||||
Kind: id.Kind,
|
||||
|
||||
@@ -60,12 +60,14 @@ type WaitRunner struct {
|
||||
func (r *WaitRunner) runE(c *cobra.Command, args []string) error {
|
||||
ctx := context.Background()
|
||||
|
||||
resolver, err := r.newResolverFunc(r.Interval)
|
||||
resolver, mapper, err := r.newResolverFunc(r.Interval)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "errors creating resolver")
|
||||
}
|
||||
|
||||
captureFilter := &CaptureIdentifiersFilter{}
|
||||
captureFilter := &CaptureIdentifiersFilter{
|
||||
Mapper: mapper,
|
||||
}
|
||||
filters := []kio.Filter{captureFilter}
|
||||
|
||||
var inputs []kio.Reader
|
||||
|
||||
Reference in New Issue
Block a user