Browse code

Merge pull request #9874 from kargakis/rollout-status

Merged by openshift-bot

OpenShift Bot authored on 2016/10/13 23:54:59
Showing 21 changed files
... ...
@@ -11653,6 +11653,61 @@ _oc_rollout_resume()
11653 11653
     noun_aliases+=("deployments")
11654 11654
 }
11655 11655
 
11656
+_oc_rollout_status()
11657
+{
11658
+    last_command="oc_rollout_status"
11659
+    commands=()
11660
+
11661
+    flags=()
11662
+    two_word_flags=()
11663
+    local_nonpersistent_flags=()
11664
+    flags_with_completion=()
11665
+    flags_completion=()
11666
+
11667
+    flags+=("--filename=")
11668
+    flags_with_completion+=("--filename")
11669
+    flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
11670
+    two_word_flags+=("-f")
11671
+    flags_with_completion+=("-f")
11672
+    flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
11673
+    local_nonpersistent_flags+=("--filename=")
11674
+    flags+=("--recursive")
11675
+    flags+=("-R")
11676
+    local_nonpersistent_flags+=("--recursive")
11677
+    flags+=("--as=")
11678
+    flags+=("--certificate-authority=")
11679
+    flags_with_completion+=("--certificate-authority")
11680
+    flags_completion+=("_filedir")
11681
+    flags+=("--client-certificate=")
11682
+    flags_with_completion+=("--client-certificate")
11683
+    flags_completion+=("_filedir")
11684
+    flags+=("--client-key=")
11685
+    flags_with_completion+=("--client-key")
11686
+    flags_completion+=("_filedir")
11687
+    flags+=("--cluster=")
11688
+    flags+=("--config=")
11689
+    flags_with_completion+=("--config")
11690
+    flags_completion+=("_filedir")
11691
+    flags+=("--context=")
11692
+    flags+=("--insecure-skip-tls-verify")
11693
+    flags+=("--log-flush-frequency=")
11694
+    flags+=("--loglevel=")
11695
+    flags+=("--logspec=")
11696
+    flags+=("--match-server-version")
11697
+    flags+=("--namespace=")
11698
+    two_word_flags+=("-n")
11699
+    flags+=("--server=")
11700
+    flags+=("--token=")
11701
+    flags+=("--user=")
11702
+
11703
+    must_have_one_flag=()
11704
+    must_have_one_noun=()
11705
+    must_have_one_noun+=("deployment")
11706
+    noun_aliases=()
11707
+    noun_aliases+=("deploy")
11708
+    noun_aliases+=("deployments")
11709
+}
11710
+
11656 11711
 _oc_rollout_undo()
11657 11712
 {
11658 11713
     last_command="oc_rollout_undo"
... ...
@@ -11719,6 +11774,7 @@ _oc_rollout()
11719 11719
     commands+=("latest")
11720 11720
     commands+=("pause")
11721 11721
     commands+=("resume")
11722
+    commands+=("status")
11722 11723
     commands+=("undo")
11723 11724
 
11724 11725
     flags=()
... ...
@@ -16217,6 +16217,62 @@ _openshift_cli_rollout_resume()
16217 16217
     noun_aliases+=("deployments")
16218 16218
 }
16219 16219
 
16220
+_openshift_cli_rollout_status()
16221
+{
16222
+    last_command="openshift_cli_rollout_status"
16223
+    commands=()
16224
+
16225
+    flags=()
16226
+    two_word_flags=()
16227
+    local_nonpersistent_flags=()
16228
+    flags_with_completion=()
16229
+    flags_completion=()
16230
+
16231
+    flags+=("--filename=")
16232
+    flags_with_completion+=("--filename")
16233
+    flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
16234
+    two_word_flags+=("-f")
16235
+    flags_with_completion+=("-f")
16236
+    flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
16237
+    local_nonpersistent_flags+=("--filename=")
16238
+    flags+=("--recursive")
16239
+    flags+=("-R")
16240
+    local_nonpersistent_flags+=("--recursive")
16241
+    flags+=("--as=")
16242
+    flags+=("--certificate-authority=")
16243
+    flags_with_completion+=("--certificate-authority")
16244
+    flags_completion+=("_filedir")
16245
+    flags+=("--client-certificate=")
16246
+    flags_with_completion+=("--client-certificate")
16247
+    flags_completion+=("_filedir")
16248
+    flags+=("--client-key=")
16249
+    flags_with_completion+=("--client-key")
16250
+    flags_completion+=("_filedir")
16251
+    flags+=("--cluster=")
16252
+    flags+=("--config=")
16253
+    flags_with_completion+=("--config")
16254
+    flags_completion+=("_filedir")
16255
+    flags+=("--context=")
16256
+    flags+=("--google-json-key=")
16257
+    flags+=("--insecure-skip-tls-verify")
16258
+    flags+=("--log-flush-frequency=")
16259
+    flags+=("--loglevel=")
16260
+    flags+=("--logspec=")
16261
+    flags+=("--match-server-version")
16262
+    flags+=("--namespace=")
16263
+    two_word_flags+=("-n")
16264
+    flags+=("--server=")
16265
+    flags+=("--token=")
16266
+    flags+=("--user=")
16267
+
16268
+    must_have_one_flag=()
16269
+    must_have_one_noun=()
16270
+    must_have_one_noun+=("deployment")
16271
+    noun_aliases=()
16272
+    noun_aliases+=("deploy")
16273
+    noun_aliases+=("deployments")
16274
+}
16275
+
16220 16276
 _openshift_cli_rollout_undo()
16221 16277
 {
16222 16278
     last_command="openshift_cli_rollout_undo"
... ...
@@ -16284,6 +16340,7 @@ _openshift_cli_rollout()
16284 16284
     commands+=("latest")
16285 16285
     commands+=("pause")
16286 16286
     commands+=("resume")
16287
+    commands+=("status")
16287 16288
     commands+=("undo")
16288 16289
 
16289 16290
     flags=()
... ...
@@ -11814,6 +11814,61 @@ _oc_rollout_resume()
11814 11814
     noun_aliases+=("deployments")
11815 11815
 }
11816 11816
 
