Skip to content

Commit 4443e8f

Browse files
committed
Allow to unlink deleted secrets from a service account
1 parent 43fbf69 commit 4443e8f

File tree

4 files changed

+47
-26
lines changed

4 files changed

+47
-26
lines changed

pkg/cmd/cli/secrets/link_secret_to_obj.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ func (o LinkSecretOptions) LinkSecrets() error {
127127
// linkSecretsToServiceAccount links secrets to the service account, either as pull secrets, mount secrets, or both.
128128
func (o LinkSecretOptions) linkSecretsToServiceAccount(serviceaccount *kapi.ServiceAccount) error {
129129
updated := false
130-
newSecrets, failLater, err := o.GetSecrets()
130+
newSecrets, hasNotFound, err := o.GetSecrets(false)
131131
if err != nil {
132132
return err
133133
}
@@ -154,7 +154,7 @@ func (o LinkSecretOptions) linkSecretsToServiceAccount(serviceaccount *kapi.Serv
154154
return err
155155
}
156156

157-
if failLater {
157+
if hasNotFound {
158158
return errors.New("Some secrets could not be linked")
159159
}
160160

pkg/cmd/cli/secrets/options.go

+22-8
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"os"
99

1010
kapi "k8s.io/kubernetes/pkg/api"
11+
kerrors "k8s.io/kubernetes/pkg/api/errors"
1112
"k8s.io/kubernetes/pkg/api/meta"
1213
client "k8s.io/kubernetes/pkg/client/unversioned"
1314
kcmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
@@ -144,9 +145,10 @@ func (o SecretOptions) GetOut() io.Writer {
144145
}
145146

146147
// GetSecrets Return a list of secret objects in the default namespace
147-
func (o SecretOptions) GetSecrets() ([]*kapi.Secret, bool, error) {
148+
// If allowNonExisting is set to true, we will return the non-existing secrets as well.
149+
func (o SecretOptions) GetSecrets(allowNonExisting bool) ([]*kapi.Secret, bool, error) {
148150
secrets := []*kapi.Secret{}
149-
failLater := false
151+
hasNotFound := false
150152

151153
for _, secretName := range o.SecretNames {
152154
r := resource.NewBuilder(o.Mapper, o.Typer, o.ClientMapper, kapi.Codecs.UniversalDecoder()).
@@ -159,11 +161,23 @@ func (o SecretOptions) GetSecrets() ([]*kapi.Secret, bool, error) {
159161
}
160162
obj, err := r.Object()
161163
if err != nil {
162-
fmt.Fprintf(os.Stderr, "secrets \"%s\" not found\n", secretName)
163-
// Missing secrets are non-fatal but the command should not return
164-
// success.
165-
failLater = true
166-
continue
164+
// If the secret is not found it means it was deleted but we want still to allow to
165+
// unlink a removed secret from the service account
166+
if kerrors.IsNotFound(err) {
167+
fmt.Fprintf(os.Stderr, "secret %q not found\n", secretName)
168+
hasNotFound = true
169+
if allowNonExisting {
170+
obj = &kapi.Secret{
171+
ObjectMeta: kapi.ObjectMeta{
172+
Name: secretName,
173+
},
174+
}
175+
} else {
176+
continue
177+
}
178+
} else if err != nil {
179+
return nil, false, err
180+
}
167181
}
168182
switch t := obj.(type) {
169183
case *kapi.Secret:
@@ -177,5 +191,5 @@ func (o SecretOptions) GetSecrets() ([]*kapi.Secret, bool, error) {
177191
return nil, false, errors.New("No valid secrets found")
178192
}
179193

180-
return secrets, failLater, nil
194+
return secrets, hasNotFound, nil
181195
}

pkg/cmd/cli/secrets/unlink_secret_from_object.go

+20-13
Original file line numberDiff line numberDiff line change
@@ -74,20 +74,23 @@ func (o UnlinkSecretOptions) UnlinkSecrets() error {
7474
func (o UnlinkSecretOptions) unlinkSecretsFromServiceAccount(serviceaccount *kapi.ServiceAccount) error {
7575
// All of the requested secrets must be present in either the Mount or Pull secrets
7676
// If any of them are not present, we'll return an error and push no changes.
77-
rmSecrets, failLater, err := o.GetSecrets()
77+
rmSecrets, hasNotFound, err := o.GetSecrets(true)
7878
if err != nil {
7979
return err
8080
}
8181
rmSecretNames := o.GetSecretNames(rmSecrets)
8282

8383
newMountSecrets := []kapi.ObjectReference{}
8484
newPullSecrets := []kapi.LocalObjectReference{}
85+
updated := false
8586

8687
// Check the mount secrets
8788
for _, secret := range serviceaccount.Secrets {
8889
if !rmSecretNames.Has(secret.Name) {
8990
// Copy this back in, since it doesn't match the ones we're removing
9091
newMountSecrets = append(newMountSecrets, secret)
92+
} else {
93+
updated = true
9194
}
9295
}
9396

@@ -96,20 +99,24 @@ func (o UnlinkSecretOptions) unlinkSecretsFromServiceAccount(serviceaccount *kap
9699
if !rmSecretNames.Has(imagePullSecret.Name) {
97100
// Copy this back in, since it doesn't match the one we're removing
98101
newPullSecrets = append(newPullSecrets, imagePullSecret)
102+
} else {
103+
updated = true
99104
}
100105
}
101106

102-
// Save the updated Secret lists back to the server
103-
serviceaccount.Secrets = newMountSecrets
104-
serviceaccount.ImagePullSecrets = newPullSecrets
105-
_, err = o.ClientInterface.ServiceAccounts(o.Namespace).Update(serviceaccount)
106-
if err != nil {
107-
return err
108-
}
109-
110-
if failLater {
111-
return errors.New("Some secrets could not be unlinked")
107+
if updated {
108+
// Save the updated Secret lists back to the server
109+
serviceaccount.Secrets = newMountSecrets
110+
serviceaccount.ImagePullSecrets = newPullSecrets
111+
_, err = o.ClientInterface.ServiceAccounts(o.Namespace).Update(serviceaccount)
112+
if err != nil {
113+
return err
114+
}
115+
if hasNotFound {
116+
return fmt.Errorf("Unlinked deleted secrets from %s/%s service account", o.Namespace, serviceaccount.Name)
117+
}
118+
return nil
119+
} else {
120+
return errors.New("No valid secrets found or secrets not linked to service account")
112121
}
113-
114-
return nil
115122
}

test/cmd/secrets.sh

+3-3
Original file line numberDiff line numberDiff line change
@@ -105,16 +105,16 @@ os::cmd::expect_failure 'oc get serviceaccounts/deployer -o yaml |grep -q basica
105105
os::cmd::expect_success 'oc secrets link deployer basicauth'
106106

107107
# Removing a non-existent secret should warn but succeed and change nothing
108-
os::cmd::expect_failure_and_text 'oc secrets unlink deployer foobar' 'secrets "foobar" not found'
108+
os::cmd::expect_failure_and_text 'oc secrets unlink deployer foobar' 'secret "foobar" not found'
109109

110110
# Make sure that removing an existent and non-existent secret succeeds but warns about the non-existent one
111-
os::cmd::expect_failure_and_text 'oc secrets unlink deployer foobar basicauth' 'secrets "foobar" not found'
111+
os::cmd::expect_failure_and_text 'oc secrets unlink deployer foobar basicauth' 'secret "foobar" not found'
112112
# Make sure that the existing secret is removed
113113
os::cmd::expect_failure 'oc get serviceaccounts/deployer -o yaml |grep -q basicauth'
114114

115115
# Make sure that removing a real but unlinked secret succeeds
116116
# https://github.com/openshift/origin/pull/9234#discussion_r70832486
117-
os::cmd::expect_success 'oc secrets unlink deployer basicauth'
117+
os::cmd::expect_failure_and_text 'oc secrets unlink deployer basicauth', 'No valid secrets found or secrets not linked to service account'
118118

119119
# Make sure that it succeeds if *any* of the secrets are linked
120120
# https://github.com/openshift/origin/pull/9234#discussion_r70832486

0 commit comments

Comments
 (0)