Browse code

oc secrets: rename `add` to `link` and add `unlink`

Separate common functions for `oc secrets add`

This is in preparation for reusing these routines for
`oc secrets unlink`

Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>

Missing secrets should warn, not fail.

Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>

oc secrets: rename "add" to "link"

Maintain compatibility with "add"

Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>

Rework help documentation for `oc secrets link`

Also drop prefixes in examples

Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>

Add `oc secrets unlink`

New command to remove the link between a service account and a
Secret object.

Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>

oc secrets: Return non-success on any error

Signed-off-by: Stephen Gallagher <sgallagh@redhat.com>

Stephen Gallagher authored on 2016/07/12 22:56:09
Showing 22 changed files
... ...
@@ -3524,6 +3524,91 @@ _oc_secrets_new-sshauth()
3524 3524
     noun_aliases=()
3525 3525
 }
3526 3526
 
3527
+_oc_secrets_link()
3528
+{
3529
+    last_command="oc_secrets_link"
3530
+    commands=()
3531
+
3532
+    flags=()
3533
+    two_word_flags=()
3534
+    flags_with_completion=()
3535
+    flags_completion=()
3536
+
3537
+    flags+=("--for=")
3538
+    flags+=("--api-version=")
3539
+    flags+=("--as=")
3540
+    flags+=("--certificate-authority=")
3541
+    flags_with_completion+=("--certificate-authority")
3542
+    flags_completion+=("_filedir")
3543
+    flags+=("--client-certificate=")
3544
+    flags_with_completion+=("--client-certificate")
3545
+    flags_completion+=("_filedir")
3546
+    flags+=("--client-key=")
3547
+    flags_with_completion+=("--client-key")
3548
+    flags_completion+=("_filedir")
3549
+    flags+=("--cluster=")
3550
+    flags+=("--config=")
3551
+    flags_with_completion+=("--config")
3552
+    flags_completion+=("_filedir")
3553
+    flags+=("--context=")
3554
+    flags+=("--insecure-skip-tls-verify")
3555
+    flags+=("--log-flush-frequency=")
3556
+    flags+=("--loglevel=")
3557
+    flags+=("--logspec=")
3558
+    flags+=("--match-server-version")
3559
+    flags+=("--namespace=")
3560
+    two_word_flags+=("-n")
3561
+    flags+=("--server=")
3562
+    flags+=("--token=")
3563
+    flags+=("--user=")
3564
+
3565
+    must_have_one_flag=()
3566
+    must_have_one_noun=()
3567
+    noun_aliases=()
3568
+}
3569
+
3570
+_oc_secrets_unlink()
3571
+{
3572
+    last_command="oc_secrets_unlink"
3573
+    commands=()
3574
+
3575
+    flags=()
3576
+    two_word_flags=()
3577
+    flags_with_completion=()
3578
+    flags_completion=()
3579
+
3580
+    flags+=("--api-version=")
3581
+    flags+=("--as=")
3582
+    flags+=("--certificate-authority=")
3583
+    flags_with_completion+=("--certificate-authority")
3584
+    flags_completion+=("_filedir")
3585
+    flags+=("--client-certificate=")
3586
+    flags_with_completion+=("--client-certificate")
3587
+    flags_completion+=("_filedir")
3588
+    flags+=("--client-key=")
3589
+    flags_with_completion+=("--client-key")
3590
+    flags_completion+=("_filedir")
3591
+    flags+=("--cluster=")
3592
+    flags+=("--config=")
3593
+    flags_with_completion+=("--config")
3594
+    flags_completion+=("_filedir")
3595
+    flags+=("--context=")
3596
+    flags+=("--insecure-skip-tls-verify")
3597
+    flags+=("--log-flush-frequency=")
3598
+    flags+=("--loglevel=")
3599
+    flags+=("--logspec=")
3600
+    flags+=("--match-server-version")
3601
+    flags+=("--namespace=")
3602
+    two_word_flags+=("-n")
3603
+    flags+=("--server=")
3604
+    flags+=("--token=")
3605
+    flags+=("--user=")
3606
+
3607
+    must_have_one_flag=()
3608
+    must_have_one_noun=()
3609
+    noun_aliases=()
3610
+}
3611
+
3527 3612
 _oc_secrets_add()
3528 3613
 {
3529 3614
     last_command="oc_secrets_add"
... ...
@@ -3575,6 +3660,8 @@ _oc_secrets()
3575 3575
     commands+=("new-dockercfg")
3576 3576
     commands+=("new-basicauth")
3577 3577
     commands+=("new-sshauth")
3578
+    commands+=("link")
3579
+    commands+=("unlink")
3578 3580
     commands+=("add")
3579 3581
 
3580 3582
     flags=()
... ...
@@ -7882,6 +7882,93 @@ _openshift_cli_secrets_new-sshauth()
7882 7882
     noun_aliases=()
7883 7883
 }
7884 7884
 
7885
+_openshift_cli_secrets_link()
7886
+{
7887
+    last_command="openshift_cli_secrets_link"
7888
+    commands=()
7889
+
7890
+    flags=()
7891
+    two_word_flags=()
7892
+    flags_with_completion=()
7893
+    flags_completion=()
7894
+
7895
+    flags+=("--for=")
7896
+    flags+=("--api-version=")
7897
+    flags+=("--as=")
7898
+    flags+=("--certificate-authority=")
7899
+    flags_with_completion+=("--certificate-authority")
7900
+    flags_completion+=("_filedir")
7901
+    flags+=("--client-certificate=")
7902
+    flags_with_completion+=("--client-certificate")
7903
+    flags_completion+=("_filedir")
7904
+    flags+=("--client-key=")
7905
+    flags_with_completion+=("--client-key")
7906
+    flags_completion+=("_filedir")
7907
+    flags+=("--cluster=")
7908
+    flags+=("--config=")
7909
+    flags_with_completion+=("--config")
7910
+    flags_completion+=("_filedir")
7911
+    flags+=("--context=")
7912
+    flags+=("--google-json-key=")
7913
+    flags+=("--insecure-skip-tls-verify")
7914
+    flags+=("--log-flush-frequency=")
7915
+    flags+=("--loglevel=")
7916
+    flags+=("--logspec=")
7917
+    flags+=("--match-server-version")
7918
+    flags+=("--namespace=")
7919
+    two_word_flags+=("-n")
7920
+    flags+=("--server=")
7921
+    flags+=("--token=")
7922
+    flags+=("--user=")
7923
+
7924
+    must_have_one_flag=()
7925
+    must_have_one_noun=()
7926
+    noun_aliases=()
7927
+}
7928
+
7929
+_openshift_cli_secrets_unlink()
7930
+{
7931
+    last_command="openshift_cli_secrets_unlink"
7932
+    commands=()
7933
+
7934
+    flags=()
7935
+    two_word_flags=()
7936
+    flags_with_completion=()
7937
+    flags_completion=()
7938
+
7939
+    flags+=("--api-version=")
7940
+    flags+=("--as=")
7941
+    flags+=("--certificate-authority=")
7942
+    flags_with_completion+=("--certificate-authority")
7943
+    flags_completion+=("_filedir")
7944
+    flags+=("--client-certificate=")
7945
+    flags_with_completion+=("--client-certificate")
7946
+    flags_completion+=("_filedir")
7947
+    flags+=("--client-key=")
7948
+    flags_with_completion+=("--client-key")
7949
+    flags_completion+=("_filedir")
7950
+    flags+=("--cluster=")
7951
+    flags+=("--config=")
7952
+    flags_with_completion+=("--config")
7953
+    flags_completion+=("_filedir")
7954
+    flags+=("--context=")
7955
+    flags+=("--google-json-key=")
7956
+    flags+=("--insecure-skip-tls-verify")
7957
+    flags+=("--log-flush-frequency=")
7958
+    flags+=("--loglevel=")
7959
+    flags+=("--logspec=")
7960
+    flags+=("--match-server-version")
7961
+    flags+=("--namespace=")
7962
+    two_word_flags+=("-n")
7963
+    flags+=("--server=")
7964
+    flags+=("--token=")
7965
+    flags+=("--user=")
7966
+
7967
+    must_have_one_flag=()
7968
+    must_have_one_noun=()
7969
+    noun_aliases=()
7970
+}
7971
+
7885 7972
 _openshift_cli_secrets_add()
7886 7973
 {
7887 7974
     last_command="openshift_cli_secrets_add"
... ...
@@ -7934,6 +8021,8 @@ _openshift_cli_secrets()
7934 7934
     commands+=("new-dockercfg")
7935 7935
     commands+=("new-basicauth")
7936 7936
     commands+=("new-sshauth")
7937
+    commands+=("link")
7938
+    commands+=("unlink")
7937 7939
     commands+=("add")
7938 7940
 
7939 7941
     flags=()
... ...
@@ -3685,6 +3685,91 @@ _oc_secrets_new-sshauth()
3685 3685
     noun_aliases=()
3686 3686
 }
3687 3687
 