11817
+_oc_rollout_status()
11818
+{
11819
+    last_command="oc_rollout_status"
11820
+    commands=()
11821
+
11822
+    flags=()
11823
+    two_word_flags=()
11824
+    local_nonpersistent_flags=()
11825
+    flags_with_completion=()
11826
+    flags_completion=()
11827
+
11828
+    flags+=("--filename=")
11829
+    flags_with_completion+=("--filename")
11830
+    flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
11831
+    two_word_flags+=("-f")
11832
+    flags_with_completion+=("-f")
11833
+    flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
11834
+    local_nonpersistent_flags+=("--filename=")
11835
+    flags+=("--recursive")
11836
+    flags+=("-R")
11837
+    local_nonpersistent_flags+=("--recursive")
11838
+    flags+=("--as=")
11839
+    flags+=("--certificate-authority=")
11840
+    flags_with_completion+=("--certificate-authority")
11841
+    flags_completion+=("_filedir")
11842
+    flags+=("--client-certificate=")
11843
+    flags_with_completion+=("--client-certificate")
11844
+    flags_completion+=("_filedir")
11845
+    flags+=("--client-key=")
11846
+    flags_with_completion+=("--client-key")
11847
+    flags_completion+=("_filedir")
11848
+    flags+=("--cluster=")
11849
+    flags+=("--config=")
11850
+    flags_with_completion+=("--config")
11851
+    flags_completion+=("_filedir")
11852
+    flags+=("--context=")
11853
+    flags+=("--insecure-skip-tls-verify")
11854
+    flags+=("--log-flush-frequency=")
11855
+    flags+=("--loglevel=")
11856
+    flags+=("--logspec=")
11857
+    flags+=("--match-server-version")
11858
+    flags+=("--namespace=")
11859
+    two_word_flags+=("-n")
11860
+    flags+=("--server=")
11861
+    flags+=("--token=")
11862
+    flags+=("--user=")
11863
+
11864
+    must_have_one_flag=()
11865
+    must_have_one_noun=()
11866
+    must_have_one_noun+=("deployment")
11867
+    noun_aliases=()
11868
+    noun_aliases+=("deploy")
11869
+    noun_aliases+=("deployments")
11870
+}
11871
+
11817 11872
 _oc_rollout_undo()
11818 11873
 {
11819 11874
     last_command="oc_rollout_undo"
... ...
@@ -11880,6 +11935,7 @@ _oc_rollout()
11880 11880
     commands+=("latest")
11881 11881
     commands+=("pause")
11882 11882
     commands+=("resume")
11883
+    commands+=("status")
11883 11884
     commands+=("undo")
11884 11885
 
11885 11886
     flags=()
... ...
@@ -16378,6 +16378,62 @@ _openshift_cli_rollout_resume()
16378 16378
     noun_aliases+=("deployments")
16379 16379
 }
16380 16380
 
16381
+_openshift_cli_rollout_status()
16382
+{
16383
+    last_command="openshift_cli_rollout_status"
16384
+    commands=()
16385
+
16386
+    flags=()
16387
+    two_word_flags=()
16388
+    local_nonpersistent_flags=()
16389
+    flags_with_completion=()
16390
+    flags_completion=()
16391
+
16392
+    flags+=("--filename=")
16393
+    flags_with_completion+=("--filename")
16394
+    flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
16395
+    two_word_flags+=("-f")
16396
+    flags_with_completion+=("-f")
16397
+    flags_completion+=("__handle_filename_extension_flag json|yaml|yml")
16398
+    local_nonpersistent_flags+=("--filename=")
16399
+    flags+=("--recursive")
16400
+    flags+=("-R")
16401
+    local_nonpersistent_flags+=("--recursive")
16402
+    flags+=("--as=")
16403
+    flags+=("--certificate-authority=")
16404
+    flags_with_completion+=("--certificate-authority")
16405
+    flags_completion+=("_filedir")
16406
+    flags+=("--client-certificate=")
16407
+    flags_with_completion+=("--client-certificate")
16408
+    flags_completion+=("_filedir")
16409
+    flags+=("--client-key=")
16410
+    flags_with_completion+=("--client-key")
16411
+    flags_completion+=("_filedir")
16412
+    flags+=("--cluster=")
16413
+    flags+=("--config=")
16414
+    flags_with_completion+=("--config")
16415
+    flags_completion+=("_filedir")
16416
+    flags+=("--context=")
16417
+    flags+=("--google-json-key=")
16418
+    flags+=("--insecure-skip-tls-verify")
16419
+    flags+=("--log-flush-frequency=")
16420
+    flags+=("--loglevel=")
16421
+    flags+=("--logspec=")
16422
+    flags+=("--match-server-version")
16423
+    flags+=("--namespace=")
16424
+    two_word_flags+=("-n")
16425
+    flags+=("--server=")
16426
+    flags+=("--token=")
16427
+    flags+=("--user=")
16428
+
16429
+    must_have_one_flag=()
16430
+    must_have_one_noun=()
16431
+    must_have_one_noun+=("deployment")
16432
+    noun_aliases=()
16433
+    noun_aliases+=("deploy")
16434
+    noun_aliases+=("deployments")
16435
+}
16436
+
16381 16437
 _openshift_cli_rollout_undo()
