Skip to content

Commit 4f56890

Browse files
Project status should include pod information
And pending deployment state
1 parent 7798730 commit 4f56890

File tree

5 files changed

+212
-13
lines changed

5 files changed

+212
-13
lines changed

pkg/cmd/cli/describe/projectstatus.go

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error
109109
if len(groups) == 0 {
110110
fmt.Fprintln(out, "\nYou have no services, deployment configs, or build configs. 'osc new-app' can be used to create applications from scratch from existing Docker images and templates.")
111111
} else {
112-
fmt.Fprintln(out, "\nTo see more information about a service or deployment config, use 'osc describe service <name>' or 'osc describe dc <name>'.")
113-
fmt.Fprintln(out, "You can use 'osc get pods,svc,dc,bc,builds' to see lists of each of the types described above.")
112+
fmt.Fprintln(out, "\nTo see more information about a service or deployment, use 'osc describe service <name>' or 'osc describe dc <name>'.")
113+
fmt.Fprintln(out, "You can use 'osc get all' to see lists of each of the types described above.")
114114
}
115115

116116
return nil
@@ -371,7 +371,7 @@ func describeDeployments(node *graph.DeploymentConfigNode, count int) []string {
371371
}
372372

373373
for i, deployment := range deployments {
374-
out = append(out, describeDeploymentStatus(deployment))
374+
out = append(out, describeDeploymentStatus(deployment, i == 0))
375375

376376
switch {
377377
case count == -1:
@@ -387,20 +387,61 @@ func describeDeployments(node *graph.DeploymentConfigNode, count int) []string {
387387
return out
388388
}
389389

390-
func describeDeploymentStatus(deploy *kapi.ReplicationController) string {
390+
func describeDeploymentStatus(deploy *kapi.ReplicationController, first bool) string {
391391
timeAt := strings.ToLower(formatRelativeTime(deploy.CreationTimestamp.Time))
392392
status := deployutil.DeploymentStatusFor(deploy)
393393
version := deployutil.DeploymentVersionFor(deploy)
394394
switch status {
395395
case deployapi.DeploymentStatusFailed:
396+
reason := deployutil.DeploymentStatusReasonFor(deploy)
397+
if len(reason) > 0 {
398+
reason = fmt.Sprintf(": %s", reason)
399+
}
396400
// TODO: encode fail time in the rc
397-
return fmt.Sprintf("#%d deployment failed %s ago", version, timeAt)
401+
return fmt.Sprintf("#%d deployment failed %s ago%s%s", version, timeAt, reason, describeDeploymentPodSummaryInline(deploy, false))
398402
case deployapi.DeploymentStatusComplete:
399403
// TODO: pod status output
400-
return fmt.Sprintf("#%d deployed %s ago", version, timeAt)
404+
return fmt.Sprintf("#%d deployed %s ago%s", version, timeAt, describeDeploymentPodSummaryInline(deploy, first))
405+
case deployapi.DeploymentStatusRunning:
406+
return fmt.Sprintf("#%d deployment running for %s%s", version, timeAt, describeDeploymentPodSummaryInline(deploy, false))
401407
default:
402-
return fmt.Sprintf("#%d deployment %s %s ago", version, strings.ToLower(string(status)), timeAt)
408+
return fmt.Sprintf("#%d deployment %s %s ago%s", version, strings.ToLower(string(status)), timeAt, describeDeploymentPodSummaryInline(deploy, false))
409+
}
410+
}
411+
412+
func describeDeploymentPodSummaryInline(deploy *kapi.ReplicationController, includeEmpty bool) string {
413+
s := describeDeploymentPodSummary(deploy, includeEmpty)
414+
if len(s) == 0 {
415+
return s
416+
}
417+
change := ""
418+
if changing, ok := deployutil.DeploymentDesiredReplicas(deploy); ok {
419+
switch {
420+
case changing < deploy.Spec.Replicas:
421+
change = fmt.Sprintf(" reducing to %d", changing)
422+
case changing > deploy.Spec.Replicas:
423+
change = fmt.Sprintf(" growing to %d", changing)
424+
}
425+
}
426+
return fmt.Sprintf(" - %s%s", s, change)
427+
}
428+
429+
func describeDeploymentPodSummary(deploy *kapi.ReplicationController, includeEmpty bool) string {
430+
actual, requested := deploy.Status.Replicas, deploy.Spec.Replicas
431+
if actual == requested {
432+
switch {
433+
case actual == 0:
434+
if !includeEmpty {
435+
return ""
436+
}
437+
return "0 pods"
438+
case actual > 1:
439+
return fmt.Sprintf("%d pods", actual)
440+
default:
441+
return "1 pod"
442+
}
403443
}
444+
return fmt.Sprintf("%d/%d pods", actual, requested)
404445
}
405446

406447
func describeDeploymentConfigTriggers(config *deployapi.DeploymentConfig) (string, bool) {

pkg/cmd/cli/describe/projectstatus_test.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,8 @@ func TestProjectStatus(t *testing.T) {
137137
"database deploys",
138138
"frontend deploys",
139139
"with docker.io/openshift/ruby-20-centos7:latest",
140+
"#2 deployment failed less than a second ago: unable to contact server - 0/1 pods",
141+
"#2 deployment running for 7 seconds - 2/1 pods",
140142
"#1 deployed 8 seconds ago",
141143
"#1 deployed less than a second ago",
142144
"To see more information",
@@ -176,6 +178,6 @@ func TestProjectStatus(t *testing.T) {
176178
t.Errorf("%s: did not have %q:\n%s\n---", k, s, out)
177179
}
178180
}
179-
//t.Logf("\n%s", out)
181+
t.Logf("\n%s", out)
180182
}
181183
}

pkg/deploy/controller/deployerpod/factory.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,7 @@ func pollPods(deploymentStore cache.Store, kClient kclient.Interface) (cache.Enu
110110
if kerrors.IsNotFound(err) {
111111
nextStatus := deployapi.DeploymentStatusFailed
112112
deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(nextStatus)
113-
deployment.Annotations[deployapi.DeploymentStatusReasonAnnotation] = fmt.Sprintf("Couldn't find pod %s for deployment %s", podID, deployment.Name)
113+
deployment.Annotations[deployapi.DeploymentStatusReasonAnnotation] = fmt.Sprintf("deployment process pod %q was deleted before completion", podID)
114114

115115
if _, err := kClient.ReplicationControllers(deployment.Namespace).Update(deployment); err != nil {
116116
glog.Errorf("couldn't update deployment %s to status %s: %v", deployutil.LabelForDeployment(deployment), nextStatus, err)

pkg/deploy/util/util.go

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@ import (
1818
deployv3 "github.com/openshift/origin/pkg/deploy/api/v1beta3"
1919
)
2020

21-
// Maps the latest annotation keys to all known previous key names.
21+
// Maps the latest annotation keys to all known previous key names. Keys not represented here
22+
// may still be looked up directly via mappedAnnotationFor
2223
var annotationMap = map[string][]string{
2324
deployapi.DeploymentConfigAnnotation: {
2425
deployv1.DeploymentConfigAnnotation,
@@ -219,6 +220,22 @@ func DeploymentStatusFor(obj runtime.Object) deployapi.DeploymentStatus {
219220
return deployapi.DeploymentStatus(mappedAnnotationFor(obj, deployapi.DeploymentStatusAnnotation))
220221
}
221222

223+
func DeploymentStatusReasonFor(obj runtime.Object) string {
224+
return mappedAnnotationFor(obj, deployapi.DeploymentStatusReasonAnnotation)
225+
}
226+
227+
func DeploymentDesiredReplicas(obj runtime.Object) (int, bool) {
228+
s := mappedAnnotationFor(obj, deployapi.DesiredReplicasAnnotation)
229+
if len(s) == 0 {
230+
return 0, false
231+
}
232+
i, err := strconv.Atoi(s)
233+
if err != nil {
234+
return 0, false
235+
}
236+
return i, true
237+
}
238+
222239
func EncodedDeploymentConfigFor(obj runtime.Object) string {
223240
return mappedAnnotationFor(obj, deployapi.DeploymentEncodedConfigAnnotation)
224241
}
@@ -239,10 +256,12 @@ func mappedAnnotationFor(obj runtime.Object, key string) string {
239256
return ""
240257
}
241258
for _, mappedKey := range annotationMap[key] {
242-
val, hasVal := meta.Annotations[mappedKey]
243-
if hasVal {
259+
if val, ok := meta.Annotations[mappedKey]; ok {
244260
return val
245261
}
246262
}
263+
if val, ok := meta.Annotations[key]; ok {
264+
return val
265+
}
247266
return ""
248267
}

test/fixtures/app-scenarios/new-project-deployed-app.yaml

Lines changed: 138 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,76 @@ items:
7575
type: STI
7676
startTimestamp: 2015-04-07T04:12:21Z
7777
status: Complete
78+
- annotations:
79+
deploymentConfig: database
80+
deploymentStatus: Running
81+
deploymentVersion: "2"
82+
encodedDeploymentConfig: '{"kind":"DeploymentConfig","apiVersion":"v1beta1","metadata":{"name":"database","namespace":"test","selfLink":"/osapi/v1beta1/watch/deploymentConfigs/database","uid":"4725b5d3-dcdc-11e4-968a-080027c5bfa9","resourceVersion":"271","creationTimestamp":"2015-04-07T04:12:17Z","labels":{"template":"application-template-stibuild"}},"triggers":[{"type":"ConfigChange"}],"template":{"strategy":{"type":"Recreate"},"controllerTemplate":{"replicas":1,"replicaSelector":{"name":"database"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"ruby-helloworld-database","image":"openshift/mysql-55-centos7","ports":[{"containerPort":3306,"protocol":"TCP"}],"env":[{"name":"MYSQL_USER","key":"MYSQL_USER","value":"user1CY"},{"name":"MYSQL_PASSWORD","key":"MYSQL_PASSWORD","value":"FfyXmsGG"},{"name":"MYSQL_DATABASE","key":"MYSQL_DATABASE","value":"root"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"database","template":"application-template-stibuild"}}}},"latestVersion":1,"details":{"causes":[{"type":"ConfigChange"}]}}'
83+
pod: deploy-database-19m1he
84+
apiVersion: v1beta1
85+
creationTimestamp: 2015-04-07T04:12:18Z
86+
currentState:
87+
podTemplate:
88+
desiredState:
89+
manifest:
90+
containers: null
91+
id: ""
92+
restartPolicy: {}
93+
version: ""
94+
volumes: null
95+
replicas: 2
96+
desiredState:
97+
podTemplate:
98+
annotations:
99+
deployment: database-2
100+
deploymentConfig: database
101+
deploymentVersion: "2"
102+
desiredState:
103+
manifest:
104+
containers:
105+
- capabilities: {}
106+
env:
107+
- key: MYSQL_USER
108+
name: MYSQL_USER
109+
value: user1CY
110+
- key: MYSQL_PASSWORD
111+
name: MYSQL_PASSWORD
112+
value: FfyXmsGG
113+
- key: MYSQL_DATABASE
114+
name: MYSQL_DATABASE
115+
value: root
116+
image: openshift/mysql-55-centos7
117+
imagePullPolicy: PullIfNotPresent
118+
name: ruby-helloworld-database
119+
ports:
120+
- containerPort: 3306
121+
protocol: TCP
122+
resources: {}
123+
terminationMessagePath: /dev/termination-log
124+
dnsPolicy: ClusterFirst
125+
id: ""
126+
restartPolicy:
127+
always: {}
128+
version: v1beta2
129+
volumes: null
130+
labels:
131+
deployment: database-2
132+
deploymentconfig: database
133+
name: database
134+
template: application-template-stibuild
135+
replicaSelector:
136+
deployment: database-2
137+
deploymentconfig: database
138+
name: database
139+
replicas: 1
140+
id: database-2
141+
kind: ReplicationController
142+
labels:
143+
template: application-template-stibuild
144+
namespace: example
145+
resourceVersion: 318
146+
selfLink: /api/v1beta1/replicationControllers/database-1?namespace=example
147+
uid: 473d4a73-dcdc-11e4-968a-080027c5bfa9
78148
- annotations:
79149
deploymentConfig: database
80150
deploymentStatus: Complete
@@ -201,6 +271,73 @@ items:
201271
type: Recreate
202272
triggers:
203273
- type: ConfigChange
274+
- annotations:
275+
deploymentConfig: frontend
276+
deploymentStatus: Failed
277+
openshift.io/deployment.status-reason: unable to contact server
278+
deploymentVersion: "2"
279+
encodedDeploymentConfig: '{"kind":"DeploymentConfig","apiVersion":"v1beta1","metadata":{"name":"frontend","namespace":"test","selfLink":"/osapi/v1beta1/watch/deploymentConfigs/frontend","uid":"471f24e3-dcdc-11e4-968a-080027c5bfa9","resourceVersion":"346","creationTimestamp":"2015-04-07T04:12:17Z","labels":{"template":"application-template-stibuild"}},"triggers":[{"type":"ImageChange","imageChangeParams":{"automatic":true,"containerNames":["ruby-helloworld"],"from":{"kind":"ImageRepository","name":"origin-ruby-sample"},"tag":"latest","lastTriggeredImage":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58"}}],"template":{"strategy":{"type":"Recreate"},"controllerTemplate":{"replicas":1,"replicaSelector":{"name":"frontend"},"podTemplate":{"desiredState":{"manifest":{"version":"v1beta2","id":"","volumes":null,"containers":[{"name":"ruby-helloworld","image":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58","ports":[{"containerPort":8080,"protocol":"TCP"}],"env":[{"name":"ADMIN_USERNAME","key":"ADMIN_USERNAME","value":"adminNPX"},{"name":"ADMIN_PASSWORD","key":"ADMIN_PASSWORD","value":"7q1IdEao"},{"name":"MYSQL_USER","key":"MYSQL_USER","value":"user1CY"},{"name":"MYSQL_PASSWORD","key":"MYSQL_PASSWORD","value":"FfyXmsGG"},{"name":"MYSQL_DATABASE","key":"MYSQL_DATABASE","value":"root"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"PullIfNotPresent","capabilities":{}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"}},"labels":{"name":"frontend","template":"application-template-stibuild"}}}},"latestVersion":1,"details":{"causes":[{"type":"ImageChange","imageTrigger":{"repositoryName":"172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58","tag":"latest"}}]}}'
280+
pod: deploy-frontend-17mza9
281+
apiVersion: v1beta1
282+
creationTimestamp: 2015-04-07T04:12:53Z
283+
desiredState:
284+
podTemplate:
285+
annotations:
286+
deployment: frontend-2
287+
deploymentConfig: frontend
288+
deploymentVersion: "2"
289+
desiredState:
290+
manifest:
291+
containers:
292+
- capabilities: {}
293+
env:
294+
- key: ADMIN_USERNAME
295+
name: ADMIN_USERNAME
296+
value: adminNPX
297+
- key: ADMIN_PASSWORD
298+
name: ADMIN_PASSWORD
299+
value: 7q1IdEao
300+
- key: MYSQL_USER
301+
name: MYSQL_USER
302+
value: user1CY
303+
- key: MYSQL_PASSWORD
304+
name: MYSQL_PASSWORD
305+
value: FfyXmsGG
306+
- key: MYSQL_DATABASE
307+
name: MYSQL_DATABASE
308+
value: root
309+
image: 172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58
310+
imagePullPolicy: PullIfNotPresent
311+
name: ruby-helloworld
312+
ports:
313+
- containerPort: 8080
314+
protocol: TCP
315+
resources: {}
316+
terminationMessagePath: /dev/termination-log
317+
dnsPolicy: ClusterFirst
318+
id: ""
319+
restartPolicy:
320+
always: {}
321+
version: v1beta2
322+
volumes: null
323+
labels:
324+
deployment: frontend-2
325+
deploymentconfig: frontend
326+
name: frontend
327+
template: application-template-stibuild
328+
replicaSelector:
329+
deployment: frontend-2
330+
deploymentconfig: frontend
331+
name: frontend
332+
replicas: 1
333+
id: frontend-2
334+
kind: ReplicationController
335+
labels:
336+
template: application-template-stibuild
337+
namespace: example
338+
resourceVersion: 379
339+
selfLink: /api/v1beta1/replicationControllers/frontend-2?namespace=example
340+
uid: 5c9cd4ec-dcdc-11e4-968a-080027c5bfa9
204341
- annotations:
205342
deploymentConfig: frontend
206343
deploymentStatus: Complete
@@ -285,7 +422,7 @@ items:
285422
tag: latest
286423
type: ImageChange
287424
kind: DeploymentConfig
288-
latestVersion: 1
425+
latestVersion: 3
289426
metadata:
290427
creationTimestamp: 2015-04-07T04:12:17Z
291428
labels:

0 commit comments

Comments
 (0)