3688
+_oc_secrets_link()
3689
+{
3690
+    last_command="oc_secrets_link"
3691
+    commands=()
3692
+
3693
+    flags=()
3694
+    two_word_flags=()
3695
+    flags_with_completion=()
3696
+    flags_completion=()
3697
+
3698
+    flags+=("--for=")
3699
+    flags+=("--api-version=")
3700
+    flags+=("--as=")
3701
+    flags+=("--certificate-authority=")
3702
+    flags_with_completion+=("--certificate-authority")
3703
+    flags_completion+=("_filedir")
3704
+    flags+=("--client-certificate=")
3705
+    flags_with_completion+=("--client-certificate")
3706
+    flags_completion+=("_filedir")
3707
+    flags+=("--client-key=")
3708
+    flags_with_completion+=("--client-key")
3709
+    flags_completion+=("_filedir")
3710
+    flags+=("--cluster=")
3711
+    flags+=("--config=")
3712
+    flags_with_completion+=("--config")
3713
+    flags_completion+=("_filedir")
3714
+    flags+=("--context=")
3715
+    flags+=("--insecure-skip-tls-verify")
3716
+    flags+=("--log-flush-frequency=")
3717
+    flags+=("--loglevel=")
3718
+    flags+=("--logspec=")
3719
+    flags+=("--match-server-version")
3720
+    flags+=("--namespace=")
3721
+    two_word_flags+=("-n")
3722
+    flags+=("--server=")
3723
+    flags+=("--token=")
3724
+    flags+=("--user=")
3725
+
3726
+    must_have_one_flag=()
3727
+    must_have_one_noun=()
3728
+    noun_aliases=()
3729
+}
3730
+
3731
+_oc_secrets_unlink()
3732
+{
3733
+    last_command="oc_secrets_unlink"
3734
+    commands=()
3735
+
3736
+    flags=()
3737
+    two_word_flags=()
3738
+    flags_with_completion=()
3739
+    flags_completion=()
3740
+
3741
+    flags+=("--api-version=")
3742
+    flags+=("--as=")
3743
+    flags+=("--certificate-authority=")
3744
+    flags_with_completion+=("--certificate-authority")
3745
+    flags_completion+=("_filedir")
3746
+    flags+=("--client-certificate=")
3747
+    flags_with_completion+=("--client-certificate")
3748
+    flags_completion+=("_filedir")
3749
+    flags+=("--client-key=")
3750
+    flags_with_completion+=("--client-key")
3751
+    flags_completion+=("_filedir")
3752
+    flags+=("--cluster=")
3753
+    flags+=("--config=")
3754
+    flags_with_completion+=("--config")
3755
+    flags_completion+=("_filedir")
3756
+    flags+=("--context=")
3757
+    flags+=("--insecure-skip-tls-verify")
3758
+    flags+=("--log-flush-frequency=")
3759
+    flags+=("--loglevel=")
3760
+    flags+=("--logspec=")
3761
+    flags+=("--match-server-version")
3762
+    flags+=("--namespace=")
3763
+    two_word_flags+=("-n")
3764
+    flags+=("--server=")
3765
+    flags+=("--token=")
3766
+    flags+=("--user=")
3767
+
3768
+    must_have_one_flag=()
3769
+    must_have_one_noun=()
3770
+    noun_aliases=()
3771
+}
3772
+
3688 3773
 _oc_secrets_add()
3689 3774
 {
3690 3775
     last_command="oc_secrets_add"
... ...
@@ -3736,6 +3821,8 @@ _oc_secrets()
3736 3736
     commands+=("new-dockercfg")
3737 3737
     commands+=("new-basicauth")
3738 3738
     commands+=("new-sshauth")
3739
+    commands+=("link")
3740
+    commands+=("unlink")
3739 3741
     commands+=("add")
3740 3742
 
3741 3743
     flags=()
... ...
@@ -8043,6 +8043,93 @@ _openshift_cli_secrets_new-sshauth()
8043 8043
     noun_aliases=()
8044 8044
 }
8045 8045
 
8046
+_openshift_cli_secrets_link()
8047
+{
8048
+    last_command="openshift_cli_secrets_link"
8049
+    commands=()
8050
+
8051
+    flags=()
8052
+    two_word_flags=()
8053
+    flags_with_completion=()
8054
+    flags_completion=()
8055
+
8056
+    flags+=("--for=")
8057
+    flags+=("--api-version=")
8058
+    flags+=("--as=")
8059
+    flags+=("--certificate-authority=")
8060
+    flags_with_completion+=("--certificate-authority")
8061
+    flags_completion+=("_filedir")
8062
+    flags+=("--client-certificate=")
8063
+    flags_with_completion+=("--client-certificate")
8064
+    flags_completion+=("_filedir")
8065
+    flags+=("--client-key=")
8066
+    flags_with_completion+=("--client-key")
8067
+    flags_completion+=("_filedir")
8068
+    flags+=("--cluster=")
8069
+    flags+=("--config=")
8070
+    flags_with_completion+=("--config")
8071
+    flags_completion+=("_filedir")
8072
+    flags+=("--context=")
8073
+    flags+=("--google-json-key=")
8074
+    flags+=("--insecure-skip-tls-verify")
8075
+    flags+=("--log-flush-frequency=")
8076
+    flags+=("--loglevel=")
8077
+    flags+=("--logspec=")
8078
+    flags+=("--match-server-version")
8079
+    flags+=("--namespace=")
8080
+    two_word_flags+=("-n")
8081
+    flags+=("--server=")
8082
+    flags+=("--token=")
8083
+    flags+=("--user=")
8084
+
8085
+    must_have_one_flag=()
8086
+    must_have_one_noun=()
8087
+    noun_aliases=()
8088
+}
8089
+
8090
+_openshift_cli_secrets_unlink()
8091
+{
8092
+    last_command="openshift_cli_secrets_unlink"
8093
+    commands=()
8094
+
8095
+    flags=()
8096
+    two_word_flags=()
8097
+    flags_with_completion=()
8098
+    flags_completion=()
8099
+
8100
+    flags+=("--api-version=")
8101
+    flags+=("--as=")
8102
+    flags+=("--certificate-authority=")
8103
+    flags_with_completion+=("--certificate-authority")
8104
+    flags_completion+=("_filedir")
8105
+    flags+=("--client-certificate=")
8106
+    flags_with_completion+=("--client-certificate")
8107
+    flags_completion+=("_filedir")
8108
+    flags+=("--client-key=")
8109
+    flags_with_completion+=("--client-key")
8110
+    flags_completion+=("_filedir")
8111
+    flags+=("--cluster=")
8112
+    flags+=("--config=")
8113
+    flags_with_completion+=("--config")
8114
+    flags_completion+=("_filedir")
8115
+    flags+=("--context=")
8116
+    flags+=("--google-json-key=")
8117
+    flags+=("--insecure-skip-tls-verify")
8118
+    flags+=("--log-flush-frequency=")
8119
+    flags+=("--loglevel=")
8120
+    flags+=("--logspec=")
8121
+    flags+=("--match-server-version")
8122
+    flags+=("--namespace=")
8123
+    two_word_flags+=("-n")
8124
+    flags+=("--server=")
8125
+    flags+=("--token=")
8126
+    flags+=("--user=")
8127
+
8128
+    must_have_one_flag=()
8129
+    must_have_one_noun=()
8130
+    noun_aliases=()
8131
+}
8132
+
8046 8133
 _openshift_cli_secrets_add()