16382 16438
 {
16383 16439
     last_command="openshift_cli_rollout_undo"
... ...
@@ -16445,6 +16501,7 @@ _openshift_cli_rollout()
16445 16445
     commands+=("latest")
16446 16446
     commands+=("pause")
16447 16447
     commands+=("resume")
16448
+    commands+=("status")
16448 16449
     commands+=("undo")
16449 16450
 
16450 16451
     flags=()
... ...
@@ -2245,6 +2245,20 @@ Resume a paused resource
2245 2245
 ====
2246 2246
 
2247 2247
 
2248
+== oc rollout status
2249
+Watch rollout status until it's done
2250
+
2251
+====
2252
+
2253
+[options="nowrap"]
2254
+----
2255
+  # Watch the status of the latest rollout
2256
+  oc rollout status dc/nginx
2257
+
2258
+----
2259
+====
2260
+
2261
+
2248 2262
 == oc rollout undo
2249 2263
 Undo a previous rollout
2250 2264
 
... ...
@@ -185,6 +185,7 @@ oc-rollout-history.1
185 185
 oc-rollout-latest.1
186 186
 oc-rollout-pause.1
187 187
 oc-rollout-resume.1
188
+oc-rollout-status.1
188 189
 oc-rollout-undo.1
189 190
 oc-rollout.1
190 191
 oc-rsh.1
... ...
@@ -274,6 +274,7 @@ openshift-cli-rollout-history.1
274 274
 openshift-cli-rollout-latest.1
275 275
 openshift-cli-rollout-pause.1
276 276
 openshift-cli-rollout-resume.1
277
+openshift-cli-rollout-status.1
277 278
 openshift-cli-rollout-undo.1
278 279
 openshift-cli-rollout.1
279 280
 openshift-cli-rsh.1
280 281
new file mode 100644
... ...
@@ -0,0 +1,115 @@
0
+.TH "OC ROLLOUT" "1" " Openshift CLI User Manuals" "Openshift" "June 2016"  ""
1
+
2
+
3
+.SH NAME
4
+.PP
5
+oc rollout status \- Watch rollout status until it's done
6
+
7
+
8
+.SH SYNOPSIS
9
+.PP
10
+\fBoc rollout status\fP [OPTIONS]
11
+
12
+
13
+.SH DESCRIPTION
14
+.PP
15
+Watch the status of the latest rollout, until it's done.
16
+
17
+
18
+.SH OPTIONS
19
+.PP
20
+\fB\-f\fP, \fB\-\-filename\fP=[]
21
+    Filename, directory, or URL to a file identifying the resource to get from a server.
22
+
23
+.PP
24
+\fB\-R\fP, \fB\-\-recursive\fP=false
25
+    Process the directory used in \-f, \-\-filename recursively. Useful when you want to manage related manifests organized within the same directory.
26
+
27
+
28
+.SH OPTIONS INHERITED FROM PARENT COMMANDS
29
+.PP
30
+\fB\-\-api\-version\fP=""
31
+    DEPRECATED: The API version to use when talking to the server
32
+
33
+.PP
34
+\fB\-\-as\fP=""
35
+    Username to impersonate for the operation
36
+
37
+.PP
38
+\fB\-\-certificate\-authority\fP=""
39
+    Path to a cert. file for the certificate authority
40
+
41
+.PP
42
+\fB\-\-client\-certificate\fP=""
43
+    Path to a client certificate file for TLS
44
+
45
+.PP
46
+\fB\-\-client\-key\fP=""
47
+    Path to a client key file for TLS
48
+
49
+.PP
50
+\fB\-\-cluster\fP=""
51
+    The name of the kubeconfig cluster to use
52
+
53
+.PP
54
+\fB\-\-config\fP=""
55
+    Path to the config file to use for CLI requests.
56
+
57
+.PP
58
+\fB\-\-context\fP=""
59
+    The name of the kubeconfig context to use
60
+
61
+.PP
62
+\fB\-\-google\-json\-key\fP=""
63
+    The Google Cloud Platform Service Account JSON Key to use for authentication.
64
+
65
+.PP
66
+\fB\-\-insecure\-skip\-tls\-verify\fP=false
67
+    If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
68
+
69
+.PP
70
+\fB\-\-log\-flush\-frequency\fP=0
71
+    Maximum number of seconds between log flushes
72
+
73
+.PP
74
+\fB\-\-match\-server\-version\fP=false
75
+    Require server version to match client version
76
+
77
+.PP
78
+\fB\-n\fP, \fB\-\-namespace\fP=""
79
+    If present, the namespace scope for this CLI request
80
+
81
+.PP
82
+\fB\-\-server\fP=""
83
+    The address and port of the Kubernetes API server
84
+
85
+.PP
86
+\fB\-\-token\fP=""
87
+    Bearer token for authentication to the API server
88
+
89
+.PP
90
+\fB\-\-user\fP=""
91
+    The name of the kubeconfig user to use
92
+
93
+
94
+.SH EXAMPLE
95
+.PP
96
+.RS
97
+
98
+.nf
99
+  # Watch the status of the latest rollout
100
+  oc rollout status dc/nginx
101
+
102
+
103
+.fi
104
+.RE
105
+
106
+
107
+.SH SEE ALSO
108
+.PP
109
+\fBoc\-rollout(1)\fP,
110
+
111
+
112
+.SH HISTORY
113
+.PP
114
+June 2016, Ported from the Kubernetes man\-doc generator
... ...
@@ -104,7 +104,7 @@ at the same time
104 104
 
105 105
 .SH SEE ALSO
106 106
 .PP
107
-\fBoc(1)\fP, \fBoc\-rollout\-history(1)\fP, \fBoc\-rollout\-latest(1)\fP, \fBoc\-rollout\-pause(1)\fP, \fBoc\-rollout\-resume(1)\fP, \fBoc\-rollout\-undo(1)\fP,
107
+\fBoc(1)\fP, \fBoc\-rollout\-history(1)\fP, \fBoc\-rollout\-latest(1)\fP, \fBoc\-rollout\-pause(1)\fP, \fBoc\-rollout\-resume(1)\fP, \fBoc\-rollout\-status(1)\fP, \fBoc\-rollout\-undo(1)\fP,
108 108
 
109 109
 
110 110
 .SH HISTORY
111 111
new file mode 100644
... ...
@@ -0,0 +1,115 @@
0
+.TH "OPENSHIFT CLI ROLLOUT" "1" " Openshift CLI User Manuals" "Openshift" "June 2016"  ""
1
+
2
+
3
+.SH NAME
4
+.PP
5
+openshift cli rollout status \- Watch rollout status until it's done
6
+
7
+
8
+.SH SYNOPSIS
9
+.PP
10
+\fBopenshift cli rollout status\fP [OPTIONS]
11
+
12
+
13
+.SH DESCRIPTION
14
+.PP
15
+Watch the status of the latest rollout, until it's done.
16
+
17
+
18
+.SH OPTIONS
19
+.PP
20
+\fB\-f\fP, \fB\-\-filename\fP=[]
21
+    Filename, directory, or URL to a file identifying the resource to get from a server.
22
+
23
+.PP
24
+\fB\-R\fP, \fB\-\-recursive\fP=false
25
+    Process the directory used in \-f, \-\-filename recursively. Useful when you want to manage related manifests organized within the same directory.
26
+
27
+
28
+.SH OPTIONS INHERITED FROM PARENT COMMANDS
29
+.PP
30
+\fB\-\-api\-version\fP=""
31
+    DEPRECATED: The API version to use when talking to the server
32
+
33
+.PP
34
+\fB\-\-as\fP=""
35
+    Username to impersonate for the operation
36
+
37
+.PP
38
+\fB\-\-certificate\-authority\fP=""
39
+    Path to a cert. file for the certificate authority
40
+
41
+.PP
42
+\fB\-\-client\-certificate\fP=""
43
+    Path to a client certificate file for TLS
44
+
45
+.PP
46
+\fB\-\-client\-key\fP=""
47
+    Path to a client key file for TLS
48
+
49
+.PP
50
+\fB\-\-cluster\fP=""
51
+    The name of the kubeconfig cluster to use
52
+
53
+.PP
54
+\fB\-\-config\fP=""
55
+    Path to the config file to use for CLI requests.
56
+
57
+.PP
58
+\fB\-\-context\fP=""
59
+    The name of the kubeconfig context to use
60
+
61
+.PP
62
+\fB\-\-google\-json\-key\fP=""
63
+    The Google Cloud Platform Service Account JSON Key to use for authentication.
64
+
65
+.PP
66
+\fB\-\-insecure\-skip\-tls\-verify\fP=false
67
+    If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure
68
+
69
+.PP
70
+\fB\-\-log\-flush\-frequency\fP=0
71
+    Maximum number of seconds between log flushes
72
+
73
+.PP
74
+\fB\-\-match\-server\-version\fP=false
75
+    Require server version to match client version
76
+
77
+.PP
78
+\fB\-n\fP, \fB\-\-namespace\fP=""
79
+    If present, the namespace scope for this CLI request
80
+
81
+.PP
82
+\fB\-\-server\fP=""
83
+    The address and port of the Kubernetes API server
84
+
85
+.PP
86
+\fB\-\-token\fP=""
87
+    Bearer token for authentication to the API server
88
+
89
+.PP
90
+\fB\-\-user\fP=""
91
+    The name of the kubeconfig user to use
92
+
93
+
94
+.SH EXAMPLE
95
+.PP
96
+.RS
97
+
98
+.nf
99
+  # Watch the status of the latest rollout
100
+  openshift cli rollout status dc/nginx
101
+
102
+
103
+.fi
104
+.RE
105
+
106
+
107
+.SH SEE ALSO
108
+.PP
109
+\fBopenshift\-cli\-rollout(1)\fP,
110
+
111
+
112
+.SH HISTORY
113
+.PP
114
+June 2016, Ported from the Kubernetes man\-doc generator
... ...
@@ -104,7 +104,7 @@ at the same time
104 104
 
105 105
 .SH SEE ALSO
106 106
 .PP
107
-\fBopenshift\-cli(1)\fP, \fBopenshift\-cli\-rollout\-history(1)\fP, \fBopenshift\-cli\-rollout\-latest(1)\fP, \fBopenshift\-cli\-rollout\-pause(1)\fP, \fBopenshift\-cli\-rollout\-resume(1)\fP, \fBopenshift\-cli\-rollout\-undo(1)\fP,
107
+\fBopenshift\-cli(1)\fP, \fBopenshift\-cli\-rollout\-history(1)\fP, \fBopenshift\-cli\-rollout\-latest(1)\fP, \fBopenshift\-cli\-rollout\-pause(1)\fP, \fBopenshift\-cli\-rollout\-resume(1)\fP, \fBopenshift\-cli\-rollout\-status(1)\fP, \fBopenshift\-cli\-rollout\-undo(1)\fP,
108 108
 
109 109
 
110 110
 .SH HISTORY
... ...
@@ -48,6 +48,7 @@ func NewCmdRollout(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.
48 48
 	cmd.AddCommand(NewCmdRolloutResume(fullName, f, out))
49 49
 	cmd.AddCommand(NewCmdRolloutUndo(fullName, f, out))
50 50
 	cmd.AddCommand(NewCmdRolloutLatest(fullName, f, out))
51
+	cmd.AddCommand(NewCmdRolloutStatus(fullName, f, out))
51 52
 
52 53
 	return cmd
53 54
 }
... ...
@@ -154,3 +155,20 @@ func NewCmdRolloutUndo(fullName string, f *clientcmd.Factory, out io.Writer) *co
154 154
 	cmd.ValidArgs = append(cmd.ValidArgs, "deploymentconfig")
155 155
 	return cmd
156 156
 }
