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