8047 8134
 {
8048 8135
     last_command="openshift_cli_secrets_add"
... ...
@@ -8095,6 +8182,8 @@ _openshift_cli_secrets()
8095 8095
     commands+=("new-dockercfg")
8096 8096
     commands+=("new-basicauth")
8097 8097
     commands+=("new-sshauth")
8098
+    commands+=("link")
8099
+    commands+=("unlink")
8098 8100
     commands+=("add")
8099 8101
 
8100 8102
     flags=()
... ...
@@ -2092,20 +2092,39 @@ Change the number of pods in a deployment
2092 2092
 
2093 2093
 
2094 2094
 == oc secrets add
2095
-Add secrets to a ServiceAccount
2095
+DEPRECATED: secrets link
2096 2096
 
2097 2097
 ====
2098 2098
 
2099 2099
 [options="nowrap"]
2100 2100
 ----
2101
-  // To use your secret inside of a pod or as a push, pull, or source secret for a build, you must add a 'mount' secret to your service account like this:
2102
-  oc secrets add serviceaccount/sa-name secrets/secret-name secrets/another-secret-name
2101
+  # Add an image pull secret to a service account to automatically use it for pulling pod images:
2102
+  oc serviceaccount-name pull-secret --for=pull
2103 2103
 
2104
-  // To use your secret as an image pull secret, you must add a 'pull' secret to your service account like this:
2105
-  oc secrets add serviceaccount/sa-name secrets/secret-name --for=pull
2104
+  # Add an image pull secret to a service account to automatically use it for both pulling and pushing build images:
2105
+  oc builder builder-image-secret --for=pull,mount
2106 2106
 
2107
-  // To use your secret for image pulls or inside a pod:
2108
-  oc secrets add serviceaccount/sa-name secrets/secret-name --for=pull,mount
2107
+  # If the cluster's serviceAccountConfig is operating with limitSecretReferences: True, secrets must be added to the pod's service account whitelist in order to be available to the pod:
2108
+  oc pod-sa pod-secret
2109
+----
2110
+====
2111
+
2112
+
2113
+== oc secrets link
2114
+Link secrets to a ServiceAccount
2115
+
2116
+====
2117
+
2118
+[options="nowrap"]
2119
+----
2120
+  # Add an image pull secret to a service account to automatically use it for pulling pod images:
2121
+  oc secrets link serviceaccount-name pull-secret --for=pull
2122
+
2123
+  # Add an image pull secret to a service account to automatically use it for both pulling and pushing build images:
2124
+  oc secrets link builder builder-image-secret --for=pull,mount
2125
+
2126
+  # If the cluster's serviceAccountConfig is operating with limitSecretReferences: True, secrets must be added to the pod's service account whitelist in order to be available to the pod:
2127
+  oc secrets link pod-sa pod-secret
2109 2128
 ----
2110 2129
 ====
2111 2130
 
... ...
@@ -2195,6 +2214,19 @@ Create a new secret for SSH authentication
2195 2195
 ====
2196 2196
 
2197 2197
 
2198
+== oc secrets unlink
2199
+Detach secrets from a ServiceAccount
2200
+
2201
+====
2202
+
2203
+[options="nowrap"]
2204
+----
2205
+ # Unlink a secret currently associated with a service account:
2206
+oc secrets unlink serviceaccount-name secret-name another-secret-name ...
2207
+----
2208
+====
2209
+
2210
+
2198 2211
 == oc serviceaccounts get-token
2199 2212
 Get a token assigned to a service account.
2200 2213
 
... ...
@@ -170,10 +170,12 @@ oc-rsync.1
170 170
 oc-run.1
171 171
 oc-scale.1
172 172
 oc-secrets-add.1
173
+oc-secrets-link.1
173 174
 oc-secrets-new-basicauth.1
174 175
 oc-secrets-new-dockercfg.1
175 176
 oc-secrets-new-sshauth.1
176 177
 oc-secrets-new.1
178
+oc-secrets-unlink.1
177 179
 oc-secrets.1
178 180
 oc-serviceaccounts-get-token.1
179 181
 oc-serviceaccounts-new-token.1
... ...
@@ -249,10 +249,12 @@ openshift-cli-rsync.1
249 249
 openshift-cli-run.1
250 250
 openshift-cli-scale.1
251 251
 openshift-cli-secrets-add.1
252
+openshift-cli-secrets-link.1
252 253
 openshift-cli-secrets-new-basicauth.1
253 254
 openshift-cli-secrets-new-dockercfg.1
254 255
 openshift-cli-secrets-new-sshauth.1
255 256
 openshift-cli-secrets-new.1
257
+openshift-cli-secrets-unlink.1
256 258
 openshift-cli-secrets.1
257 259
 openshift-cli-serviceaccounts-get-token.1
258 260
 openshift-cli-serviceaccounts-new-token.1
... ...
@@ -3,7 +3,7 @@
3 3
 
4 4
 .SH NAME
5 5
 .PP
6
-oc secrets add \- Add secrets to a ServiceAccount
6
+oc secrets add \- DEPRECATED: secrets link
7 7
 
8 8
 
9 9
 .SH SYNOPSIS
... ...
@@ -13,16 +13,13 @@ oc secrets add \- Add secrets to a ServiceAccount
13 13
 
14 14
 .SH DESCRIPTION
15 15
 .PP
16
-Add secrets to a ServiceAccount
17
-
18
-.PP
19
-After you have created a secret, you probably want to make use of that secret inside of a pod, for a build, or as an image pull secret.  In order to do that, you must add your secret to a service account.
16
+DEPRECATED: This command has been moved to "oc secrets link"
20 17
 
21 18
 
22 19
 .SH OPTIONS
23 20
 .PP
24 21
 \fB\-\-for\fP=[mount]
25
-    type of secret to add: mount or pull
22
+    type of secret to link: mount or pull
26 23
 
27 24
 
28 25
 .SH OPTIONS INHERITED FROM PARENT COMMANDS
... ...
@@ -96,14 +93,14 @@ After you have created a secret, you probably want to make use of that secret in
96 96
 .RS
97 97
 
98 98
 .nf
99
-  // To use your secret inside of a pod or as a push, pull, or source secret for a build, you must add a 'mount' secret to your service account like this:
100
-  oc secrets add serviceaccount/sa\-name secrets/secret\-name secrets/another\-secret\-name
99
+  # Add an image pull secret to a service account to automatically use it for pulling pod images:
100
+  oc serviceaccount\-name pull\-secret \-\-for=pull
101 101
 
102
-  // To use your secret as an image pull secret, you must add a 'pull' secret to your service account like this:
103
-  oc secrets add serviceaccount/sa\-name secrets/secret\-name \-\-for=pull
102
+  # Add an image pull secret to a service account to automatically use it for both pulling and pushing build images:
103
+  oc builder builder\-image\-secret \-\-for=pull,mount
104 104
 
105
-  // To use your secret for image pulls or inside a pod:
106
-  oc secrets add serviceaccount/sa\-name secrets/secret\-name \-\-for=pull,mount
105
+  # If the cluster's serviceAccountConfig is operating with limitSecretReferences: True, secrets must be added to the pod's service account whitelist in order to be available to the pod:
106
+  oc pod\-sa pod\-secret
107 107
 
108 108
 .fi
109 109
 .RE
110 110
new file mode 100644
... ...
@@ -0,0 +1,119 @@
0
+.TH "OC SECRETS" "1" " Openshift CLI User Manuals" "Openshift" "June 2016"  ""
1
+
2
+
3
+.SH NAME
4
+.PP
5
+oc secrets link \- Link secrets to a ServiceAccount
6
+
7
+
8
+.SH SYNOPSIS
9
+.PP
10
+\fBoc secrets link\fP [OPTIONS]
11
+
12
+
13
+.SH DESCRIPTION
14
+.PP
15
+Link secrets to a service account
16
+
17
+.PP
18
+Linking a secret enables a service account to automatically use that secret for some forms of authentication
19
+
20
+
21
+.SH OPTIONS
22
+.PP
23
+\fB\-\-for\fP=[mount]
24
+    type of secret to link: mount or pull
25
+
26
+
27
+.SH OPTIONS INHERITED FROM PARENT COMMANDS
28
+.PP
29
+\fB\-\-api\-version\fP=""
30
+    DEPRECATED: The API version to use when talking to the server
31
+
32
+.PP
33
+\fB\-\-as\fP=""
34
+    Username to impersonate for the operation.
35
+
36
+.PP
37
+\fB\-\-certificate\-authority\fP=""
38
+    Path to a cert. file for the certificate authority.
39
+
40
+.PP
41
+\fB\-\-client\-certificate\fP=""
42
+    Path to a client certificate file for TLS.
43
+
44
+.PP
45
+\fB\-\-client\-key\fP=""
46
+    Path to a client key file for TLS.
47
+
48
+.PP
49
+\fB\-\-cluster\fP=""
50
+    The name of the kubeconfig cluster to use
51
+
52
+.PP
53
+\fB\-\-config\fP=""
54
+    Path to the config file to use for CLI requests.
55
+
56
+.PP
57
+\fB\-\-context\fP=""
58
+    The name of the kubeconfig context to use
59
+
60
+.PP
61
+\fB\-\-google\-json\-key\fP=""
62
+    The Google Cloud Platform Service Account JSON Key to use for authentication.
63
+
64
+.PP
65
+\fB\-\-insecure\-skip\-tls\-verify\fP=false
66
+    If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
67
+
68
+.PP
69
+\fB\-\-log\-flush\-frequency\fP=0
70
+    Maximum number of seconds between log flushes
71
+
72
+.PP
73
+\fB\-\-match\-server\-version\fP=false
74
+    Require server version to match client version
75
+
76
+.PP
77
+\fB\-n\fP, \fB\-\-namespace\fP=""
78
+    If present, the namespace scope for this CLI request.
79
+
80
+.PP
81
+\fB\-\-server\fP=""
82
+    The address and port of the Kubernetes API server
83
+
84
+.PP
85
+\fB\-\-token\fP=""
86
+    Bearer token for authentication to the API server.
87
+
88
+.PP
89
+\fB\-\-user\fP=""
90
+    The name of the kubeconfig user to use
91
+
92
+
93
+.SH EXAMPLE
94
+.PP
95
+.RS
96
+
97
+.nf
98
+  # Add an image pull secret to a service account to automatically use it for pulling pod images:
99
+  oc secrets link serviceaccount\-name pull\-secret \-\-for=pull
100
+
101
+  # Add an image pull secret to a service account to automatically use it for both pulling and pushing build images:
102
+  oc secrets link builder builder\-image\-secret \-\-for=pull,mount
103
+
104
+  # If the cluster's serviceAccountConfig is operating with limitSecretReferences: True, secrets must be added to the pod's service account whitelist in order to be available to the pod:
105
+  oc secrets link pod\-sa pod\-secret
106
+
107
+.fi
108
+.RE
109
+
110
+
111
+.SH SEE ALSO
112
+.PP
113
+\fBoc\-secrets(1)\fP,
114
+
115
+
116
+.SH HISTORY
117
+.PP
118
+June 2016, Ported from the Kubernetes man\-doc generator
0 119
new file mode 100644
... ...
@@ -0,0 +1,107 @@
0
+.TH "OC SECRETS" "1" " Openshift CLI User Manuals" "Openshift" "June 2016"  ""
1
+
2
+
3
+.SH NAME
4
+.PP
5
+oc secrets unlink \- Detach secrets from a ServiceAccount
6
+
7
+
8
+.SH SYNOPSIS
9
+.PP
10
+\fBoc secrets unlink\fP [OPTIONS]
11
+
12
+
13
+.SH DESCRIPTION
14
+.PP
15
+Unlink (detach) secrets from a service account
16
+
17
+.PP
18
+If a secret is no longer valid for a pod, build or image pull, you may unlink it from a service account.
19
+
20
+
21
+.SH OPTIONS INHERITED FROM PARENT COMMANDS
22
+.PP
23
+\fB\-\-api\-version\fP=""
24
+    DEPRECATED: The API version to use when talking to the server
25
+
26
+.PP
27
+\fB\-\-as\fP=""
28
+    Username to impersonate for the operation.
29
+
30
+.PP
31
+\fB\-\-certificate\-authority\fP=""
32
+    Path to a cert. file for the certificate authority.
33
+
34
+.PP
35
+\fB\-\-client\-certificate\fP=""
36
+    Path to a client certificate file for TLS.
37
+
38
+.PP
39
+\fB\-\-client\-key\fP=""
40
+    Path to a client key file for TLS.
41
+
42
+.PP
43
+\fB\-\-cluster\fP=""
44
+    The name of the kubeconfig cluster to use
45
+
46
+.PP
47
+\fB\-\-config\fP=""
48
+    Path to the config file to use for CLI requests.
49
+
50
+.PP
51
+\fB\-\-context\fP=""
52
+    The name of the kubeconfig context to use
53
+
54
+.PP
55
+\fB\-\-google\-json\-key\fP=""
56
+    The Google Cloud Platform Service Account JSON Key to use for authentication.
57
+
58
+.PP
59
+\fB\-\-insecure\-skip\-tls\-verify\fP=false
60
+    If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
61
+
62
+.PP
63
+\fB\-\-log\-flush\-frequency\fP=0
64
+    Maximum number of seconds between log flushes
65
+
66
+.PP
67
+\fB\-\-match\-server\-version\fP=false
68
+    Require server version to match client version
69
+
70
+.PP
71
+\fB\-n\fP, \fB\-\-namespace\fP=""
72
+    If present, the namespace scope for this CLI request.
73
+
74
+.PP
75
+\fB\-\-server\fP=""
76
+    The address and port of the Kubernetes API server
77
+
78
+.PP
79
+\fB\-\-token\fP=""
80
+    Bearer token for authentication to the API server.
81
+
82
+.PP
83
+\fB\-\-user\fP=""
84
+    The name of the kubeconfig user to use
85
+
86
+
87
+.SH EXAMPLE
88
+.PP
89
+.RS
90
+
91
+.nf
92
+ # Unlink a secret currently associated with a service account:
93
+oc secrets unlink serviceaccount\-name secret\-name another\-secret\-name ...
94
+
95
+.fi
96
+.RE
97
+
98
+
99
+.SH SEE ALSO
100
+.PP
101
+\fBoc\-secrets(1)\fP,
102
+
103
+
104
+.SH HISTORY
105
+.PP
106
+June 2016, Ported from the Kubernetes man\-doc generator
... ...
@@ -89,7 +89,7 @@ Docker registries.
89 89
 
90 90
 .SH SEE ALSO
91 91
 .PP
92
-\fBoc(1)\fP, \fBoc\-secrets\-new(1)\fP, \fBoc\-secrets\-new\-dockercfg(1)\fP, \fBoc\-secrets\-new\-basicauth(1)\fP, \fBoc\-secrets\-new\-sshauth(1)\fP, \fBoc\-secrets\-add(1)\fP,
92
+\fBoc(1)\fP, \fBoc\-secrets\-new(1)\fP, \fBoc\-secrets\-new\-dockercfg(1)\fP, \fBoc\-secrets\-new\-basicauth(1)\fP, \fBoc\-secrets\-new\-sshauth(1)\fP, \fBoc\-secrets\-link(1)\fP, \fBoc\-secrets\-unlink(1)\fP, \fBoc\-secrets\-add(1)\fP,
93 93
 
94 94
 
95 95
 .SH HISTORY
... ...
@@ -3,7 +3,7 @@
3 3
 
4 4
 .SH NAME
5 5
 .PP
6
-openshift cli secrets add \- Add secrets to a ServiceAccount
6
+openshift cli secrets add \- DEPRECATED: secrets link
7 7
 
8 8
 
9 9
 .SH SYNOPSIS
... ...
@@ -13,16 +13,13 @@ openshift cli secrets add \- Add secrets to a ServiceAccount
13 13
 
14 14
 .SH DESCRIPTION
15 15
 .PP
16
-Add secrets to a ServiceAccount
17
-
18
-.PP
19
-After you have created a secret, you probably want to make use of that secret inside of a pod, for a build, or as an image pull secret.  In order to do that, you must add your secret to a service account.
16
+DEPRECATED: This command has been moved to "openshift cli secrets link"
20 17
 
21 18
 
22 19
 .SH OPTIONS
23 20
 .PP
24 21
 \fB\-\-for\fP=[mount]
25
-    type of secret to add: mount or pull
22
+    type of secret to link: mount or pull
26 23
 
27 24
 
28 25
 .SH OPTIONS INHERITED FROM PARENT COMMANDS
... ...
@@ -96,14 +93,14 @@ After you have created a secret, you probably want to make use of that secret in
96 96
 .RS
97 97
 
98 98
 .nf
99
-  // To use your secret inside of a pod or as a push, pull, or source secret for a build, you must add a 'mount' secret to your service account like this:
100
-  openshift cli secrets add serviceaccount/sa\-name secrets/secret\-name secrets/another\-secret\-name
99
+  # Add an image pull secret to a service account to automatically use it for pulling pod images:
100
+  openshift cli serviceaccount\-name pull\-secret \-\-for=pull
101 101
 
102
-  // To use your secret as an image pull secret, you must add a 'pull' secret to your service account like this:
103
-  openshift cli secrets add serviceaccount/sa\-name secrets/secret\-name \-\-for=pull
102
+  # Add an image pull secret to a service account to automatically use it for both pulling and pushing build images:
103
+  openshift cli builder builder\-image\-secret \-\-for=pull,mount
104 104
 
105
-  // To use your secret for image pulls or inside a pod:
106
-  openshift cli secrets add serviceaccount/sa\-name secrets/secret\-name \-\-for=pull,mount
105
+  # If the cluster's serviceAccountConfig is operating with limitSecretReferences: True, secrets must be added to the pod's service account whitelist in order to be available to the pod:
106
+  openshift cli pod\-sa pod\-secret
107 107
 
108 108
 .fi
109 109
 .RE
110 110
new file mode 100644
... ...
@@ -0,0 +1,119 @@
0
+.TH "OPENSHIFT CLI SECRETS" "1" " Openshift CLI User Manuals" "Openshift" "June 2016"  ""
1
+
2
+
3
+.SH NAME
4
+.PP
5
+openshift cli secrets link \- Link secrets to a ServiceAccount
6
+
7
+
8
+.SH SYNOPSIS
9
+.PP
10
+\fBopenshift cli secrets link\fP [OPTIONS]
11
+
12
+
13
+.SH DESCRIPTION
14
+.PP
15
+Link secrets to a service account
16
+
17
+.PP
18
+Linking a secret enables a service account to automatically use that secret for some forms of authentication
19
+
20
+
21
+.SH OPTIONS
22
+.PP
23
+\fB\-\-for\fP=[mount]
24
+    type of secret to link: mount or pull
25
+
26
+
27
+.SH OPTIONS INHERITED FROM PARENT COMMANDS
28
+.PP
29
+\fB\-\-api\-version\fP=""
30
+    DEPRECATED: The API version to use when talking to the server
31
+
32
+.PP
33
+\fB\-\-as\fP=""
34
+    Username to impersonate for the operation.
35
+
36
+.PP
37
+\fB\-\-certificate\-authority\fP=""
38
+    Path to a cert. file for the certificate authority.
39
+
40
+.PP
41
+\fB\-\-client\-certificate\fP=""
42
+    Path to a client certificate file for TLS.
43
+
44
+.PP
45
+\fB\-\-client\-key\fP=""
46
+    Path to a client key file for TLS.
47
+
48
+.PP
49
+\fB\-\-cluster\fP=""
50
+    The name of the kubeconfig cluster to use
51
+
52
+.PP
53
+\fB\-\-config\fP=""
54
+    Path to the config file to use for CLI requests.
55
+
56
+.PP
57
+\fB\-\-context\fP=""
58
+    The name of the kubeconfig context to use
59
+
60
+.PP
61
+\fB\-\-google\-json\-key\fP=""
62
+    The Google Cloud Platform Service Account JSON Key to use for authentication.
63
+
64
+.PP
65
+\fB\-\-insecure\-skip\-tls\-verify\fP=false
66
+    If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
67
+
68
+.PP
69
+\fB\-\-log\-flush\-frequency\fP=0
70
+    Maximum number of seconds between log flushes
71
+
72
+.PP
73
+\fB\-\-match\-server\-version\fP=false
74
+    Require server version to match client version
75
+
76
+.PP
77
+\fB\-n\fP, \fB\-\-namespace\fP=""
78
+    If present, the namespace scope for this CLI request.
79
+
80
+.PP
81
+\fB\-\-server\fP=""
82
+    The address and port of the Kubernetes API server
83
+
84
+.PP
85
+\fB\-\-token\fP=""
86
+    Bearer token for authentication to the API server.
87
+
88
+.PP
89
+\fB\-\-user\fP=""
90
+    The name of the kubeconfig user to use
91
+
92
+
93
+.SH EXAMPLE
94
+.PP
95
+.RS
96
+
97
+.nf
98
+  # Add an image pull secret to a service account to automatically use it for pulling pod images:
99
+  openshift cli secrets link serviceaccount\-name pull\-secret \-\-for=pull
100
+
101
+  # Add an image pull secret to a service account to automatically use it for both pulling and pushing build images:
102
+  openshift cli secrets link builder builder\-image\-secret \-\-for=pull,mount
103
+
104
+  # If the cluster's serviceAccountConfig is operating with limitSecretReferences: True, secrets must be added to the pod's service account whitelist in order to be available to the pod:
105
+  openshift cli secrets link pod\-sa pod\-secret
106
+
107
+.fi
108
+.RE
109
+
110
+
111
+.SH SEE ALSO
112
+.PP
113
+\fBopenshift\-cli\-secrets(1)\fP,
114
+
115
+
116
+.SH HISTORY
117
+.PP
118
+June 2016, Ported from the Kubernetes man\-doc generator
0 119
new file mode 100644
... ...
@@ -0,0 +1,107 @@
0
+.TH "OPENSHIFT CLI SECRETS" "1" " Openshift CLI User Manuals" "Openshift" "June 2016"  ""
1
+
2
+
3
+.SH NAME
4
+.PP
5
+openshift cli secrets unlink \- Detach secrets from a ServiceAccount
6
+
7
+
8
+.SH SYNOPSIS
9
+.PP
10
+\fBopenshift cli secrets unlink\fP [OPTIONS]
11
+
12
+
13
+.SH DESCRIPTION
14
+.PP
15
+Unlink (detach) secrets from a service account
16
+
17
+.PP
18
+If a secret is no longer valid for a pod, build or image pull, you may unlink it from a service account.
19
+
20
+
21
+.SH OPTIONS INHERITED FROM PARENT COMMANDS
22
+.PP
23
+\fB\-\-api\-version\fP=""
24
+    DEPRECATED: The API version to use when talking to the server
25
+
26
+.PP
27
+\fB\-\-as\fP=""
28
+    Username to impersonate for the operation.
29
+
30
+.PP
31
+\fB\-\-certificate\-authority\fP=""
32
+    Path to a cert. file for the certificate authority.
33
+
34
+.PP
35
+\fB\-\-client\-certificate\fP=""
36
+    Path to a client certificate file for TLS.
37
+
38
+.PP
39
+\fB\-\-client\-key\fP=""
40
+    Path to a client key file for TLS.
41
+
42
+.PP
43
+\fB\-\-cluster\fP=""
44
+    The name of the kubeconfig cluster to use
45
+
46
+.PP
47
+\fB\-\-config\fP=""
48
+    Path to the config file to use for CLI requests.
49
+
50
+.PP
51
+\fB\-\-context\fP=""
52
+    The name of the kubeconfig context to use
53
+
54
+.PP
55
+\fB\-\-google\-json\-key\fP=""
56
+    The Google Cloud Platform Service Account JSON Key to use for authentication.
57
+
58
+.PP
59
+\fB\-\-insecure\-skip\-tls\-verify\fP=false
60
+    If true, the server's certificate will not be checked for validity. This will make your HTTPS connections insecure.
61
+
62
+.PP
63
+\fB\-\-log\-flush\-frequency\fP=0
64
+    Maximum number of seconds between log flushes
65
+
66
+.PP
67
+\fB\-\-match\-server\-version\fP=false
68
+    Require server version to match client version
69
+
70
+.PP
71
+\fB\-n\fP, \fB\-\-namespace\fP=""
72
+    If present, the namespace scope for this CLI request.
73
+
74
+.PP
75
+\fB\-\-server\fP=""
76
+    The address and port of the Kubernetes API server
77
+
78
+.PP
79
+\fB\-\-token\fP=""
80
+    Bearer token for authentication to the API server.
81
+
82
+.PP
83
+\fB\-\-user\fP=""
84
+    The name of the kubeconfig user to use
85
+
86
+
87
+.SH EXAMPLE
88
+.PP
89
+.RS
90
+
91
+.nf
92
+ # Unlink a secret currently associated with a service account:
93
+openshift cli secrets unlink serviceaccount\-name secret\-name another\-secret\-name ...
94
+
95
+.fi
96
+.RE
97
+
98
+
99
+.SH SEE ALSO
100
+.PP
101
+\fBopenshift\-cli\-secrets(1)\fP,
102
+
103
+
104
+.SH HISTORY
105
+.PP
106
+June 2016, Ported from the Kubernetes man\-doc generator
... ...
@@ -89,7 +89,7 @@ Docker registries.
89 89
 
90 90
 .SH SEE ALSO
91 91
 .PP
92
-\fBopenshift\-cli(1)\fP, \fBopenshift\-cli\-secrets\-new(1)\fP, \fBopenshift\-cli\-secrets\-new\-dockercfg(1)\fP, \fBopenshift\-cli\-secrets\-new\-basicauth(1)\fP, \fBopenshift\-cli\-secrets\-new\-sshauth(1)\fP, \fBopenshift\-cli\-secrets\-add(1)\fP,
92
+\fBopenshift\-cli(1)\fP, \fBopenshift\-cli\-secrets\-new(1)\fP, \fBopenshift\-cli\-secrets\-new\-dockercfg(1)\fP, \fBopenshift\-cli\-secrets\-new\-basicauth(1)\fP, \fBopenshift\-cli\-secrets\-new\-sshauth(1)\fP, \fBopenshift\-cli\-secrets\-link(1)\fP, \fBopenshift\-cli\-secrets\-unlink(1)\fP, \fBopenshift\-cli\-secrets\-add(1)\fP,
93 93
 
94 94
 
95 95
 .SH HISTORY
... ...
@@ -87,6 +87,8 @@ func NewCommandCLI(name, fullName string, in io.Reader, out, errout io.Writer) *
87 87
 	f := clientcmd.New(cmds.PersistentFlags())
88 88
 
89 89
 	loginCmd := cmd.NewCmdLogin(fullName, f, in, out)
90
+	secretcmds := secrets.NewCmdSecrets(secrets.SecretsRecommendedName, fullName+" "+secrets.SecretsRecommendedName, f, in, out, fullName+" edit")
91
+
90 92
 	groups := templates.CommandGroups{
91 93
 		{
92 94
 			Message: "Basic Commands:",
... ...
@@ -128,7 +130,7 @@ func NewCommandCLI(name, fullName string, in io.Reader, out, errout io.Writer) *
128 128
 				cmd.NewCmdDelete(fullName, f, out),
129 129
 				cmd.NewCmdScale(fullName, f, out),
130 130
 				cmd.NewCmdAutoscale(fullName, f, out),
131
-				secrets.NewCmdSecrets(secrets.SecretsRecommendedName, fullName+" "+secrets.SecretsRecommendedName, f, in, out, fullName+" edit"),
131
+				secretcmds,
132 132
 				sa.NewCmdServiceAccounts(sa.ServiceAccountsRecommendedName, fullName+" "+sa.ServiceAccountsRecommendedName, f, out),
133 133
 			},
134 134
 		},
... ...
@@ -180,6 +182,7 @@ func NewCommandCLI(name, fullName string, in io.Reader, out, errout io.Writer) *
180 180
 		moved(fullName, "set env", cmds, set.NewCmdEnv(fullName, f, in, out)),
181 181
 		moved(fullName, "set volume", cmds, set.NewCmdVolume(fullName, f, out, errout)),
182 182
 		moved(fullName, "logs", cmds, cmd.NewCmdBuildLogs(fullName, f, out)),
183
+		moved(fullName, "secrets link", secretcmds, secrets.NewCmdLinkSecret("add", fullName, f.Factory, out)),
183 184
 	}