157
+
158
+const (
159
+	rolloutStatusLong = `
160
+Watch the status of the latest rollout, until it's done.`
161
+
162
+	rolloutStatusExample = `  # Watch the status of the latest rollout
163
+  %[1]s rollout status dc/nginx
164
+`
165
+)
166
+
167
+// NewCmdRolloutStatus is a wrapper for the Kubernetes cli rollout status command
168
+func NewCmdRolloutStatus(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command {
169
+	cmd := rollout.NewCmdRolloutStatus(f.Factory, out)
170
+	cmd.Long = rolloutStatusLong
171
+	cmd.Example = fmt.Sprintf(rolloutStatusExample, fullName)
172
+	return cmd
173
+}
... ...
@@ -637,6 +637,19 @@ func NewFactory(clientConfig kclientcmd.ClientConfig) *Factory {
637 637
 		}
638 638
 		return kRollbackerFunc(mapping)
639 639
 	}
640
+	kStatusViewerFunc := w.Factory.StatusViewer
641
+	w.Factory.StatusViewer = func(mapping *meta.RESTMapping) (kubectl.StatusViewer, error) {
642
+		oc, _, err := w.Clients()
643
+		if err != nil {
644
+			return nil, err
645
+		}
646
+
647
+		switch mapping.GroupVersionKind.GroupKind() {
648
+		case deployapi.Kind("DeploymentConfig"):
649
+			return deploycmd.NewDeploymentConfigStatusViewer(oc), nil
650
+		}
651
+		return kStatusViewerFunc(mapping)
652
+	}
640 653
 
