Skip to content

Commit

Permalink
Project status should include pod information
Browse files Browse the repository at this point in the history
And pending deployment state
  • Loading branch information
smarterclayton committed May 21, 2015
1 parent 7798730 commit 4f56890
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 13 deletions.
55 changes: 48 additions & 7 deletions pkg/cmd/cli/describe/projectstatus.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,8 +109,8 @@ func (d *ProjectStatusDescriber) Describe(namespace, name string) (string, error
if len(groups) == 0 {
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.")
} else {
fmt.Fprintln(out, "\nTo see more information about a service or deployment config, use 'osc describe service <name>' or 'osc describe dc <name>'.")
fmt.Fprintln(out, "You can use 'osc get pods,svc,dc,bc,builds' to see lists of each of the types described above.")
fmt.Fprintln(out, "\nTo see more information about a service or deployment, use 'osc describe service <name>' or 'osc describe dc <name>'.")
fmt.Fprintln(out, "You can use 'osc get all' to see lists of each of the types described above.")
}

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

for i, deployment := range deployments {
out = append(out, describeDeploymentStatus(deployment))
out = append(out, describeDeploymentStatus(deployment, i == 0))

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

func describeDeploymentStatus(deploy *kapi.ReplicationController) string {
func describeDeploymentStatus(deploy *kapi.ReplicationController, first bool) string {
timeAt := strings.ToLower(formatRelativeTime(deploy.CreationTimestamp.Time))
status := deployutil.DeploymentStatusFor(deploy)
version := deployutil.DeploymentVersionFor(deploy)
switch status {
case deployapi.DeploymentStatusFailed:
reason := deployutil.DeploymentStatusReasonFor(deploy)
if len(reason) > 0 {
reason = fmt.Sprintf(": %s", reason)
}
// TODO: encode fail time in the rc
return fmt.Sprintf("#%d deployment failed %s ago", version, timeAt)
return fmt.Sprintf("#%d deployment failed %s ago%s%s", version, timeAt, reason, describeDeploymentPodSummaryInline(deploy, false))
case deployapi.DeploymentStatusComplete:
// TODO: pod status output
return fmt.Sprintf("#%d deployed %s ago", version, timeAt)
return fmt.Sprintf("#%d deployed %s ago%s", version, timeAt, describeDeploymentPodSummaryInline(deploy, first))
case deployapi.DeploymentStatusRunning:
return fmt.Sprintf("#%d deployment running for %s%s", version, timeAt, describeDeploymentPodSummaryInline(deploy, false))
default:
return fmt.Sprintf("#%d deployment %s %s ago", version, strings.ToLower(string(status)), timeAt)
return fmt.Sprintf("#%d deployment %s %s ago%s", version, strings.ToLower(string(status)), timeAt, describeDeploymentPodSummaryInline(deploy, false))
}
}

func describeDeploymentPodSummaryInline(deploy *kapi.ReplicationController, includeEmpty bool) string {
s := describeDeploymentPodSummary(deploy, includeEmpty)
if len(s) == 0 {
return s
}
change := ""
if changing, ok := deployutil.DeploymentDesiredReplicas(deploy); ok {
switch {
case changing < deploy.Spec.Replicas:
change = fmt.Sprintf(" reducing to %d", changing)
case changing > deploy.Spec.Replicas:
change = fmt.Sprintf(" growing to %d", changing)
}
}
return fmt.Sprintf(" - %s%s", s, change)
}

func describeDeploymentPodSummary(deploy *kapi.ReplicationController, includeEmpty bool) string {
actual, requested := deploy.Status.Replicas, deploy.Spec.Replicas
if actual == requested {
switch {
case actual == 0:
if !includeEmpty {
return ""
}
return "0 pods"
case actual > 1:
return fmt.Sprintf("%d pods", actual)
default:
return "1 pod"
}
}
return fmt.Sprintf("%d/%d pods", actual, requested)
}

func describeDeploymentConfigTriggers(config *deployapi.DeploymentConfig) (string, bool) {
Expand Down
4 changes: 3 additions & 1 deletion pkg/cmd/cli/describe/projectstatus_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ func TestProjectStatus(t *testing.T) {
"database deploys",
"frontend deploys",
"with docker.io/openshift/ruby-20-centos7:latest",
"#2 deployment failed less than a second ago: unable to contact server - 0/1 pods",
"#2 deployment running for 7 seconds - 2/1 pods",
"#1 deployed 8 seconds ago",
"#1 deployed less than a second ago",
"To see more information",
Expand Down Expand Up @@ -176,6 +178,6 @@ func TestProjectStatus(t *testing.T) {
t.Errorf("%s: did not have %q:\n%s\n---", k, s, out)
}
}
//t.Logf("\n%s", out)
t.Logf("\n%s", out)
}
}
2 changes: 1 addition & 1 deletion pkg/deploy/controller/deployerpod/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func pollPods(deploymentStore cache.Store, kClient kclient.Interface) (cache.Enu
if kerrors.IsNotFound(err) {
nextStatus := deployapi.DeploymentStatusFailed
deployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(nextStatus)
deployment.Annotations[deployapi.DeploymentStatusReasonAnnotation] = fmt.Sprintf("Couldn't find pod %s for deployment %s", podID, deployment.Name)
deployment.Annotations[deployapi.DeploymentStatusReasonAnnotation] = fmt.Sprintf("deployment process pod %q was deleted before completion", podID)

if _, err := kClient.ReplicationControllers(deployment.Namespace).Update(deployment); err != nil {
glog.Errorf("couldn't update deployment %s to status %s: %v", deployutil.LabelForDeployment(deployment), nextStatus, err)
Expand Down
25 changes: 22 additions & 3 deletions pkg/deploy/util/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@ import (
deployv3 "github.com/openshift/origin/pkg/deploy/api/v1beta3"
)

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

func DeploymentStatusReasonFor(obj runtime.Object) string {
return mappedAnnotationFor(obj, deployapi.DeploymentStatusReasonAnnotation)
}

func DeploymentDesiredReplicas(obj runtime.Object) (int, bool) {
s := mappedAnnotationFor(obj, deployapi.DesiredReplicasAnnotation)
if len(s) == 0 {
return 0, false
}
i, err := strconv.Atoi(s)
if err != nil {
return 0, false
}
return i, true
}

func EncodedDeploymentConfigFor(obj runtime.Object) string {
return mappedAnnotationFor(obj, deployapi.DeploymentEncodedConfigAnnotation)
}
Expand All @@ -239,10 +256,12 @@ func mappedAnnotationFor(obj runtime.Object, key string) string {
return ""
}
for _, mappedKey := range annotationMap[key] {
val, hasVal := meta.Annotations[mappedKey]
if hasVal {
if val, ok := meta.Annotations[mappedKey]; ok {
return val
}
}
if val, ok := meta.Annotations[key]; ok {
return val
}
return ""
}
139 changes: 138 additions & 1 deletion test/fixtures/app-scenarios/new-project-deployed-app.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,76 @@ items:
type: STI
startTimestamp: 2015-04-07T04:12:21Z
status: Complete
- annotations:
deploymentConfig: database
deploymentStatus: Running
deploymentVersion: "2"
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"}]}}'
pod: deploy-database-19m1he
apiVersion: v1beta1
creationTimestamp: 2015-04-07T04:12:18Z
currentState:
podTemplate:
desiredState:
manifest:
containers: null
id: ""
restartPolicy: {}
version: ""
volumes: null
replicas: 2
desiredState:
podTemplate:
annotations:
deployment: database-2
deploymentConfig: database
deploymentVersion: "2"
desiredState:
manifest:
containers:
- capabilities: {}
env:
- key: MYSQL_USER
name: MYSQL_USER
value: user1CY
- key: MYSQL_PASSWORD
name: MYSQL_PASSWORD
value: FfyXmsGG
- key: MYSQL_DATABASE
name: MYSQL_DATABASE
value: root
image: openshift/mysql-55-centos7
imagePullPolicy: PullIfNotPresent
name: ruby-helloworld-database
ports:
- containerPort: 3306
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
dnsPolicy: ClusterFirst
id: ""
restartPolicy:
always: {}
version: v1beta2
volumes: null
labels:
deployment: database-2
deploymentconfig: database
name: database
template: application-template-stibuild
replicaSelector:
deployment: database-2
deploymentconfig: database
name: database
replicas: 1
id: database-2
kind: ReplicationController
labels:
template: application-template-stibuild
namespace: example
resourceVersion: 318
selfLink: /api/v1beta1/replicationControllers/database-1?namespace=example
uid: 473d4a73-dcdc-11e4-968a-080027c5bfa9
- annotations:
deploymentConfig: database
deploymentStatus: Complete
Expand Down Expand Up @@ -201,6 +271,73 @@ items:
type: Recreate
triggers:
- type: ConfigChange
- annotations:
deploymentConfig: frontend
deploymentStatus: Failed
openshift.io/deployment.status-reason: unable to contact server
deploymentVersion: "2"
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"}}]}}'
pod: deploy-frontend-17mza9
apiVersion: v1beta1
creationTimestamp: 2015-04-07T04:12:53Z
desiredState:
podTemplate:
annotations:
deployment: frontend-2
deploymentConfig: frontend
deploymentVersion: "2"
desiredState:
manifest:
containers:
- capabilities: {}
env:
- key: ADMIN_USERNAME
name: ADMIN_USERNAME
value: adminNPX
- key: ADMIN_PASSWORD
name: ADMIN_PASSWORD
value: 7q1IdEao
- key: MYSQL_USER
name: MYSQL_USER
value: user1CY
- key: MYSQL_PASSWORD
name: MYSQL_PASSWORD
value: FfyXmsGG
- key: MYSQL_DATABASE
name: MYSQL_DATABASE
value: root
image: 172.30.17.139:5000/test/origin-ruby-sample:73214fafa244cb8abbe55273dac5d237a589a5fc7ac09926a1756a42c21e8a58
imagePullPolicy: PullIfNotPresent
name: ruby-helloworld
ports:
- containerPort: 8080
protocol: TCP
resources: {}
terminationMessagePath: /dev/termination-log
dnsPolicy: ClusterFirst
id: ""
restartPolicy:
always: {}
version: v1beta2
volumes: null
labels:
deployment: frontend-2
deploymentconfig: frontend
name: frontend
template: application-template-stibuild
replicaSelector:
deployment: frontend-2
deploymentconfig: frontend
name: frontend
replicas: 1
id: frontend-2
kind: ReplicationController
labels:
template: application-template-stibuild
namespace: example
resourceVersion: 379
selfLink: /api/v1beta1/replicationControllers/frontend-2?namespace=example
uid: 5c9cd4ec-dcdc-11e4-968a-080027c5bfa9
- annotations:
deploymentConfig: frontend
deploymentStatus: Complete
Expand Down Expand Up @@ -285,7 +422,7 @@ items:
tag: latest
type: ImageChange
kind: DeploymentConfig
latestVersion: 1
latestVersion: 3
metadata:
creationTimestamp: 2015-04-07T04:12:17Z
labels:
Expand Down

0 comments on commit 4f56890

Please sign in to comment.