184 185
 
185 186
 	changeSharedFlagDefaults(cmds)
186 187
deleted file mode 100644
... ...
@@ -1,274 +0,0 @@
1
-package secrets
2
-
3
-import (
4
-	"errors"
5
-	"fmt"
6
-	"io"
7
-	"io/ioutil"
8
-	"strings"
9
-
10
-	kapi "k8s.io/kubernetes/pkg/api"
11
-	"k8s.io/kubernetes/pkg/api/meta"
12
-	client "k8s.io/kubernetes/pkg/client/unversioned"
13
-	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
14
-	"k8s.io/kubernetes/pkg/kubectl/resource"
15
-	"k8s.io/kubernetes/pkg/runtime"
16
-	"k8s.io/kubernetes/pkg/util/sets"
17
-
18
-	"github.com/spf13/cobra"
19
-)
20
-
21
-const (
22
-	AddSecretRecommendedName = "add"
23
-
24
-	// TODO: move to examples
25
-	addSecretLong = `
26
-Add secrets to a ServiceAccount
27
-
28
-After you have created a secret, you probably want to make use of that secret inside of a pod, for a build, or as an image pull secret.  In order to do that, you must add your secret to a service account.`
29
-
30
-	addSecretExample = `  // To use your secret inside of a pod or as a push, pull, or source secret for a build, you must add a 'mount' secret to your service account like this:
31
-  %[1]s serviceaccount/sa-name secrets/secret-name secrets/another-secret-name
32
-
33
-  // To use your secret as an image pull secret, you must add a 'pull' secret to your service account like this:
34
-  %[1]s serviceaccount/sa-name secrets/secret-name --for=pull
35
-
36
-  // To use your secret for image pulls or inside a pod:
37
-  %[1]s serviceaccount/sa-name secrets/secret-name --for=pull,mount`
38
-)
39
-
40
-type AddSecretOptions struct {
41
-	TargetName  string
42
-	SecretNames []string
43
-
44
-	ForMount bool
45
-	ForPull  bool
46
-
47
-	Namespace string
48
-
49
-	Mapper          meta.RESTMapper
50
-	Typer           runtime.ObjectTyper
51
-	ClientMapper    resource.ClientMapper
52
-	ClientInterface client.Interface
53
-
54
-	Out io.Writer
55
-}
56
-
57
-// NewCmdAddSecret creates a command object for adding a secret reference to a service account
58
-func NewCmdAddSecret(name, fullName string, f *kcmdutil.Factory, out io.Writer) *cobra.Command {
59
-	o := &AddSecretOptions{Out: out}
60
-	var typeFlags []string
61
-
62
-	cmd := &cobra.Command{
63
-		Use:     fmt.Sprintf("%s serviceaccounts/sa-name secrets/secret-name [secrets/another-secret-name]...", name),
64
-		Short:   "Add secrets to a ServiceAccount",
65
-		Long:    addSecretLong,
66
-		Example: fmt.Sprintf(addSecretExample, fullName),
67
-		Run: func(c *cobra.Command, args []string) {
68
-			if err := o.Complete(f, args, typeFlags); err != nil {
69
-				kcmdutil.CheckErr(kcmdutil.UsageError(c, err.Error()))
70
-			}
71
-
72
-			if err := o.Validate(); err != nil {
73
-				kcmdutil.CheckErr(kcmdutil.UsageError(c, err.Error()))
74
-			}
75
-
76
-			if err := o.AddSecrets(); err != nil {
77
-				kcmdutil.CheckErr(err)
78
-			}
79
-
80
-		},
81
-	}
82
-
83
-	cmd.Flags().StringSliceVar(&typeFlags, "for", []string{"mount"}, "type of secret to add: mount or pull")
84
-
85
-	return cmd
86
-}
87
-
88
-func (o *AddSecretOptions) Complete(f *kcmdutil.Factory, args []string, typeFlags []string) error {
89
-	if len(args) < 2 {
90
-		return errors.New("must have service account name and at least one secret name")
91
-	}
92
-	o.TargetName = args[0]
93
-	o.SecretNames = args[1:]
94
-
95
-	if len(typeFlags) == 0 {
96
-		o.ForMount = true
97
-	} else {
98
-		for _, flag := range typeFlags {
99
-			loweredValue := strings.ToLower(flag)
100
-			switch loweredValue {
101
-			case "pull":
102
-				o.ForPull = true
103
-			case "mount":
104
-				o.ForMount = true
105
-			default:
106
-				return fmt.Errorf("unknown for: %v", flag)
107
-			}
108
-		}
109
-	}
110
-
111
-	var err error
112
-	o.ClientInterface, err = f.Client()
113
-	if err != nil {
114
-		return err
115
-	}
116
-
117
-	o.Namespace, _, err = f.DefaultNamespace()
118
-	if err != nil {
119
-		return err
120
-	}
121
-
122
-	o.Mapper, o.Typer = f.Object(false)
123
-	o.ClientMapper = resource.ClientMapperFunc(f.ClientForMapping)
124
-
125
-	return nil
126
-}
127
-
128
-func (o AddSecretOptions) Validate() error {
129
-	if len(o.TargetName) == 0 {
130
-		return errors.New("service account name must be present")
131
-	}
132
-	if len(o.SecretNames) == 0 {
133
-		return errors.New("secret name must be present")
134
-	}
135
-	if !o.ForPull && !o.ForMount {
136
-		return errors.New("for must be present")
137
-	}
138
-	if o.Mapper == nil {
139
-		return errors.New("Mapper must be present")
140
-	}
141
-	if o.Typer == nil {
142
-		return errors.New("Typer must be present")
143
-	}
144
-	if o.ClientMapper == nil {
145
-		return errors.New("ClientMapper must be present")
146
-	}
147
-	if o.ClientInterface == nil {
148
-		return errors.New("ClientInterface must be present")
149
-	}
150
-
151
-	return nil
152
-}
153
-
154
-func (o AddSecretOptions) AddSecrets() error {
155
-	r := resource.NewBuilder(o.Mapper, o.Typer, o.ClientMapper, kapi.Codecs.UniversalDecoder()).
156
-		NamespaceParam(o.Namespace).
157
-		ResourceNames("serviceaccounts", o.TargetName).
158
-		SingleResourceType().
159
-		Do()
160
-	if r.Err() != nil {
161
-		return r.Err()
162
-	}
163
-	obj, err := r.Object()
164
-	if err != nil {
165
-		return err
166
-	}
167
-
168
-	switch t := obj.(type) {
169
-	case *kapi.ServiceAccount:
170
-		err = o.addSecretsToServiceAccount(t)
171
-		if err != nil {
172
-			return err
173
-		}
174
-	default:
175
-		return fmt.Errorf("unhandled object: %#v", t)
176
-	}
177
-
178
-	return nil
179
-}
180
-
181
-// TODO: when Secrets in kapi.ServiceAccount get changed to MountSecrets and represented by LocalObjectReferences, this can be
182
-// refactored to reuse the addition code better
183
-// addSecretsToServiceAccount adds secrets to the service account, either as pull secrets, mount secrets, or both.
184
-func (o AddSecretOptions) addSecretsToServiceAccount(serviceaccount *kapi.ServiceAccount) error {
185
-	updated := false
186
-	newSecrets, err := o.getSecrets()
187
-	if err != nil {
188
-		return err
189
-	}
190
-	newSecretNames := getSecretNames(newSecrets)
191
-
192
-	if o.ForMount {
193
-		currentSecrets := getMountSecretNames(serviceaccount)
194
-		secretsToAdd := newSecretNames.Difference(currentSecrets)
195
-		for _, secretName := range secretsToAdd.List() {
196
-			serviceaccount.Secrets = append(serviceaccount.Secrets, kapi.ObjectReference{Name: secretName})
197
-			updated = true
198
-		}
199
-	}
200
-	if o.ForPull {
201
-		currentSecrets := getPullSecretNames(serviceaccount)
202
-		secretsToAdd := newSecretNames.Difference(currentSecrets)
203
-		for _, secretName := range secretsToAdd.List() {
204
-			serviceaccount.ImagePullSecrets = append(serviceaccount.ImagePullSecrets, kapi.LocalObjectReference{Name: secretName})
205
-			updated = true
206
-		}
207
-	}
208
-	if updated {
209
-		_, err = o.ClientInterface.ServiceAccounts(o.Namespace).Update(serviceaccount)
210
-		return err
211
-	}
212
-	return nil
213
-}
214
-
215
-func (o AddSecretOptions) getSecrets() ([]*kapi.Secret, error) {
216
-	r := resource.NewBuilder(o.Mapper, o.Typer, o.ClientMapper, kapi.Codecs.UniversalDecoder()).
217
-		NamespaceParam(o.Namespace).
218
-		ResourceNames("secrets", o.SecretNames...).
219
-		SingleResourceType().
220
-		Do()
221
-	if r.Err() != nil {
222
-		return nil, r.Err()
223
-	}
224
-	infos, err := r.Infos()
225
-	if err != nil {
226
-		return nil, err
227
-	}
228
-
229
-	secrets := []*kapi.Secret{}
230
-	for i := range infos {
231
-		info := infos[i]
232
-
233
-		switch t := info.Object.(type) {
234
-		case *kapi.Secret:
235
-			secrets = append(secrets, t)
236
-		default:
237
-			return nil, fmt.Errorf("unhandled object: %#v", t)
238
-		}
239
-	}
240
-
241
-	return secrets, nil
242
-}
243
-
244
-func getSecretNames(secrets []*kapi.Secret) sets.String {
245
-	names := sets.String{}
246
-	for _, secret := range secrets {
247
-		names.Insert(secret.Name)
248
-	}
249
-	return names
250
-}
251
-
252
-func getMountSecretNames(serviceaccount *kapi.ServiceAccount) sets.String {
253
-	names := sets.String{}
254
-	for _, secret := range serviceaccount.Secrets {
255
-		names.Insert(secret.Name)
256
-	}
257
-	return names
258
-}
259
-
260
-func getPullSecretNames(serviceaccount *kapi.ServiceAccount) sets.String {
261
-	names := sets.String{}
262
-	for _, secret := range serviceaccount.ImagePullSecrets {
263
-		names.Insert(secret.Name)
264
-	}
265
-	return names
266
-}
267
-
268
-func (o AddSecretOptions) GetOut() io.Writer {
269
-	if o.Out == nil {
270
-		return ioutil.Discard
271
-	}
272
-
273
-	return o.Out
274
-}
275 1
new file mode 100644
... ...
@@ -0,0 +1,161 @@
0
+package secrets
1
+
2
+import (
3
+	"errors"
4
+	"fmt"
5
+	"io"
6
+	"strings"
7
+
8
+	kapi "k8s.io/kubernetes/pkg/api"
9
+	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
10
+
11
+	"github.com/spf13/cobra"
12
+)
13
+
14
+const (
15
+	// LinkSecretRecommendedName `oc secrets link`
16
+	LinkSecretRecommendedName = "link"
17
+
18
+	// TODO: move to examples
19
+	linkSecretLong = `
20
+Link secrets to a service account
21
+
22
+Linking a secret enables a service account to automatically use that secret for some forms of authentication`
23
+
24
+	linkSecretExample = `  # Add an image pull secret to a service account to automatically use it for pulling pod images:
25
+  %[1]s serviceaccount-name pull-secret --for=pull
26
+
27
+  # Add an image pull secret to a service account to automatically use it for both pulling and pushing build images:
28
+  %[1]s builder builder-image-secret --for=pull,mount
29
+
30
+  # If the cluster's serviceAccountConfig is operating with limitSecretReferences: True, secrets must be added to the pod's service account whitelist in order to be available to the pod:
31
+  %[1]s pod-sa pod-secret`
32
+)
33
+
34
+type LinkSecretOptions struct {
35
+	SecretOptions
36
+
37
+	ForMount bool
38
+	ForPull  bool
39
+
40
+	typeFlags []string
41
+}
42
+
43
+// NewCmdLinkSecret creates a command object for linking a secret reference to a service account
44
+func NewCmdLinkSecret(name, fullName string, f *kcmdutil.Factory, out io.Writer) *cobra.Command {
45
+	o := &LinkSecretOptions{SecretOptions{Out: out}, false, false, nil}
46
+
47
+	cmd := &cobra.Command{
48
+		Use:     fmt.Sprintf("%s serviceaccounts-name secret-name [another-secret-name]...", name),
49
+		Short:   "Link secrets to a ServiceAccount",
50
+		Long:    linkSecretLong,
51
+		Example: fmt.Sprintf(linkSecretExample, fullName),
52
+		Run: func(c *cobra.Command, args []string) {
53
+			if err := o.Complete(f, args); err != nil {
54
+				kcmdutil.CheckErr(kcmdutil.UsageError(c, err.Error()))
55
+			}
56
+
57
+			if err := o.Validate(); err != nil {
58
+				kcmdutil.CheckErr(kcmdutil.UsageError(c, err.Error()))
59
+			}
60
+
61
+			if err := o.LinkSecrets(); err != nil {
62
+				kcmdutil.CheckErr(err)
63
+			}
64
+
65
+		},
66
+	}
67
+
68
+	cmd.Flags().StringSliceVar(&o.typeFlags, "for", []string{"mount"}, "type of secret to link: mount or pull")
69
+
70
+	return cmd
71
+}
72
+
73
+func (o *LinkSecretOptions) Complete(f *kcmdutil.Factory, args []string) error {
74
+	if err := o.SecretOptions.Complete(f, args); err != nil {
75
+		return err
76
+	}
77
+
78
+	if len(o.typeFlags) == 0 {
79
+		o.ForMount = true
80
+	} else {
81
+		for _, flag := range o.typeFlags {
82
+			loweredValue := strings.ToLower(flag)
83
+			switch loweredValue {
84
+			case "pull":
85
+				o.ForPull = true
86
+			case "mount":
87
+				o.ForMount = true
88
+			default:
89
+				return fmt.Errorf("unknown for: %v", flag)
90
+			}
91
+		}
92
+	}
93
+
94
+	return nil
95
+}
96
+
97
+func (o LinkSecretOptions) Validate() error {
98
+	if err := o.SecretOptions.Validate(); err != nil {
99
+		return err
100
+	}
101
+
102
+	if !o.ForPull && !o.ForMount {
103
+		return errors.New("for must be present")
104
+	}
105
+
106
+	return nil
107
+}
108
+
109
+func (o LinkSecretOptions) LinkSecrets() error {
110
+	serviceaccount, err := o.GetServiceAccount()
111
+	if err != nil {
112
+		return err
113
+	}
114
+
115
+	err = o.linkSecretsToServiceAccount(serviceaccount)
116
+	if err != nil {
117
+		return err
118
+	}
119
+
120
+	return nil
121
+}
122
+
123
+// TODO: when Secrets in kapi.ServiceAccount get changed to MountSecrets and represented by LocalObjectReferences, this can be
124
+// refactored to reuse the addition code better
125
+// linkSecretsToServiceAccount links secrets to the service account, either as pull secrets, mount secrets, or both.
126
+func (o LinkSecretOptions) linkSecretsToServiceAccount(serviceaccount *kapi.ServiceAccount) error {
127
+	updated := false
128
+	newSecrets, failLater, err := o.GetSecrets()
129
+	if err != nil {
130
+		return err
131
+	}
132
+	newSecretNames := o.GetSecretNames(newSecrets)
133
+
134
+	if o.ForMount {
135
+		currentSecrets := o.GetMountSecretNames(serviceaccount)
136
+		secretsToLink := newSecretNames.Difference(currentSecrets)
137
+		for _, secretName := range secretsToLink.List() {
138
+			serviceaccount.Secrets = append(serviceaccount.Secrets, kapi.ObjectReference{Name: secretName})
139
+			updated = true
140
+		}
141
+	}
142
+	if o.ForPull {
143
+		currentSecrets := o.GetPullSecretNames(serviceaccount)
144
+		secretsToLink := newSecretNames.Difference(currentSecrets)
145
+		for _, secretName := range secretsToLink.List() {
146
+			serviceaccount.ImagePullSecrets = append(serviceaccount.ImagePullSecrets, kapi.LocalObjectReference{Name: secretName})
147
+			updated = true
148
+		}
149
+	}
150
+	if updated {
151
+		_, err = o.ClientInterface.ServiceAccounts(o.Namespace).Update(serviceaccount)
152
+		return err
153
+	}
154
+
155
+	if failLater {
156
+		return errors.New("Some secrets could not be linked")
157
+	}
158
+
159
+	return nil
160
+}
0 161
new file mode 100644
... ...
@@ -0,0 +1,181 @@
0
+package secrets
1
+
2
+import (
3
+	"errors"
4
+	"fmt"
5
+	"io"
6
+	"io/ioutil"
7
+	"os"
8
+
9
+	kapi "k8s.io/kubernetes/pkg/api"
10
+	"k8s.io/kubernetes/pkg/api/meta"
11
+	client "k8s.io/kubernetes/pkg/client/unversioned"
12
+	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
13
+	"k8s.io/kubernetes/pkg/kubectl/resource"
14
+	"k8s.io/kubernetes/pkg/runtime"
15
+	"k8s.io/kubernetes/pkg/util/sets"
16
+)
17
+
18
+// SecretOptions Structure holding state for processing secret linking and
19
+// unlinking.
20
+type SecretOptions struct {
21
+	TargetName  string
22
+	SecretNames []string
23
+	typeFlags   []string
24
+
25
+	Namespace string
26
+
27
+	Mapper          meta.RESTMapper
28
+	Typer           runtime.ObjectTyper
29
+	ClientMapper    resource.ClientMapper
30
+	ClientInterface client.Interface
31
+
32
+	Out io.Writer
33
+}
34
+
35
+// Complete Parses the command line arguments and populates SecretOptions
36
+func (o *SecretOptions) Complete(f *kcmdutil.Factory, args []string) error {
37
+	if len(args) < 2 {
38
+		return errors.New("must have service account name and at least one secret name")
39
+	}
40
+	o.TargetName = args[0]
41
+	o.SecretNames = args[1:]
42
+
43
+	var err error
44
+	o.ClientInterface, err = f.Client()
45
+	if err != nil {
46
+		return err
47
+	}
48
+
49
+	o.Namespace, _, err = f.DefaultNamespace()
50
+	if err != nil {
51
+		return err
52
+	}
53
+
54
+	o.Mapper, o.Typer = f.Object(false)
55
+	o.ClientMapper = resource.ClientMapperFunc(f.ClientForMapping)
56
+
57
+	return nil
58
+}
59
+
60
+// Validate Ensures that all arguments have appropriate values
61
+func (o SecretOptions) Validate() error {
62
+	if len(o.TargetName) == 0 {
63
+		return errors.New("service account name must be present")
64
+	}
65
+	if len(o.SecretNames) == 0 {
66
+		return errors.New("secret name must be present")
67
+	}
68
+	if o.Mapper == nil {
69
+		return errors.New("Mapper must be present")
70
+	}
71
+	if o.Typer == nil {
72
+		return errors.New("Typer must be present")
73
+	}
74
+	if o.ClientMapper == nil {
75
+		return errors.New("ClientMapper must be present")
76
+	}
77
+	if o.ClientInterface == nil {
78
+		return errors.New("ClientInterface must be present")
79
+	}
80
+
81
+	return nil
82
+}
83
+
84
+// GetServiceAccount Retrieve the service account object specified by the command
85
+func (o SecretOptions) GetServiceAccount() (*kapi.ServiceAccount, error) {
86
+	r := resource.NewBuilder(o.Mapper, o.Typer, o.ClientMapper, kapi.Codecs.UniversalDecoder()).
87
+		NamespaceParam(o.Namespace).
88
+		ResourceNames("serviceaccounts", o.TargetName).
89
+		SingleResourceType().
90
+		Do()
91
+	if r.Err() != nil {
92
+		return nil, r.Err()
93
+	}
94
+	obj, err := r.Object()
95
+	if err != nil {
96
+		return nil, err
97
+	}
98
+
99
+	switch t := obj.(type) {
100
+	case *kapi.ServiceAccount:
101
+		return t, nil
102
+	default:
103
+		return nil, fmt.Errorf("unhandled object: %#v", t)
104
+	}
105
+}
106
+
107
+// GetSecretNames Get a list of the names of the secrets in a set of them
108
+func (o SecretOptions) GetSecretNames(secrets []*kapi.Secret) sets.String {
109
+	names := sets.String{}
110
+	for _, secret := range secrets {
111
+		names.Insert(secret.Name)
112
+	}
113
+	return names
114
+}
115
+
116
+// GetMountSecretNames Get a list of the names of the mount secrets associated
117
+// with a service account
118
+func (o SecretOptions) GetMountSecretNames(serviceaccount *kapi.ServiceAccount) sets.String {
119
+	names := sets.String{}
120
+	for _, secret := range serviceaccount.Secrets {
121
+		names.Insert(secret.Name)
122
+	}
123
+	return names
124
+}
125
+
126
+// GetPullSecretNames Get a list of the names of the pull secrets associated
127
+// with a service account.
128
+func (o SecretOptions) GetPullSecretNames(serviceaccount *kapi.ServiceAccount) sets.String {
129
+	names := sets.String{}
130
+	for _, secret := range serviceaccount.ImagePullSecrets {
131
+		names.Insert(secret.Name)
132
+	}
133
+	return names
134
+}
135
+
136
+// GetOut Retrieve the output writer
137
+func (o SecretOptions) GetOut() io.Writer {
138
+	if o.Out == nil {
139
+		return ioutil.Discard
140
+	}
141
+
142
+	return o.Out
143
+}
144
+
145
+// GetSecrets Return a list of secret objects in the default namespace
146
+func (o SecretOptions) GetSecrets() ([]*kapi.Secret, bool, error) {
147
+	secrets := []*kapi.Secret{}
148
+	failLater := false
149
+
150
+	for _, secretName := range o.SecretNames {
151
+		r := resource.NewBuilder(o.Mapper, o.Typer, o.ClientMapper, kapi.Codecs.UniversalDecoder()).
152
+			NamespaceParam(o.Namespace).
153
+			ResourceNames("secrets", secretName).
154
+			SingleResourceType().
155
+			Do()
156
+		if r.Err() != nil {
157
+			return nil, false, r.Err()
158
+		}
159
+		obj, err := r.Object()
160
+		if err != nil {
161
+			fmt.Fprintf(os.Stderr, "secrets \"%s\" not found\n", secretName)
162
+			// Missing secrets are non-fatal but the command should not return
163
+			// success.
164
+			failLater = true
165
+			continue
166
+		}
167
+		switch t := obj.(type) {
168
+		case *kapi.Secret:
169
+			secrets = append(secrets, t)
170
+		default:
171
+			return nil, false, fmt.Errorf("unhandled object: %#v", t)
172
+		}
173
+	}
174
+
175
+	if len(secrets) == 0 {
176
+		return nil, false, errors.New("No valid secrets found")
177
+	}
178
+
179
+	return secrets, failLater, nil
180
+}
... ...
@@ -49,7 +49,8 @@ func NewCmdSecrets(name, fullName string, f *clientcmd.Factory, reader io.Reader
49 49
 	cmds.AddCommand(NewCmdCreateDockerConfigSecret(CreateDockerConfigSecretRecommendedName, fullName+" "+CreateDockerConfigSecretRecommendedName, f.Factory, out, newSecretFullName, ocEditFullName))
50 50
 	cmds.AddCommand(NewCmdCreateBasicAuthSecret(CreateBasicAuthSecretRecommendedCommandName, fullName+" "+CreateBasicAuthSecretRecommendedCommandName, f.Factory, reader, out, newSecretFullName, ocEditFullName))
51 51
 	cmds.AddCommand(NewCmdCreateSSHAuthSecret(CreateSSHAuthSecretRecommendedCommandName, fullName+" "+CreateSSHAuthSecretRecommendedCommandName, f.Factory, out, newSecretFullName, ocEditFullName))
52
-	cmds.AddCommand(NewCmdAddSecret(AddSecretRecommendedName, fullName+" "+AddSecretRecommendedName, f.Factory, out))
52
+	cmds.AddCommand(NewCmdLinkSecret(LinkSecretRecommendedName, fullName+" "+LinkSecretRecommendedName, f.Factory, out))
53
+	cmds.AddCommand(NewCmdUnlinkSecret(UnlinkSecretRecommendedName, fullName+" "+UnlinkSecretRecommendedName, f.Factory, out))
53 54
 
54 55
 	return cmds
55 56
 }