641 654
 	return w
642 655
 }
643 656
new file mode 100644
... ...
@@ -0,0 +1,67 @@
0
+package cmd
1
+
2
+import (
3
+	"errors"
4
+	"fmt"
5
+
6
+	"k8s.io/kubernetes/pkg/kubectl"
7
+
8
+	"github.com/openshift/origin/pkg/client"
9
+	deployapi "github.com/openshift/origin/pkg/deploy/api"
10
+	deployutil "github.com/openshift/origin/pkg/deploy/util"
11
+)
12
+
13
+func NewDeploymentConfigStatusViewer(oc client.Interface) kubectl.StatusViewer {
14
+	return &DeploymentConfigStatusViewer{dn: oc}
15
+}
16
+
17
+// DeploymentConfigStatusViewer is an implementation of the kubectl StatusViewer interface
18
+// for deployment configs.
19
+type DeploymentConfigStatusViewer struct {
20
+	dn client.DeploymentConfigsNamespacer
21
+}
22
+
23
+var _ kubectl.StatusViewer = &DeploymentConfigStatusViewer{}
24
+
25
+// Status returns a message describing deployment status, and a bool value indicating if the status is considered done
26
+func (s *DeploymentConfigStatusViewer) Status(namespace, name string) (string, bool, error) {
27
+	config, err := s.dn.DeploymentConfigs(namespace).Get(name)
28
+	if err != nil {
29
+		return "", false, err
30
+	}
31
+
32
+	if config.Status.LatestVersion == 0 {
33
+		switch {
34
+		case deployutil.HasImageChangeTrigger(config):
35
+			return fmt.Sprintf("Deployment config %q waiting on image update\n", name), false, nil
36
+
37
+		case len(config.Spec.Triggers) == 0:
38
+			return "", true, fmt.Errorf("Deployment config %q waiting on manual update (use 'oc rollout latest %s')", name, name)
39
+		}
40
+	}
41
+
42
+	cond := deployutil.GetDeploymentCondition(config.Status, deployapi.DeploymentProgressing)
43
+
44
+	if config.Generation <= config.Status.ObservedGeneration {
45
+		switch {
46
+		case cond != nil && cond.Reason == deployutil.NewRcAvailableReason:
47
+			return fmt.Sprintf("%s\n", cond.Message), true, nil
48
+
49
+		case cond != nil && cond.Reason == deployutil.TimedOutReason:
50
+			return "", true, errors.New(cond.Message)
51
+
52
+		case cond != nil && cond.Reason == deployutil.PausedDeployReason:
53
+			return "", true, fmt.Errorf("Deployment config %q is paused. Resume to continue watching the status of the rollout.\n", config.Name)
54
+
55
+		case config.Status.UpdatedReplicas < config.Spec.Replicas:
56
+			return fmt.Sprintf("Waiting for rollout to finish: %d out of %d new replicas have been updated...\n", config.Status.UpdatedReplicas, config.Spec.Replicas), false, nil
57
+
58
+		case config.Status.Replicas > config.Status.UpdatedReplicas:
59
+			return fmt.Sprintf("Waiting for rollout to finish: %d old replicas are pending termination...\n", config.Status.Replicas-config.Status.UpdatedReplicas), false, nil
60
+
61
+		case config.Status.AvailableReplicas < config.Status.UpdatedReplicas:
62
+			return fmt.Sprintf("Waiting for rollout to finish: %d of %d updated replicas are available...\n", config.Status.AvailableReplicas, config.Status.UpdatedReplicas), false, nil
63
+		}
64
+	}
65
+	return fmt.Sprintf("Waiting for latest deployment config spec to be observed by the controller loop...\n"), false, nil
66
+}
... ...
@@ -359,6 +359,12 @@ func (c *DeploymentConfigController) updateStatus(config *deployapi.DeploymentCo
359 359
 		return err
360 360
 	}
361 361
 
362
+	latestExists, latestRC := deployutil.LatestDeploymentInfo(config, deployments)
363
+	if !latestExists {
364
+		latestRC = nil
365
+	}
366
+	updateConditions(config, &newStatus, latestRC)
367
+
362 368
 	// NOTE: We should update the status of the deployment config only if we need to, otherwise
363 369
 	// we hotloop between updates.
364 370
 	if reflect.DeepEqual(newStatus, config.Status) {
... ...
@@ -411,6 +417,58 @@ func (c *DeploymentConfigController) calculateStatus(config deployapi.Deployment
411 411
 	}, nil
412 412
 }
413 413
 
