| 1 | 1 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,130 @@ |
| 0 |
+apiVersion: v1 |
|
| 1 |
+items: |
|
| 2 |
+- apiVersion: v1 |
|
| 3 |
+ kind: DeploymentConfig |
|
| 4 |
+ metadata: |
|
| 5 |
+ name: example |
|
| 6 |
+ spec: |
|
| 7 |
+ replicas: 3 |
|
| 8 |
+ selector: |
|
| 9 |
+ name: example |
|
| 10 |
+ strategy: |
|
| 11 |
+ type: Rolling |
|
| 12 |
+ template: |
|
| 13 |
+ metadata: |
|
| 14 |
+ labels: |
|
| 15 |
+ name: example |
|
| 16 |
+ spec: |
|
| 17 |
+ containers: |
|
| 18 |
+ - command: |
|
| 19 |
+ - /bin/sleep |
|
| 20 |
+ - "100" |
|
| 21 |
+ image: docker.io/centos:centos7 |
|
| 22 |
+ name: myapp |
|
| 23 |
+ test: false |
|
| 24 |
+ triggers: |
|
| 25 |
+ - type: ConfigChange |
|
| 26 |
+ status: |
|
| 27 |
+ availableReplicas: 1 |
|
| 28 |
+ details: |
|
| 29 |
+ causes: |
|
| 30 |
+ - type: ConfigChange |
|
| 31 |
+ message: config change |
|
| 32 |
+ latestVersion: 2 |
|
| 33 |
+ replicas: 3 |
|
| 34 |
+ updatedReplicas: 2 |
|
| 35 |
+- apiVersion: v1 |
|
| 36 |
+ kind: ReplicationController |
|
| 37 |
+ metadata: |
|
| 38 |
+ annotations: |
|
| 39 |
+ openshift.io/deployer-pod.name: example-1-deploy |
|
| 40 |
+ openshift.io/deployment-config.latest-version: "1" |
|
| 41 |
+ openshift.io/deployment-config.name: example |
|
| 42 |
+ openshift.io/deployment.phase: Complete |
|
| 43 |
+ openshift.io/deployment.replicas: "1" |
|
| 44 |
+ openshift.io/deployment.status-reason: config change |
|
| 45 |
+ openshift.io/encoded-deployment-config: | |
|
| 46 |
+ {"kind":"DeploymentConfig","apiVersion":"v1","metadata":{"name":"example","namespace":"myproject","selfLink":"/oapi/v1/namespaces/myproject/deploymentconfigs/example","uid":"6d298d51-9486-11e6-b581-080027242396","resourceVersion":"1173","generation":2,"creationTimestamp":"2016-10-17T16:26:15Z"},"spec":{"strategy":{"type":"Rolling","rollingParams":{"updatePeriodSeconds":1,"intervalSeconds":1,"timeoutSeconds":600,"maxUnavailable":"25%","maxSurge":"25%","pre":{"failurePolicy":"Abort","execNewPod":{"command":["/bin/echo","test pre hook executed"],"containerName":"myapp"}}},"resources":{}},"triggers":[{"type":"ConfigChange"}],"replicas":1,"test":false,"selector":{"name":"example"},"template":{"metadata":{"creationTimestamp":null,"labels":{"name":"example"}},"spec":{"containers":[{"name":"myapp","image":"docker.io/centos:centos7","command":["/bin/sleep","100"],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","securityContext":{}}}},"status":{"latestVersion":1,"observedGeneration":1,"details":{"message":"config change","causes":[{"type":"ConfigChange"}]},"conditions":[{"type":"Available","status":"False","lastTransitionTime":"2016-10-17T16:26:15Z","message":"Deployment config does not have minimum availability."}]}}
|
|
| 47 |
+ creationTimestamp: 2016-04-07T04:11:25Z |
|
| 48 |
+ generation: 2 |
|
| 49 |
+ labels: |
|
| 50 |
+ openshift.io/deployment-config.name: example |
|
| 51 |
+ name: example-1 |
|
| 52 |
+ spec: |
|
| 53 |
+ replicas: 2 |
|
| 54 |
+ selector: |
|
| 55 |
+ deployment: example-1 |
|
| 56 |
+ deploymentconfig: example |
|
| 57 |
+ name: example |
|
| 58 |
+ template: |
|
| 59 |
+ metadata: |
|
| 60 |
+ annotations: |
|
| 61 |
+ openshift.io/deployment-config.latest-version: "1" |
|
| 62 |
+ openshift.io/deployment-config.name: example |
|
| 63 |
+ openshift.io/deployment.name: example-1 |
|
| 64 |
+ creationTimestamp: null |
|
| 65 |
+ labels: |
|
| 66 |
+ deployment: example-1 |
|
| 67 |
+ deploymentconfig: example |
|
| 68 |
+ name: example |
|
| 69 |
+ spec: |
|
| 70 |
+ containers: |
|
| 71 |
+ - command: |
|
| 72 |
+ - /bin/sleep |
|
| 73 |
+ - "100" |
|
| 74 |
+ image: docker.io/centos:centos7 |
|
| 75 |
+ imagePullPolicy: IfNotPresent |
|
| 76 |
+ name: myapp |
|
| 77 |
+ status: |
|
| 78 |
+ fullyLabeledReplicas: 2 |
|
| 79 |
+ observedGeneration: 2 |
|
| 80 |
+ readyReplicas: 1 |
|
| 81 |
+ replicas: 2 |
|
| 82 |
+- apiVersion: v1 |
|
| 83 |
+ kind: ReplicationController |
|
| 84 |
+ metadata: |
|
| 85 |
+ annotations: |
|
| 86 |
+ openshift.io/deployer-pod.name: example-2-deploy |
|
| 87 |
+ openshift.io/deployment-config.latest-version: "2" |
|
| 88 |
+ openshift.io/deployment-config.name: example |
|
| 89 |
+ openshift.io/deployment.phase: Running |
|
| 90 |
+ openshift.io/deployment.replicas: "3" |
|
| 91 |
+ openshift.io/deployment.status-reason: manual change |
|
| 92 |
+ openshift.io/encoded-deployment-config: | |
|
| 93 |
+ {"kind":"DeploymentConfig","apiVersion":"v1","metadata":{"name":"example","namespace":"myproject","selfLink":"/oapi/v1/namespaces/myproject/deploymentconfigs/example","uid":"6d298d51-9486-11e6-b581-080027242396","resourceVersion":"1314","generation":5,"creationTimestamp":"2016-10-17T16:26:15Z"},"spec":{"strategy":{"type":"Rolling","rollingParams":{"updatePeriodSeconds":1,"intervalSeconds":1,"timeoutSeconds":600,"maxUnavailable":"25%","maxSurge":"25%"},"resources":{}},"triggers":[{"type":"ConfigChange"}],"replicas":3,"test":false,"selector":{"name":"example"},"template":{"metadata":{"creationTimestamp":null,"labels":{"name":"example"}},"spec":{"containers":[{"name":"myapp","image":"docker.io/centos:centos7","command":["/bin/sleep","100"],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","terminationGracePeriodSeconds":30,"dnsPolicy":"ClusterFirst","securityContext":{}}}},"status":{"latestVersion":2,"observedGeneration":4,"replicas":3,"updatedReplicas":3,"availableReplicas":2,"unavailableReplicas":1,"details":{"message":"manual change","causes":[{"type":"Manual"}]},"conditions":[{"type":"Available","status":"False","lastTransitionTime":"2016-10-17T16:29:55Z","message":"Deployment config does not have minimum availability."},{"type":"Progressing","status":"True","lastTransitionTime":"2016-10-17T16:29:55Z","reason":"NewReplicationControllerAvailable","message":"Replication controller \"example-1\" has completed progressing"}]}}
|
|
| 94 |
+ creationTimestamp: 2016-04-07T04:11:55Z |
|
| 95 |
+ generation: 4 |
|
| 96 |
+ labels: |
|
| 97 |
+ openshift.io/deployment-config.name: example |
|
| 98 |
+ name: example-2 |
|
| 99 |
+ spec: |
|
| 100 |
+ replicas: 1 |
|
| 101 |
+ selector: |
|
| 102 |
+ deployment: example-2 |
|
| 103 |
+ deploymentconfig: example |
|
| 104 |
+ name: example |
|
| 105 |
+ template: |
|
| 106 |
+ metadata: |
|
| 107 |
+ annotations: |
|
| 108 |
+ openshift.io/deployment-config.latest-version: "2" |
|
| 109 |
+ openshift.io/deployment-config.name: example |
|
| 110 |
+ openshift.io/deployment.name: example-2 |
|
| 111 |
+ creationTimestamp: null |
|
| 112 |
+ labels: |
|
| 113 |
+ deployment: example-2 |
|
| 114 |
+ deploymentconfig: example |
|
| 115 |
+ name: example |
|
| 116 |
+ spec: |
|
| 117 |
+ containers: |
|
| 118 |
+ - command: |
|
| 119 |
+ - /bin/sleep |
|
| 120 |
+ - "100" |
|
| 121 |
+ image: docker.io/centos:centos7 |
|
| 122 |
+ imagePullPolicy: IfNotPresent |
|
| 123 |
+ name: myapp |
|
| 124 |
+ status: |
|
| 125 |
+ fullyLabeledReplicas: 1 |
|
| 126 |
+ readyReplicas: 0 |
|
| 127 |
+ replicas: 1 |
|
| 128 |
+kind: List |
|
| 129 |
+metadata: {}
|
| ... | ... |
@@ -130,6 +130,7 @@ items: |
| 130 | 130 |
restartPolicy: Always |
| 131 | 131 |
status: |
| 132 | 132 |
replicas: 2 |
| 133 |
+ readyReplicas: 2 |
|
| 133 | 134 |
- apiVersion: v1 |
| 134 | 135 |
kind: ReplicationController |
| 135 | 136 |
metadata: |
| ... | ... |
@@ -187,6 +188,7 @@ items: |
| 187 | 187 |
restartPolicy: Always |
| 188 | 188 |
status: |
| 189 | 189 |
replicas: 1 |
| 190 |
+ readyReplicas: 1 |
|
| 190 | 191 |
- apiVersion: v1 |
| 191 | 192 |
kind: DeploymentConfig |
| 192 | 193 |
metadata: |
| ... | ... |
@@ -362,6 +364,7 @@ items: |
| 362 | 362 |
restartPolicy: Always |
| 363 | 363 |
status: |
| 364 | 364 |
replicas: 1 |
| 365 |
+ readyReplicas: 1 |
|
| 365 | 366 |
- apiVersion: v1 |
| 366 | 367 |
kind: DeploymentConfig |
| 367 | 368 |
metadata: |
| ... | ... |
@@ -1013,52 +1013,53 @@ func describeDeployments(f formatter, dcNode *deploygraph.DeploymentConfigNode, |
| 1013 | 1013 |
return out |
| 1014 | 1014 |
} |
| 1015 | 1015 |
|
| 1016 |
-func describeDeploymentStatus(deploy *kapi.ReplicationController, first, test bool, restartCount int32) string {
|
|
| 1017 |
- timeAt := strings.ToLower(formatRelativeTime(deploy.CreationTimestamp.Time)) |
|
| 1018 |
- status := deployutil.DeploymentStatusFor(deploy) |
|
| 1019 |
- version := deployutil.DeploymentVersionFor(deploy) |
|
| 1016 |
+func describeDeploymentStatus(rc *kapi.ReplicationController, first, test bool, restartCount int32) string {
|
|
| 1017 |
+ timeAt := strings.ToLower(formatRelativeTime(rc.CreationTimestamp.Time)) |
|
| 1018 |
+ status := deployutil.DeploymentStatusFor(rc) |
|
| 1019 |
+ version := deployutil.DeploymentVersionFor(rc) |
|
| 1020 | 1020 |
maybeCancelling := "" |
| 1021 |
- if deployutil.IsDeploymentCancelled(deploy) && !deployutil.IsTerminatedDeployment(deploy) {
|
|
| 1021 |
+ if deployutil.IsDeploymentCancelled(rc) && !deployutil.IsTerminatedDeployment(rc) {
|
|
| 1022 | 1022 |
maybeCancelling = " (cancelling)" |
| 1023 | 1023 |
} |
| 1024 | 1024 |
|
| 1025 | 1025 |
switch status {
|
| 1026 | 1026 |
case deployapi.DeploymentStatusFailed: |
| 1027 |
- reason := deployutil.DeploymentStatusReasonFor(deploy) |
|
| 1027 |
+ reason := deployutil.DeploymentStatusReasonFor(rc) |
|
| 1028 | 1028 |
if len(reason) > 0 {
|
| 1029 | 1029 |
reason = fmt.Sprintf(": %s", reason)
|
| 1030 | 1030 |
} |
| 1031 | 1031 |
// TODO: encode fail time in the rc |
| 1032 |
- return fmt.Sprintf("deployment #%d failed %s ago%s%s", version, timeAt, reason, describePodSummaryInline(deploy.Status.Replicas, deploy.Spec.Replicas, false, restartCount))
|
|
| 1032 |
+ return fmt.Sprintf("deployment #%d failed %s ago%s%s", version, timeAt, reason, describePodSummaryInline(rc.Status.ReadyReplicas, rc.Status.Replicas, rc.Spec.Replicas, false, restartCount))
|
|
| 1033 | 1033 |
case deployapi.DeploymentStatusComplete: |
| 1034 | 1034 |
// TODO: pod status output |
| 1035 | 1035 |
if test {
|
| 1036 | 1036 |
return fmt.Sprintf("test deployment #%d deployed %s ago", version, timeAt)
|
| 1037 | 1037 |
} |
| 1038 |
- return fmt.Sprintf("deployment #%d deployed %s ago%s", version, timeAt, describePodSummaryInline(deploy.Status.Replicas, deploy.Spec.Replicas, first, restartCount))
|
|
| 1038 |
+ return fmt.Sprintf("deployment #%d deployed %s ago%s", version, timeAt, describePodSummaryInline(rc.Status.ReadyReplicas, rc.Status.Replicas, rc.Spec.Replicas, first, restartCount))
|
|
| 1039 | 1039 |
case deployapi.DeploymentStatusRunning: |
| 1040 | 1040 |
format := "deployment #%d running%s for %s%s" |
| 1041 | 1041 |
if test {
|
| 1042 | 1042 |
format = "test deployment #%d running%s for %s%s" |
| 1043 | 1043 |
} |
| 1044 |
- return fmt.Sprintf(format, version, maybeCancelling, timeAt, describePodSummaryInline(deploy.Status.Replicas, deploy.Spec.Replicas, false, restartCount)) |
|
| 1044 |
+ return fmt.Sprintf(format, version, maybeCancelling, timeAt, describePodSummaryInline(rc.Status.ReadyReplicas, rc.Status.Replicas, rc.Spec.Replicas, false, restartCount)) |
|
| 1045 | 1045 |
default: |
| 1046 |
- return fmt.Sprintf("deployment #%d %s%s %s ago%s", version, strings.ToLower(string(status)), maybeCancelling, timeAt, describePodSummaryInline(deploy.Status.Replicas, deploy.Spec.Replicas, false, restartCount))
|
|
| 1046 |
+ return fmt.Sprintf("deployment #%d %s%s %s ago%s", version, strings.ToLower(string(status)), maybeCancelling, timeAt, describePodSummaryInline(rc.Status.ReadyReplicas, rc.Status.Replicas, rc.Spec.Replicas, false, restartCount))
|
|
| 1047 | 1047 |
} |
| 1048 | 1048 |
} |
| 1049 | 1049 |
|
| 1050 | 1050 |
func describePetSetStatus(p *kapps.PetSet) string {
|
| 1051 | 1051 |
timeAt := strings.ToLower(formatRelativeTime(p.CreationTimestamp.Time)) |
| 1052 |
- return fmt.Sprintf("created %s ago%s", timeAt, describePodSummaryInline(int32(p.Status.Replicas), int32(p.Spec.Replicas), false, 0))
|
|
| 1052 |
+ // TODO: Replace first argument in describePodSummaryInline with ReadyReplicas once that's a thing for pet sets. |
|
| 1053 |
+ return fmt.Sprintf("created %s ago%s", timeAt, describePodSummaryInline(int32(p.Status.Replicas), int32(p.Status.Replicas), int32(p.Spec.Replicas), false, 0))
|
|
| 1053 | 1054 |
} |
| 1054 | 1055 |
|
| 1055 | 1056 |
func describeRCStatus(rc *kapi.ReplicationController) string {
|
| 1056 | 1057 |
timeAt := strings.ToLower(formatRelativeTime(rc.CreationTimestamp.Time)) |
| 1057 |
- return fmt.Sprintf("rc/%s created %s ago%s", rc.Name, timeAt, describePodSummaryInline(rc.Status.Replicas, rc.Spec.Replicas, false, 0))
|
|
| 1058 |
+ return fmt.Sprintf("rc/%s created %s ago%s", rc.Name, timeAt, describePodSummaryInline(rc.Status.ReadyReplicas, rc.Status.Replicas, rc.Spec.Replicas, false, 0))
|
|
| 1058 | 1059 |
} |
| 1059 | 1060 |
|
| 1060 |
-func describePodSummaryInline(actual, requested int32, includeEmpty bool, restartCount int32) string {
|
|
| 1061 |
- s := describePodSummary(actual, requested, includeEmpty, restartCount) |
|
| 1061 |
+func describePodSummaryInline(ready, actual, requested int32, includeEmpty bool, restartCount int32) string {
|
|
| 1062 |
+ s := describePodSummary(ready, requested, includeEmpty, restartCount) |
|
| 1062 | 1063 |
if len(s) == 0 {
|
| 1063 | 1064 |
return s |
| 1064 | 1065 |
} |
| ... | ... |
@@ -1072,25 +1073,25 @@ func describePodSummaryInline(actual, requested int32, includeEmpty bool, restar |
| 1072 | 1072 |
return fmt.Sprintf(" - %s%s", s, change)
|
| 1073 | 1073 |
} |
| 1074 | 1074 |
|
| 1075 |
-func describePodSummary(actual, requested int32, includeEmpty bool, restartCount int32) string {
|
|
| 1075 |
+func describePodSummary(ready, requested int32, includeEmpty bool, restartCount int32) string {
|
|
| 1076 | 1076 |
var restartWarn string |
| 1077 | 1077 |
if restartCount > 0 {
|
| 1078 | 1078 |
restartWarn = fmt.Sprintf(" (warning: %d restarts)", restartCount)
|
| 1079 | 1079 |
} |
| 1080 |
- if actual == requested {
|
|
| 1080 |
+ if ready == requested {
|
|
| 1081 | 1081 |
switch {
|
| 1082 |
- case actual == 0: |
|
| 1082 |
+ case ready == 0: |
|
| 1083 | 1083 |
if !includeEmpty {
|
| 1084 | 1084 |
return "" |
| 1085 | 1085 |
} |
| 1086 | 1086 |
return "0 pods" |
| 1087 |
- case actual > 1: |
|
| 1088 |
- return fmt.Sprintf("%d pods", actual) + restartWarn
|
|
| 1087 |
+ case ready > 1: |
|
| 1088 |
+ return fmt.Sprintf("%d pods", ready) + restartWarn
|
|
| 1089 | 1089 |
default: |
| 1090 | 1090 |
return "1 pod" + restartWarn |
| 1091 | 1091 |
} |
| 1092 | 1092 |
} |
| 1093 |
- return fmt.Sprintf("%d/%d pods", actual, requested) + restartWarn
|
|
| 1093 |
+ return fmt.Sprintf("%d/%d pods", ready, requested) + restartWarn
|
|
| 1094 | 1094 |
} |
| 1095 | 1095 |
|
| 1096 | 1096 |
func describeDeploymentConfigTriggers(config *deployapi.DeploymentConfig) (string, bool) {
|
| ... | ... |
@@ -367,6 +367,20 @@ func TestProjectStatus(t *testing.T) {
|
| 367 | 367 |
`View details with 'oc describe <resource>/<name>' or list everything with 'oc get all'.`, |
| 368 | 368 |
}, |
| 369 | 369 |
}, |
| 370 |
+ "deployment with unavailable pods": {
|
|
| 371 |
+ File: "available-deployment.yaml", |
|
| 372 |
+ Extra: []runtime.Object{
|
|
| 373 |
+ &projectapi.Project{
|
|
| 374 |
+ ObjectMeta: kapi.ObjectMeta{Name: "example", Namespace: ""},
|
|
| 375 |
+ }, |
|
| 376 |
+ }, |
|
| 377 |
+ ErrFn: func(err error) bool { return err == nil },
|
|
| 378 |
+ Contains: []string{
|
|
| 379 |
+ "deployment #2 running for 30 seconds - 0/1 pods\n", |
|
| 380 |
+ "deployment #1 deployed about a minute ago - 1/2 pods", |
|
| 381 |
+ }, |
|
| 382 |
+ Time: mustParseTime("2016-04-07T04:12:25Z"),
|
|
| 383 |
+ }, |
|
| 370 | 384 |
} |
| 371 | 385 |
oldTimeFn := timeNowFn |
| 372 | 386 |
defer func() { timeNowFn = oldTimeFn }()
|