56 57
new file mode 100644
... ...
@@ -0,0 +1,128 @@
0
+package secrets
1
+
2
+import (
3
+	"errors"
4
+	"fmt"
5
+	"io"
6
+
7
+	kapi "k8s.io/kubernetes/pkg/api"
8
+	kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
9
+
10
+	"github.com/spf13/cobra"
11
+)
12
+
13
+const (
14
+	UnlinkSecretRecommendedName = "unlink"
15
+
16
+	// TODO: move to examples
17
+	unlinkSecretLong = `
18
+Unlink (detach) secrets from a service account
19
+
20
+If a secret is no longer valid for a pod, build or image pull, you may unlink it from a service account.`
21
+
22
+	unlinkSecretExample = ` # Unlink a secret currently associated with a service account:
23
+%[1]s serviceaccount-name secret-name another-secret-name ...`
24
+)
25
+
26
+type UnlinkSecretOptions struct {
27
+	SecretOptions
28
+}
29
+
30
+// NewCmdUnlinkSecret creates a command object for detaching one or more secret references from a service account
31
+func NewCmdUnlinkSecret(name, fullName string, f *kcmdutil.Factory, out io.Writer) *cobra.Command {
32
+	o := &UnlinkSecretOptions{SecretOptions{Out: out}}
33
+
34
+	cmd := &cobra.Command{
35
+		Use:     fmt.Sprintf("%s serviceaccount-name secret-name [another-secret-name] ...", name),
36
+		Short:   "Detach secrets from a ServiceAccount",
37
+		Long:    unlinkSecretLong,
38
+		Example: fmt.Sprintf(unlinkSecretExample, fullName),
39
+		Run: func(c *cobra.Command, args []string) {
40
+			if err := o.Complete(f, args); err != nil {
41
+				kcmdutil.CheckErr(kcmdutil.UsageError(c, err.Error()))
42
+			}
43
+			if err := o.Validate(); err != nil {
44
+				kcmdutil.CheckErr(kcmdutil.UsageError(c, err.Error()))
45
+			}
46
+
47
+			if err := o.UnlinkSecrets(); err != nil {
48
+				kcmdutil.CheckErr(err)
49
+			}
50
+
51
+		},
52
+	}
53
+
54
+	return cmd
55
+}
56
+
57
+func (o UnlinkSecretOptions) UnlinkSecrets() error {
58
+	serviceaccount, err := o.GetServiceAccount()
59
+	if err != nil {
60
+		return err
61
+	}
62
+
63
+	if err = o.unlinkSecretsFromServiceAccount(serviceaccount); err != nil {
64
+		return err
65
+	}
66
+
67
+	return nil
68
+}
69
+
70
+// unlinkSecretsFromServiceAccount detaches pull and mount secrets from the service account.
71
+func (o UnlinkSecretOptions) unlinkSecretsFromServiceAccount(serviceaccount *kapi.ServiceAccount) error {
72
+	// All of the requested secrets must be present in either the Mount or Pull secrets
73
+	// If any of them are not present, we'll return an error and push no changes.
74
+	rmSecrets, failLater, err := o.GetSecrets()
75
+	if err != nil {
76
+		return err
77
+	}
78
+	rmSecretNames := o.GetSecretNames(rmSecrets)
79
+
80
+	newMountSecrets := []kapi.ObjectReference{}
81
+	newPullSecrets := []kapi.LocalObjectReference{}
82
+
83
+	// Check the mount secrets
84
+	for i := len(serviceaccount.Secrets) - 1; i >= 0; i-- {
85
+		found := false
86
+		for _, secretname := range rmSecretNames.List() {
87
+			if secretname == serviceaccount.Secrets[i].Name {
88
+				found = true
89
+				// Skip adding this to the updated list
90
+			}
91
+		}
92
+
93
+		if !found {
94
+			// Copy this back in, since it doesn't match the ones we're removing
95
+			newMountSecrets = append(newMountSecrets, serviceaccount.Secrets[i])
96
+		}
97
+	}
98
+
99
+	// Check the image pull secrets
100
+	for i := len(serviceaccount.ImagePullSecrets) - 1; i >= 0; i-- {
101
+		found := false
102
+		for _, secretname := range rmSecretNames.List() {
103
+			if secretname == serviceaccount.ImagePullSecrets[i].Name {
104
+				found = true
105
+				// Skip adding this to the updated list
106
+			}
107
+		}
108
+		if !found {
109
+			// Copy this back in, since it doesn't match the one we're removing
110
+			newPullSecrets = append(newPullSecrets, serviceaccount.ImagePullSecrets[i])
111
+		}
112
+	}
113
+
114
+	// Save the updated Secret lists back to the server
115
+	serviceaccount.Secrets = newMountSecrets
116
+	serviceaccount.ImagePullSecrets = newPullSecrets
117
+	_, err = o.ClientInterface.ServiceAccounts(o.Namespace).Update(serviceaccount)
118
+	if err != nil {
119
+		return err
120
+	}
121
+
122
+	if failLater {
123
+		return errors.New("Some secrets could not be unlinked")
124
+	}
125
+
126
+	return nil
127
+}
... ...
@@ -69,15 +69,56 @@ os::cmd::expect_success 'oc secrets new-sshauth sshauth --ssh-privatekey=$PRIVAT
69 69
 # check to make sure incorrect SSH private-key path fail as expected