414
+func updateConditions(config *deployapi.DeploymentConfig, newStatus *deployapi.DeploymentConfigStatus, latestRC *kapi.ReplicationController) {
415
+	// Availability condition.
416
+	if newStatus.AvailableReplicas >= config.Spec.Replicas-deployutil.MaxUnavailable(*config) {
417
+		minAvailability := deployutil.NewDeploymentCondition(deployapi.DeploymentAvailable, kapi.ConditionTrue, "", "Deployment config has minimum availability.")
418
+		deployutil.SetDeploymentCondition(newStatus, *minAvailability)
419
+	} else {
420
+		noMinAvailability := deployutil.NewDeploymentCondition(deployapi.DeploymentAvailable, kapi.ConditionFalse, "", "Deployment config does not have minimum availability.")
421
+		deployutil.SetDeploymentCondition(newStatus, *noMinAvailability)
422
+	}
423
+	// Condition about progress.
424
+	cond := deployutil.GetDeploymentCondition(*newStatus, deployapi.DeploymentProgressing)
425
+	if latestRC != nil {
426
+		switch deployutil.DeploymentStatusFor(latestRC) {
427
+		case deployapi.DeploymentStatusNew, deployapi.DeploymentStatusPending:
428
+			msg := fmt.Sprintf("Waiting on deployer pod for %q to be scheduled", latestRC.Name)
429
+			condition := deployutil.NewDeploymentCondition(deployapi.DeploymentProgressing, kapi.ConditionUnknown, "", msg)
430
+			deployutil.SetDeploymentCondition(newStatus, *condition)
431
+		case deployapi.DeploymentStatusRunning:
432
+			msg := fmt.Sprintf("Replication controller %q is progressing", latestRC.Name)
433
+			condition := deployutil.NewDeploymentCondition(deployapi.DeploymentProgressing, kapi.ConditionTrue, deployutil.ReplicationControllerUpdatedReason, msg)
434
+			deployutil.SetDeploymentCondition(newStatus, *condition)
435
+		case deployapi.DeploymentStatusFailed:
436
+			if cond != nil && cond.Reason == deployutil.TimedOutReason {
437
+				break
438
+			}
439
+			msg := fmt.Sprintf("Replication controller %q has failed progressing", latestRC.Name)
440
+			condition := deployutil.NewDeploymentCondition(deployapi.DeploymentProgressing, kapi.ConditionFalse, deployutil.TimedOutReason, msg)
441
+			deployutil.SetDeploymentCondition(newStatus, *condition)
442
+		case deployapi.DeploymentStatusComplete:
443
+			if cond != nil && cond.Reason == deployutil.NewRcAvailableReason {
444
+				break
445
+			}
446
+			msg := fmt.Sprintf("Replication controller %q has completed progressing", latestRC.Name)
447
+			condition := deployutil.NewDeploymentCondition(deployapi.DeploymentProgressing, kapi.ConditionTrue, deployutil.NewRcAvailableReason, msg)
448
+			deployutil.SetDeploymentCondition(newStatus, *condition)
449
+		}
450
+	}
451
+	// Pause / resume condition. Since we don't pause running deployments, let's use paused conditions only when a deployment
452
+	// actually terminates. For now it may be ok to override lack of progress in the conditions, later we may want to separate
453
+	// paused from the rest of the progressing conditions.
454
+	if latestRC == nil || deployutil.IsTerminatedDeployment(latestRC) {
455
+		pausedCondExists := cond != nil && cond.Reason == deployutil.PausedDeployReason
456
+		if config.Spec.Paused && !pausedCondExists {
457
+			condition := deployutil.NewDeploymentCondition(deployapi.DeploymentProgressing, kapi.ConditionUnknown, deployutil.PausedDeployReason, "Deployment config is paused")
458
+			deployutil.SetDeploymentCondition(newStatus, *condition)
459
+		} else if !config.Spec.Paused && pausedCondExists {
460
+			condition := deployutil.NewDeploymentCondition(deployapi.DeploymentProgressing, kapi.ConditionUnknown, deployutil.ResumedDeployReason, "Deployment config is resumed")
461
+			deployutil.SetDeploymentCondition(newStatus, *condition)
462
+		}
463
+	}
464
+}
465
+
414 466
 func (c *DeploymentConfigController) handleErr(err error, key interface{}) {
415 467
 	if err == nil {
416 468
 		c.queue.Forget(key)
... ...
@@ -9,6 +9,7 @@ import (
9 9
 	"time"
10 10
 
11 11
 	"k8s.io/kubernetes/pkg/api"
12
+	"k8s.io/kubernetes/pkg/api/unversioned"
12 13
 	kdeplutil "k8s.io/kubernetes/pkg/controller/deployment/util"
13 14
 	"k8s.io/kubernetes/pkg/fields"
14 15
 	"k8s.io/kubernetes/pkg/labels"
... ...
@@ -20,6 +21,78 @@ import (
20 20
 	kclient "k8s.io/kubernetes/pkg/client/unversioned"
21 21
 )
22 22
 
23
+const (
24
+	// Reasons for deployment config conditions:
25
+	//
26
+	// ReplicationControllerUpdatedReason is added in a deployment config when one of its replication
27
+	// controllers is updated as part of the rollout process.
28
+	ReplicationControllerUpdatedReason = "ReplicationControllerUpdated"
29
+	// FailedRcCreateReason is added in a deployment config when it cannot create a new replication
30
+	// controller.
31
+	FailedRcCreateReason = "ReplicationControllerCreateError"
32
+	// NewReplicationControllerReason is added in a deployment config when it creates a new replication
33
+	// controller.
34
+	NewReplicationControllerReason = "NewReplicationControllerCreated"
35
+	// NewRcAvailableReason is added in a deployment config when its newest replication controller is made
36
+	// available ie. the number of new pods that have passed readiness checks and run for at least
37
+	// minReadySeconds is at least the minimum available pods that need to run for the deployment config.
38
+	NewRcAvailableReason = "NewReplicationControllerAvailable"
39
+	// TimedOutReason is added in a deployment config when its newest replication controller fails to show
40
+	// any progress within the given deadline (progressDeadlineSeconds).
41
+	TimedOutReason = "ProgressDeadlineExceeded"
42
+	// PausedDeployReason is added in a deployment config when it is paused. Lack of progress shouldn't be
43
+	// estimated once a deployment config is paused.
44
+	PausedDeployReason = "DeploymentConfigPaused"
45
+	// ResumedDeployReason is added in a deployment config when it is resumed. Useful for not failing accidentally
46
+	// deployment configs that paused amidst a rollout.
47
+	ResumedDeployReason = "DeploymentConfigResumed"
48
+)
49
+
50
+// NewDeploymentCondition creates a new deployment condition.
51
+func NewDeploymentCondition(condType deployapi.DeploymentConditionType, status api.ConditionStatus, reason, message string) *deployapi.DeploymentCondition {
52
+	return &deployapi.DeploymentCondition{
53
+		Type:               condType,
54
+		Status:             status,
55
+		LastTransitionTime: unversioned.Now(),
56
+		Reason:             reason,
57
+		Message:            message,
58
+	}
59
+}
60
+
61
+// GetDeploymentCondition returns the condition with the provided type.
62
+func GetDeploymentCondition(status deployapi.DeploymentConfigStatus, condType deployapi.DeploymentConditionType) *deployapi.DeploymentCondition {
63
+	for i := range status.Conditions {
64
+		c := status.Conditions[i]
65
+		if c.Type == condType {
66
+			return &c
67
+		}
68
+	}
69
+	return nil
70
+}
71
+
72
+// SetDeploymentCondition updates the deployment to include the provided condition.
73
+func SetDeploymentCondition(status *deployapi.DeploymentConfigStatus, condition deployapi.DeploymentCondition) {
74
+	newConditions := filterOutCondition(status.Conditions, condition.Type)
75
+	status.Conditions = append(newConditions, condition)
76
+}
77
+
78
+// RemoveDeploymentCondition removes the deployment condition with the provided type.
79
+func RemoveDeploymentCondition(status *deployapi.DeploymentConfigStatus, condType deployapi.DeploymentConditionType) {
80
+	status.Conditions = filterOutCondition(status.Conditions, condType)
81
+}
82
+
83
+// filterOutCondition returns a new slice of deployment conditions without conditions with the provided type.
84
+func filterOutCondition(conditions []deployapi.DeploymentCondition, condType deployapi.DeploymentConditionType) []deployapi.DeploymentCondition {
85
+	var newConditions []deployapi.DeploymentCondition
86
+	for _, c := range conditions {
87
+		if c.Type == condType {
88
+			continue
89
+		}
90
+		newConditions = append(newConditions, c)
91
+	}
92
+	return newConditions
93
+}
94
+
23 95
 // LatestDeploymentNameForConfig returns a stable identifier for config based on its version.
24 96
 func LatestDeploymentNameForConfig(config *deployapi.DeploymentConfig) string {
25 97
 	return fmt.Sprintf("%s-%d", config.Name, config.Status.LatestVersion)
... ...
@@ -112,6 +185,17 @@ func HasChangeTrigger(config *deployapi.DeploymentConfig) bool {
112 112
 	return false
113 113
 }
114 114
 
115
+// HasImageChangeTrigger returns whether the provided deployment configuration has
116
+// an image change trigger or not.
117
+func HasImageChangeTrigger(config *deployapi.DeploymentConfig) bool {
118
+	for _, trigger := range config.Spec.Triggers {
119
+		if trigger.Type == deployapi.DeploymentTriggerOnImageChange {
120
+			return true
121
+		}
122
+	}
123
+	return false
124
+}
125
+
115 126
 func DeploymentConfigDeepCopy(dc *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) {
116 127
 	objCopy, err := api.Scheme.DeepCopy(dc)
117 128
 	if err != nil {
... ...
@@ -385,6 +469,31 @@ func CanTransitionPhase(current, next deployapi.DeploymentStatus) bool {
385 385
 	return false
386 386
 }
387 387
 
388
+// IsRollingConfig returns true if the strategy type is a rolling update.
389
+func IsRollingConfig(config *deployapi.DeploymentConfig) bool {
390
+	return config.Spec.Strategy.Type == deployapi.DeploymentStrategyTypeRolling
391
+}
392
+
393
+// MaxUnavailable returns the maximum unavailable pods a rolling deployment config can take.
394
+func MaxUnavailable(config deployapi.DeploymentConfig) int32 {
395
+	if !IsRollingConfig(&config) {
396
+		return int32(0)
397
+	}
398
+	// Error caught by validation
399
+	_, maxUnavailable, _ := kdeplutil.ResolveFenceposts(&config.Spec.Strategy.RollingParams.MaxSurge, &config.Spec.Strategy.RollingParams.MaxUnavailable, config.Spec.Replicas)
400
+	return maxUnavailable
401
+}
402
+
403
+// MaxSurge returns the maximum surge pods a rolling deployment config can take.
404
+func MaxSurge(config deployapi.DeploymentConfig) int32 {
405
+	if !IsRollingConfig(&config) {
406
+		return int32(0)
407
+	}
408
+	// Error caught by validation
409
+	maxSurge, _, _ := kdeplutil.ResolveFenceposts(&config.Spec.Strategy.RollingParams.MaxSurge, &config.Spec.Strategy.RollingParams.MaxUnavailable, config.Spec.Replicas)
410
+	return maxSurge
411
+}
412
+
388 413
 // annotationFor returns the annotation with key for obj.
389 414
 func annotationFor(obj runtime.Object, key string) string {
390 415
 	meta, err := api.ObjectMetaFor(obj)
... ...
@@ -85,7 +85,7 @@ echo "[INFO] Waiting for Docker registry pod to start"
85 85
 wait_for_registry
86 86
 
87 87
 echo "[INFO] Waiting for IP failover to deploy"
88
-os::cmd::try_until_text "oc get rc/ipfailover-1 --template \"{{ index .metadata.annotations \\\"openshift.io/deployment.phase\\\" }}\"" "Complete"
88
+os::cmd::expect_success 'oc rollout status dc/ipfailover'
89 89
 os::cmd::expect_success "oc delete all -l ipfailover=ipfailover"
90 90
 
91 91
 # check to make sure that logs for rc works
... ...
@@ -347,7 +347,7 @@ os::cmd::try_until_text 'oc get pods -l openshift.io/deployer-pod.type=hook-post
347 347
 os::cmd::expect_success 'oc create -f test/testdata/failing-dc.yaml'
348 348
 os::cmd::try_until_success 'oc get rc/failing-dc-1'
349 349
 os::cmd::expect_success 'oc logs -f dc/failing-dc'
350
-os::cmd::try_until_text "oc get rc/failing-dc-1 --template={{.metadata.annotations}}" 'openshift.io/deployment.phase:Failed'
350
+os::cmd::expect_failure 'oc rollout status dc/failing-dc'
351 351
 os::cmd::expect_success_and_text 'oc logs dc/failing-dc' 'test pre hook executed'
352 352
 os::cmd::expect_success 'oc deploy failing-dc --latest'
353 353
 os::cmd::expect_success_and_text 'oc logs --version=1 dc/failing-dc' 'test pre hook executed'
... ...
@@ -360,7 +360,7 @@ os::cmd::expect_success 'oc delete dc/failing-dc'
360 360
 os::cmd::expect_success 'oc create -f test/testdata/failing-dc-mid.yaml'
361 361
 os::cmd::try_until_success 'oc get rc/failing-dc-mid-1'
362 362
 os::cmd::expect_success 'oc logs -f dc/failing-dc-mid'
363
-os::cmd::try_until_text "oc get rc/failing-dc-mid-1 --template={{.metadata.annotations}}" 'openshift.io/deployment.phase:Failed'
363
+os::cmd::expect_failure 'oc rollout status dc/failing-dc-mid'
364 364
 os::cmd::expect_success_and_text 'oc logs dc/failing-dc-mid' 'test mid hook executed'
365 365
 # The following command is the equivalent of 'oc deploy --latest' on old clients
366 366
 # Ensures we won't break those while removing the dc status update from oc
... ...
@@ -171,8 +171,11 @@ func deploymentReachedCompletion(dc *deployapi.DeploymentConfig, rcs []kapi.Repl
171 171
 		return false, nil
172 172
 	}
173 173
 
174
-	status := rc.Annotations[deployapi.DeploymentStatusAnnotation]
175
-	if deployapi.DeploymentStatus(status) != deployapi.DeploymentStatusComplete {
174
+	if !deployutil.IsCompleteDeployment(&rc) {
175
+		return false, nil
176
+	}
177
+	cond := deployutil.GetDeploymentCondition(dc.Status, deployapi.DeploymentProgressing)
178
+	if cond == nil || cond.Reason != deployutil.NewRcAvailableReason {
176 179
 		return false, nil
177 180
 	}
178 181
 	expectedReplicas := dc.Spec.Replicas
... ...
@@ -199,7 +202,11 @@ func deploymentFailed(dc *deployapi.DeploymentConfig, rcs []kapi.ReplicationCont
199 199
 	if version != dc.Status.LatestVersion {
200 200
 		return false, nil
201 201
 	}
202
-	return deployutil.IsFailedDeployment(&rc), nil
202
+	if !deployutil.IsFailedDeployment(&rc) {
203
+		return false, nil
204
+	}
205
+	cond := deployutil.GetDeploymentCondition(dc.Status, deployapi.DeploymentProgressing)
206
+	return cond != nil && cond.Reason == deployutil.TimedOutReason, nil
203 207
 }
204 208
 
205 209
 func deploymentRunning(dc *deployapi.DeploymentConfig, rcs []kapi.ReplicationController, pods []kapi.Pod) (bool, error) {
... ...
@@ -24,6 +24,7 @@ import (
24 24
 	"k8s.io/kubernetes/pkg/kubectl"
25 25
 	cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
26 26
 	"k8s.io/kubernetes/pkg/kubectl/resource"
27
+	"k8s.io/kubernetes/pkg/util/interrupt"
27 28
 	"k8s.io/kubernetes/pkg/watch"
28 29
 
29 30
 	"github.com/spf13/cobra"
... ...
@@ -133,18 +134,21 @@ func RunStatus(f *cmdutil.Factory, cmd *cobra.Command, out io.Writer, args []str
133 133
 	}
134 134
 
135 135
 	// if the rollout isn't done yet, keep watching deployment status
136
-	kubectl.WatchLoop(w, func(e watch.Event) error {
137
-		// print deployment's status
138
-		status, done, err := statusViewer.Status(cmdNamespace, info.Name)
139
-		if err != nil {
140
-			return err
141
-		}
142
-		fmt.Fprintf(out, "%s", status)
143
-		// Quit waiting if the rollout is done
144
-		if done {
145
-			w.Stop()
146
-		}
147
-		return nil
136
+	intr := interrupt.New(nil, w.Stop)
137
+	return intr.Run(func() error {
138
+		_, err := watch.Until(0, w, func(e watch.Event) (bool, error) {
139
+			// print deployment's status
140
+			status, done, err := statusViewer.Status(cmdNamespace, info.Name)
141
+			if err != nil {
142
+				return false, err
143
+			}
144
+			fmt.Fprintf(out, "%s", status)
145
+			// Quit waiting if the rollout is done
146
+			if done {
147
+				return true, nil
148
+			}
149
+			return false, nil
150
+		})
151
+		return err
148 152
 	})
149
-	return nil
150 153
 }
... ...
@@ -40,7 +40,7 @@ func Until(timeout time.Duration, watcher Interface, conditions ...ConditionFunc
40 40
 		after = time.After(timeout)
41 41
 	} else {
42 42
 		ch := make(chan time.Time)
43
-		close(ch)
43
+		defer close(ch)
44 44
 		after = ch
45 45
 	}
46 46
 	var lastEvent *Event
... ...
@@ -23,7 +23,6 @@ import (
23 23
 	"time"
24 24
 
25 25
 	"k8s.io/kubernetes/pkg/api"
26
-	"k8s.io/kubernetes/pkg/util/wait"
27 26
 )
28 27
 
29 28
 func TestUntil(t *testing.T) {
... ...
@@ -83,17 +82,33 @@ func TestUntilMultipleConditions(t *testing.T) {
83 83
 
84 84
 func TestUntilTimeout(t *testing.T) {
85 85
 	fw := NewFake()
86
+	go func() {
87
+		var obj *api.Pod
88
+		fw.Add(obj)
89
+		fw.Modify(obj)
90
+	}()
86 91
 	conditions := []ConditionFunc{
87
-		func(event Event) (bool, error) { return event.Type == Added, nil },
92
+		func(event Event) (bool, error) {
93
+			return event.Type == Added, nil
94
+		},
95
+		func(event Event) (bool, error) {
96
+			return event.Type == Modified, nil
97
+		},
88 98
 	}
89 99
 
90 100
 	timeout := time.Duration(0)
91 101
 	lastEvent, err := Until(timeout, fw, conditions...)
92
-	if err != wait.ErrWaitTimeout {
93
-		t.Fatalf("expected ErrWaitTimeout error, got %#v", err)
102
+	if err != nil {
103
+		t.Fatalf("expected nil error, got %#v", err)
94 104
 	}
95
-	if lastEvent != nil {
96
-		t.Fatalf("expected nil event, got %#v", lastEvent)
105
+	if lastEvent == nil {
106
+		t.Fatal("expected an event")
107
+	}
108
+	if lastEvent.Type != Modified {
109
+		t.Fatalf("expected MODIFIED event type, got %v", lastEvent.Type)
110
+	}
111
+	if got, isPod := lastEvent.Object.(*api.Pod); !isPod {
112
+		t.Fatalf("expected a pod event, got %#v", got)
97 113
 	}
98 114
 }
99 115