Skip to content

Commit 251468a

Browse files
author
Stan Lagun
committed
Improved status reporting
This commit rewrites status reporting used to control deployment progress and get-status command * Old reporter machinery was removed * Resource classes were simplified: - they no longer wrap resources in SimpleReporter - they do not care about their metadata - Status method was replaced with GetProgress which reports deployment progress in float number 0..1. Most resources have either 0 or 1, but replicated resources can have all the variety - resources no longer dial with reporting - handling of success factor is now done in scheduler As a result resource classes are now much simpler On top of that new status methods were added that collect overall deployment statistics and detailed per-resource status table. Both can be retrieved using get-status CLI command
1 parent de235b1 commit 251468a

40 files changed

+1229
-1527
lines changed

cmd/get-status.go

+32-8
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,9 @@ import (
2323
"github.com/Mirantis/k8s-AppController/pkg/client"
2424
"github.com/Mirantis/k8s-AppController/pkg/interfaces"
2525
"github.com/Mirantis/k8s-AppController/pkg/scheduler"
26-
"github.com/spf13/cobra"
2726

27+
"github.com/olekukonko/tablewriter"
28+
"github.com/spf13/cobra"
2829
"k8s.io/client-go/pkg/labels"
2930
)
3031

@@ -93,25 +94,48 @@ func getStatus(cmd *cobra.Command, args []string) {
9394
AllowUndeclaredArgs: anyArgs,
9495
}
9596

96-
status, report, err := scheduler.GetStatus(c, sel, options)
97+
graph, err := scheduler.GetStatusGraph(c, sel, options)
9798
if err != nil {
9899
log.Fatal(err)
99100
}
101+
102+
//status := graph.GetDeploymentStatus()
100103
if getJSON {
101-
data, err := json.Marshal(report)
104+
data := graph.GetNodeStatuses()
105+
out, err := json.Marshal(data)
102106
if err != nil {
103107
log.Fatal(err)
104108
}
105-
fmt.Printf(string(data))
109+
fmt.Printf(string(out))
106110
} else {
107-
fmt.Printf("STATUS: %s\n", status)
111+
status := graph.GetDeploymentStatus()
112+
if status.Total == 0 {
113+
fmt.Println("Dependency graph is empty")
114+
return
115+
}
116+
117+
fmt.Println()
118+
fmt.Printf("Total nodes: %d (%d groups)\n", status.Total, status.TotalGroups)
119+
fmt.Printf(" Finished: %d\n", status.Finished)
120+
fmt.Printf(" Progress: %d %%\n", int(status.Progress*100))
121+
108122
if getReport {
109-
data := report.AsText(0)
110-
for _, line := range data {
111-
fmt.Println(line)
123+
fmt.Println()
124+
table := tablewriter.NewWriter(os.Stdout)
125+
table.SetHeader([]string{"Node", "Status", "Progress %"})
126+
table.SetColWidth(70)
127+
table.SetAutoFormatHeaders(false)
128+
for _, node := range graph.GetNodeStatuses() {
129+
table.Append([]string{
130+
node.Name,
131+
node.Status,
132+
fmt.Sprintf("%d %%", node.Progress),
133+
})
112134
}
135+
table.Render()
113136
}
114137
}
138+
115139
}
116140

117141
// InitGetStatusCommand is an initialiser for get-status

e2e/example_runner.go

+4-7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ import (
2525
"github.com/Mirantis/k8s-AppController/e2e/utils"
2626
"github.com/Mirantis/k8s-AppController/pkg/client"
2727
"github.com/Mirantis/k8s-AppController/pkg/interfaces"
28-
"github.com/Mirantis/k8s-AppController/pkg/report"
2928
"github.com/Mirantis/k8s-AppController/pkg/scheduler"
3029

3130
. "github.com/onsi/ginkgo"
@@ -105,18 +104,16 @@ func (f *examplesFramework) handleListCreation(ustList *runtime.UnstructuredList
105104
}
106105

107106
func (f *examplesFramework) VerifyStatus(options interfaces.DependencyGraphOptions) {
108-
var depReport report.DeploymentReport
109107
Eventually(
110108
func() bool {
111-
status, r, err := scheduler.GetStatus(f.Client, nil, options)
109+
graph, err := scheduler.GetStatusGraph(f.Client, nil, options)
112110
if err != nil {
113111
return false
114112
}
115-
depReport = r.(report.DeploymentReport)
116-
utils.Logf("STATUS: %s\n", status)
117-
return status == interfaces.Finished || status == interfaces.Empty
113+
status := graph.GetDeploymentStatus()
114+
return status.Progress == 1 || status.Total == 0
118115
},
119-
300*time.Second, 5*time.Second).Should(BeTrue(), strings.Join(depReport.AsText(0), "\n"))
116+
300*time.Second, 5*time.Second).Should(BeTrue())
120117
}
121118