70 70
 os::cmd::expect_failure_and_text 'oc secrets new-sshauth bad-file --ssh-privatekey=/bad/path' 'error: open /bad/path: no such file or directory'
71 71
 
72
+# attach secrets to service account (deprecated)
73
+# single secret with prefix
74
+os::cmd::expect_success 'oc secrets add deployer basicauth'
75
+# don't add the same secret twice
76
+os::cmd::expect_success 'oc secrets add deployer basicauth sshauth'
77
+# make sure we can add as as pull secret
78
+os::cmd::expect_success 'oc secrets add deployer basicauth sshauth --for=pull'
79
+# make sure we can add as as pull secret and mount secret at once
80
+os::cmd::expect_success 'oc secrets add deployer basicauth sshauth --for=pull,mount'
81
+
72 82
 # attach secrets to service account
73 83
 # single secret with prefix
74
-os::cmd::expect_success 'oc secrets add serviceaccounts/deployer secrets/basicauth'
84
+os::cmd::expect_success 'oc secrets link deployer basicauth'
75 85
 # don't add the same secret twice
76
-os::cmd::expect_success 'oc secrets add serviceaccounts/deployer secrets/basicauth secrets/sshauth'
86
+os::cmd::expect_success 'oc secrets link deployer basicauth sshauth'
77 87
 # make sure we can add as as pull secret
78
-os::cmd::expect_success 'oc secrets add serviceaccounts/deployer secrets/basicauth secrets/sshauth --for=pull'
88
+os::cmd::expect_success 'oc secrets link deployer basicauth sshauth --for=pull'
79 89
 # make sure we can add as as pull secret and mount secret at once
80
-os::cmd::expect_success 'oc secrets add serviceaccounts/deployer secrets/basicauth secrets/sshauth --for=pull,mount'
90
+os::cmd::expect_success 'oc secrets link deployer basicauth sshauth --for=pull,mount'
91
+
92
+# Confirm that all the linked secrets are present
93
+os::cmd::expect_success 'oc get serviceaccounts/deployer -o yaml |grep -q basicauth'
94
+os::cmd::expect_success 'oc get serviceaccounts/deployer -o yaml |grep -q sshauth'
95
+
96
+# Remove secrets from service account
97
+os::cmd::expect_success 'oc secrets unlink deployer basicauth'
98
+# Confirm that the secret was removed
99
+os::cmd::expect_failure 'oc get serviceaccounts/deployer -o yaml |grep -q basicauth'
100
+
101
+# Re-link that secret
102
+os::cmd::expect_success 'oc secrets link deployer basicauth'
103
+
104
+# Removing a non-existent secret should warn but succeed and change nothing
105
+os::cmd::expect_failure_and_text 'oc secrets unlink deployer foobar' 'secrets "foobar" not found'
106
+
107
+# Make sure that removing an existent and non-existent secret succeeds but warns about the non-existent one
108
+os::cmd::expect_failure_and_text 'oc secrets unlink deployer foobar basicauth' 'secrets "foobar" not found'
109
+# Make sure that the existing secret is removed
110
+os::cmd::expect_failure 'oc get serviceaccounts/deployer -o yaml |grep -q basicauth'
111
+
112
+# Make sure that removing a real but unlinked secret succeeds
113
+# https://github.com/openshift/origin/pull/9234#discussion_r70832486
114
+os::cmd::expect_success 'oc secrets unlink deployer basicauth'
115
+
116
+# Make sure that it succeeds if *any* of the secrets are linked
117
+# https://github.com/openshift/origin/pull/9234#discussion_r70832486
118
+os::cmd::expect_success 'oc secrets unlink deployer basicauth sshauth'
119
+
120
+# Confirm that the linked one was removed
121
+os::cmd::expect_failure 'oc get serviceaccounts/deployer -o yaml |grep -q sshauth'
81 122
 
82 123
 # command alias
83 124
 os::cmd::expect_success 'oc secret --help'
... ...
@@ -86,6 +127,8 @@ os::cmd::expect_success 'oc secret new-dockercfg --help'
86 86
 os::cmd::expect_success 'oc secret new-basicauth --help'
87 87
 os::cmd::expect_success 'oc secret new-sshauth --help'
88 88
 os::cmd::expect_success 'oc secret add --help'
89
+os::cmd::expect_success 'oc secret link --help'
90
+os::cmd::expect_success 'oc secret unlink --help'
89 91
 
90 92
 echo "secrets: ok"
91 93
 os::test::junit::declare_suite_end