122119
func (f *examplesFramework) CreateRunAndVerify(exampleName string, options interfaces.DependencyGraphOptions) {

glide.lock

+9-3
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

glide.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ import:
66
- package: k8s.io/apimachinery
77
- package: github.com/fatih/color
88
version: ^1.1.0
9+
- package: github.com/olekukonko/tablewriter

pkg/interfaces/enums.go

-54
This file was deleted.

pkg/interfaces/interfaces.go

+21-34
Original file line numberDiff line numberDiff line change
@@ -18,42 +18,15 @@ import (
1818
"github.com/Mirantis/k8s-AppController/pkg/client"
1919
)
2020

21-
// ResourceStatus is an enum of k8s resource statuses
22-
type ResourceStatus string
23-
24-
// Possible ResourceStatus values
25-
const (
26-
ResourceReady ResourceStatus = "ready"
27-
ResourceNotReady ResourceStatus = "not ready"
28-
ResourceError ResourceStatus = "error"
29-
)
30-
3121
// DefaultFlowName is the name of default flow (main dependency graph)
3222
const DefaultFlowName = "DEFAULT"
3323

34-
// BaseResource is an interface for AppController supported resources
35-
type BaseResource interface {
24+
// Resource is an interface for AppController supported resources
25+
type Resource interface {
3626
Key() string
37-
// Ensure that Status() supports nil as meta
38-
Status(meta map[string]string) (ResourceStatus, error)
27+
GetProgress() (float32, error)
3928
Create() error
4029
Delete() error
41-
Meta(string) interface{}
42-
}
43-
44-
// DependencyReport is a report of a single dependency of a node in graph
45-
type DependencyReport struct {
46-
Dependency string
47-
Blocks bool
48-
Percentage int
49-
Needed int
50-
Message string
51-
}
52-
53-
// Resource is an interface for a base resource that implements getting dependency reports
54-
type Resource interface {
55-
BaseResource
56-
GetDependencyReport(map[string]string) DependencyReport
5730
}
5831

5932
// ResourceTemplate is an interface for AppController supported resource templates
@@ -64,14 +37,28 @@ type ResourceTemplate interface {
6437
NewExisting(string, client.Interface, GraphContext) Resource
6538
}
6639

67-
// DeploymentReport is an interface to get string representation of current deployment progress
68-
type DeploymentReport interface {
69-
AsText(int) []string
40+
// DeploymentStatus is the structure containing deployment status - different stats and progress info
41+
type DeploymentStatus struct {
42+
Total int
43+
TotalGroups int
44+
Failed int
45+
Skipped int
46+
Finished int
47+
Replicas int
48+
Progress float32
49+
}
50+
51+
// NodeStatus represents status of each graph node
52+
type NodeStatus struct {
53+
Name string
54+
Status string
55+
Progress int
7056
}
7157

7258
// DependencyGraph represents operations on dependency graph
7359
type DependencyGraph interface {
74-
GetStatus() (DeploymentStatus, DeploymentReport)
60+
GetDeploymentStatus() DeploymentStatus
61+
GetNodeStatuses() []NodeStatus
7562
Deploy(<-chan struct{}) bool
7663
Options() DependencyGraphOptions
7764
}

pkg/mocks/countingresource.go

+14-25
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,13 @@ import (
1919

2020
"github.com/Mirantis/k8s-AppController/pkg/client"
2121
"github.com/Mirantis/k8s-AppController/pkg/interfaces"
22-
"github.com/Mirantis/k8s-AppController/pkg/report"
2322
)
2423

2524
// CountingResource is a fake resource that becomes ready after given timeout.
2625
// It also increases the counter when started and decreases it when becomes ready
2726
type CountingResource struct {
2827
key string
29-
status interfaces.ResourceStatus
28+
progress float32
3029
counter *CounterWithMemo
3130
timeout time.Duration
3231
startTime time.Time
@@ -37,15 +36,15 @@ func (c CountingResource) Key() string {
3736
return c.key
3837
}
3938

40-
// Status returns a status of the CountingResource. It also updates the status
39+
// GetProgress returns a progress of the CountingResource. It also updates the progress
4140
// after provided timeout and decrements counter
42-
func (c *CountingResource) Status(meta map[string]string) (interfaces.ResourceStatus, error) {
43-
if time.Since(c.startTime) >= c.timeout && c.status != interfaces.ResourceReady {
41+
func (c *CountingResource) GetProgress() (float32, error) {
42+
if time.Since(c.startTime) >= c.timeout && c.progress < 1 {
4443
c.counter.Dec()
45-
c.status = interfaces.ResourceReady
44+
c.progress = 1
4645
}
4746

48-
return c.status, nil
47+
return c.progress, nil
4948
}
5049

5150
// Create increments counter and sets creation time
@@ -60,32 +59,22 @@ func (c *CountingResource) Delete() error {
6059
return nil
6160
}
6261

63-
// Meta returns empty string
64-
func (c *CountingResource) Meta(string) interface{} {
65-
return nil
66-
}
67-
68-
// NameMatches returns true
69-
func (c *CountingResource) NameMatches(_ client.ResourceDefinition, _ string) bool {
70-
return true
71-
}
72-
7362
// New returns new fake resource
74-
func (c *CountingResource) New(_ client.ResourceDefinition, _ client.Interface) interfaces.BaseResource {
75-
return report.SimpleReporter{BaseResource: NewResource("fake", interfaces.ResourceReady)}
63+
func (c *CountingResource) New(_ client.ResourceDefinition, _ client.Interface) interfaces.Resource {
64+
return NewResource("fake", 1)
7665
}
7766

7867
// NewExisting returns new existing resource
79-
func (c *CountingResource) NewExisting(name string, _ client.Interface) interfaces.BaseResource {
80-
return report.SimpleReporter{BaseResource: NewResource(name, interfaces.ResourceReady)}
68+
func (c *CountingResource) NewExisting(name string, _ client.Interface) interfaces.Resource {
69+
return NewResource(name, 1)
8170
}
8271

8372
// NewCountingResource creates new instance of CountingResource
8473
func NewCountingResource(key string, counter *CounterWithMemo, timeout time.Duration) *CountingResource {
8574
return &CountingResource{
86-
key: key,
87-
status: interfaces.ResourceNotReady,
88-
counter: counter,
89-
timeout: timeout,
75+
key: key,
76+
progress: 0,
77+
counter: counter,
78+
timeout: timeout,
9079
}
9180
}

0 commit comments

Comments
 (0)